diff --git a/.deadcode-out b/.deadcode-out index 8fca0d96b..cf5f7c479 100644 --- a/.deadcode-out +++ b/.deadcode-out @@ -162,9 +162,6 @@ package "code.gitea.io/gitea/modules/cache" package "code.gitea.io/gitea/modules/charset" func (*BreakWriter).Write -package "code.gitea.io/gitea/modules/context" - func GetPrivateContext - package "code.gitea.io/gitea/modules/emoji" func ReplaceCodes @@ -296,7 +293,6 @@ package "code.gitea.io/gitea/modules/translation" package "code.gitea.io/gitea/modules/util" func UnsafeStringToBytes - func OptionalBoolFromGeneric package "code.gitea.io/gitea/modules/util/filebuffer" func CreateFromReader @@ -316,6 +312,9 @@ package "code.gitea.io/gitea/routers/web/org" func getActionIssues func UpdateIssueProject +package "code.gitea.io/gitea/services/context" + func GetPrivateContext + package "code.gitea.io/gitea/services/convert" func ToSecret diff --git a/.gitignore b/.gitignore index 12014d405..34c71b697 100644 --- a/.gitignore +++ b/.gitignore @@ -18,7 +18,7 @@ _test # MS VSCode .vscode -__debug_bin +__debug_bin* *.cgo1.go *.cgo2.c diff --git a/.stylelintrc.yaml b/.stylelintrc.yaml index 7dd0a566f..c7725159f 100644 --- a/.stylelintrc.yaml +++ b/.stylelintrc.yaml @@ -64,6 +64,7 @@ rules: "@stylistic/media-query-list-comma-newline-before": null "@stylistic/media-query-list-comma-space-after": null "@stylistic/media-query-list-comma-space-before": null + "@stylistic/named-grid-areas-alignment": null "@stylistic/no-empty-first-line": null "@stylistic/no-eol-whitespace": true "@stylistic/no-extra-semicolons": true diff --git a/custom/conf/app.example.ini b/custom/conf/app.example.ini index 04714e550..4d077643f 100644 --- a/custom/conf/app.example.ini +++ b/custom/conf/app.example.ini @@ -969,6 +969,12 @@ LEVEL = Info ;GO_GET_CLONE_URL_PROTOCOL = https ;; ;; Close issues as long as a commit on any branch marks it as fixed +;DEFAULT_CLOSE_ISSUES_VIA_COMMITS_IN_ANY_BRANCH = false +;; +;; Allow users to push local repositories to Gitea and have them automatically created for a user or an org +;ENABLE_PUSH_CREATE_USER = false +;ENABLE_PUSH_CREATE_ORG = false +;; ;; Comma separated list of globally disabled repo units. Allowed values: repo.issues, repo.ext_issues, repo.pulls, repo.wiki, repo.ext_wiki, repo.projects, repo.packages, repo.actions. ;DISABLED_REPO_UNITS = ;; @@ -1490,10 +1496,11 @@ LEVEL = Info ;; ;; Default configuration for email notifications for users (user configurable). Options: enabled, onmention, disabled ;DEFAULT_EMAIL_NOTIFICATIONS = enabled -;; Send an email to all admins when a new user signs up to inform the admins about this act. Options: true, false +;; Disabled features for users, could be "deletion","manage_gpg_keys" more features can be disabled in future ;SEND_NOTIFICATION_EMAIL_ON_NEW_USER = false ;; Disabled features for users, could be "deletion", more features can be disabled in future ;; - deletion: a user cannot delete their own account +;; - manage_gpg_keys: a user cannot configure gpg keys ;USER_DISABLED_FEATURES = ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; diff --git a/docs/content/administration/config-cheat-sheet.en-us.md b/docs/content/administration/config-cheat-sheet.en-us.md index aa2cbcee5..ea6e1eb1a 100644 --- a/docs/content/administration/config-cheat-sheet.en-us.md +++ b/docs/content/administration/config-cheat-sheet.en-us.md @@ -518,7 +518,9 @@ And the following unique queues: - `DEFAULT_EMAIL_NOTIFICATIONS`: **enabled**: Default configuration for email notifications for users (user configurable). Options: enabled, onmention, disabled - `DISABLE_REGULAR_ORG_CREATION`: **false**: Disallow regular (non-admin) users from creating organizations. -- `SEND_NOTIFICATION_EMAIL_ON_NEW_USER`: **false**: Send an email to all admins when a new user signs up to inform the admins about this act. +- `USER_DISABLED_FEATURES`: **_empty_** Disabled features for users, could be `deletion`, `manage_gpg_keys` and more features can be added in future. + - `deletion`: User cannot delete their own account. + - `manage_gpg_keys`: User cannot configure gpg keys ## Security (`security`) diff --git a/docs/content/administration/config-cheat-sheet.zh-cn.md b/docs/content/administration/config-cheat-sheet.zh-cn.md index 01906930c..5cc573435 100644 --- a/docs/content/administration/config-cheat-sheet.zh-cn.md +++ b/docs/content/administration/config-cheat-sheet.zh-cn.md @@ -497,6 +497,9 @@ Gitea 创建以下非唯一队列: - `DEFAULT_EMAIL_NOTIFICATIONS`: **enabled**:用户电子邮件通知的默认配置(用户可配置)。选项:enabled、onmention、disabled - `DISABLE_REGULAR_ORG_CREATION`: **false**:禁止普通(非管理员)用户创建组织。 +- `USER_DISABLED_FEATURES`:**_empty_** 禁用的用户特性,当前允许为空或者 `deletion`,`manage_gpg_keys` 未来可以增加更多设置。 + - `deletion`: 用户不能通过界面或者API删除他自己。 + - `manage_gpg_keys`: 用户不能配置 GPG 密钥 ## 安全性 (`security`) diff --git a/docs/content/administration/mail-templates.en-us.md b/docs/content/administration/mail-templates.en-us.md index 32b352da4..0154fe55d 100644 --- a/docs/content/administration/mail-templates.en-us.md +++ b/docs/content/administration/mail-templates.en-us.md @@ -222,9 +222,9 @@ Please check [Gitea's logs](administration/logging-config.md) for error messages {{.Repo}}#{{.Issue.Index}}.

{{if not (eq .Body "")}} -

Message content:

+

Message content


- {{.Body | Str2html}} + {{.Body | SanitizeHTML}} {{end}}


@@ -245,7 +245,7 @@ This template produces something along these lines: > [@rhonda](#) (Rhonda Myers) updated [mike/stuff#38](#). > -> #### Message content: +> #### Message content > > \_********************************\_******************************** > @@ -259,20 +259,20 @@ This template produces something along these lines: The template system contains several functions that can be used to further process and format the messages. Here's a list of some of them: -| Name | Parameters | Available | Usage | -| ---------------- | ----------- | --------- | --------------------------------------------------------------------------- | -| `AppUrl` | - | Any | Gitea's URL | -| `AppName` | - | Any | Set from `app.ini`, usually "Gitea" | -| `AppDomain` | - | Any | Gitea's host name | -| `EllipsisString` | string, int | Any | Truncates a string to the specified length; adds ellipsis as needed | -| `Str2html` | string | Body only | Sanitizes text by removing any HTML tags from it. | -| `Safe` | string | Body only | Takes the input as HTML; can be used for `.ReviewComments.RenderedContent`. | +| Name | Parameters | Available | Usage | +| ---------------- | ----------- | --------- | ------------------------------------------------------------------- | +| `AppUrl` | - | Any | Gitea's URL | +| `AppName` | - | Any | Set from `app.ini`, usually "Gitea" | +| `AppDomain` | - | Any | Gitea's host name | +| `EllipsisString` | string, int | Any | Truncates a string to the specified length; adds ellipsis as needed | +| `SanitizeHTML` | string | Body only | Sanitizes text by removing any dangerous HTML tags from it | +| `SafeHTML` | string | Body only | Takes the input as HTML, can be used for outputing raw HTML content | These are _functions_, not metadata, so they have to be used: ```html -Like this: {{Str2html "Escapetext"}} -Or this: {{"Escapetext" | Str2html}} +Like this: {{SanitizeHTML "Escapetext"}} +Or this: {{"Escapetext" | SanitizeHTML}} Or this: {{AppUrl}} But not like this: {{.AppUrl}} ``` diff --git a/docs/content/administration/mail-templates.zh-cn.md b/docs/content/administration/mail-templates.zh-cn.md index 588f0b2cc..e8c281733 100644 --- a/docs/content/administration/mail-templates.zh-cn.md +++ b/docs/content/administration/mail-templates.zh-cn.md @@ -207,7 +207,7 @@ _主题_ 和 _邮件正文_ 由 [Golang的模板引擎](https://go.dev/pkg/text/ {{if not (eq .Body "")}}

消息内容:


- {{.Body | Str2html}} + {{.Body | SanitizeHTML}} {{end}}


@@ -228,7 +228,7 @@ _主题_ 和 _邮件正文_ 由 [Golang的模板引擎](https://go.dev/pkg/text/ > [@rhonda](#)(Rhonda Myers)更新了 [mike/stuff#38](#)。 > -> #### 消息内容: +> #### 消息内容 > > \_********************************\_******************************** > @@ -242,20 +242,20 @@ _主题_ 和 _邮件正文_ 由 [Golang的模板引擎](https://go.dev/pkg/text/ 模板系统包含一些函数,可用于进一步处理和格式化消息。以下是其中一些函数的列表: -| 函数名 | 参数 | 可用于 | 用法 | -| ----------------- | ----------- | ------------ | --------------------------------------------------------------------------------- | -| `AppUrl` | - | 任何地方 | Gitea 的 URL | -| `AppName` | - | 任何地方 | 从 `app.ini` 中设置,通常为 "Gitea" | -| `AppDomain` | - | 任何地方 | Gitea 的主机名 | -| `EllipsisString` | string, int | 任何地方 | 将字符串截断为指定长度;根据需要添加省略号 | -| `Str2html` | string | 仅正文部分 | 通过删除其中的 HTML 标签对文本进行清理 | -| `Safe` | string | 仅正文部分 | 将输入作为 HTML 处理;可用于 `.ReviewComments.RenderedContent` 等字段 | +| 函数名 | 参数 | 可用于 | 用法 | +|------------------| ----------- | ------------ | ------------------------------ | +| `AppUrl` | - | 任何地方 | Gitea 的 URL | +| `AppName` | - | 任何地方 | 从 `app.ini` 中设置,通常为 "Gitea" | +| `AppDomain` | - | 任何地方 | Gitea 的主机名 | +| `EllipsisString` | string, int | 任何地方 | 将字符串截断为指定长度;根据需要添加省略号 | +| `SanitizeHTML` | string | 仅正文部分 | 通过删除其中的危险 HTML 标签对文本进行清理 | +| `SafeHTML` | string | 仅正文部分 | 将输入作为 HTML 处理;可用于输出原始的 HTML 内容 | 这些都是 _函数_,而不是元数据,因此必须按以下方式使用: ```html -像这样使用: {{Str2html "Escapetext"}} -或者这样使用: {{"Escapetext" | Str2html}} +像这样使用: {{SanitizeHTML "Escapetext"}} +或者这样使用: {{"Escapetext" | SanitizeHTML}} 或者这样使用: {{AppUrl}} 但不要像这样使用: {{.AppUrl}} ``` diff --git a/docs/content/usage/issue-pull-request-templates.en-us.md b/docs/content/usage/issue-pull-request-templates.en-us.md index 34475e346..bd43131f4 100644 --- a/docs/content/usage/issue-pull-request-templates.en-us.md +++ b/docs/content/usage/issue-pull-request-templates.en-us.md @@ -135,6 +135,12 @@ body: attributes: value: | Thanks for taking the time to fill out this bug report! + # some markdown that will only be visible once the issue has been created + - type: markdown + attributes: + value: | + This issue was created by an issue **template** :) + visible: [content] - type: input id: contact attributes: @@ -186,11 +192,16 @@ body: options: - label: I agree to follow this project's Code of Conduct required: true + - label: I have also read the CONTRIBUTION.MD + required: true + visible: [form] + - label: This is a TODO only visible after issue creation + visible: [content] ``` ### Markdown -You can use a `markdown` element to display Markdown in your form that provides extra context to the user, but is not submitted. +You can use a `markdown` element to display Markdown in your form that provides extra context to the user, but is not submitted by default. Attributes: @@ -198,6 +209,8 @@ Attributes: |-------|--------------------------------------------------------------|----------|--------|---------|--------------| | value | The text that is rendered. Markdown formatting is supported. | Required | String | - | - | +visible: Default is **[form]** + ### Textarea You can use a `textarea` element to add a multi-line text field to your form. Contributors can also attach files in `textarea` fields. @@ -218,6 +231,8 @@ Validations: |----------|------------------------------------------------------|----------|---------|---------|--------------| | required | Prevents form submission until element is completed. | Optional | Boolean | false | - | +visible: Default is **[form, content]** + ### Input You can use an `input` element to add a single-line text field to your form. @@ -239,6 +254,8 @@ Validations: | is_number | Prevents form submission until element is filled with a number. | Optional | Boolean | false | - | | regex | Prevents form submission until element is filled with a value that match the regular expression. | Optional | String | - | a [regular expression](https://en.wikipedia.org/wiki/Regular_expression) | +visible: Default is **[form, content]** + ### Dropdown You can use a `dropdown` element to add a dropdown menu in your form. @@ -258,6 +275,8 @@ Validations: |----------|------------------------------------------------------|----------|---------|---------|--------------| | required | Prevents form submission until element is completed. | Optional | Boolean | false | - | +visible: Default is **[form, content]** + ### Checkboxes You can use the `checkboxes` element to add a set of checkboxes to your form. @@ -265,17 +284,20 @@ You can use the `checkboxes` element to add a set of checkboxes to your form. Attributes: | Key | Description | Required | Type | Default | Valid values | -|-------------|-------------------------------------------------------------------------------------------------------|----------|--------|--------------|--------------| +| ----------- | ----------------------------------------------------------------------------------------------------- | -------- | ------ | ------------ | ------------ | | label | A brief description of the expected user input, which is displayed in the form. | Required | String | - | - | | description | A description of the set of checkboxes, which is displayed in the form. Supports Markdown formatting. | Optional | String | Empty String | - | | options | An array of checkboxes that the user can select. For syntax, see below. | Required | Array | - | - | For each value in the options array, you can set the following keys. -| Key | Description | Required | Type | Default | Options | -|----------|------------------------------------------------------------------------------------------------------------------------------------------|----------|---------|---------|---------| -| label | The identifier for the option, which is displayed in the form. Markdown is supported for bold or italic text formatting, and hyperlinks. | Required | String | - | - | -| required | Prevents form submission until element is completed. | Optional | Boolean | false | - | +| Key | Description | Required | Type | Default | Options | +|--------------|------------------------------------------------------------------------------------------------------------------------------------------|----------|--------------|---------|---------| +| label | The identifier for the option, which is displayed in the form. Markdown is supported for bold or italic text formatting, and hyperlinks. | Required | String | - | - | +| required | Prevents form submission until element is completed. | Optional | Boolean | false | - | +| visible | Whether a specific checkbox appears in the form only, in the created issue only, or both. Valid options are "form" and "content". | Optional | String array | false | - | + +visible: Default is **[form, content]** ## Syntax for issue config @@ -291,15 +313,15 @@ contact_links: ### Possible Options -| Key | Description | Type | Default | -|----------------------|-------------------------------------------------------------------------------------------------------|--------------------|----------------| -| blank_issues_enabled | If set to false, the User is forced to use a Template | Boolean | true | -| contact_links | Custom Links to show in the Choose Box | Contact Link Array | Empty Array | +| Key | Description | Type | Default | +|----------------------|-------------------------------------------------------|--------------------|-------------| +| blank_issues_enabled | If set to false, the User is forced to use a Template | Boolean | true | +| contact_links | Custom Links to show in the Choose Box | Contact Link Array | Empty Array | ### Contact Link -| Key | Description | Type | Required | -|----------------------|-------------------------------------------------------------------------------------------------------|---------|----------| -| name | the name of your link | String | true | -| url | The URL of your Link | String | true | -| about | A short description of your Link | String | true | +| Key | Description | Type | Required | +|-------|----------------------------------|--------|----------| +| name | the name of your link | String | true | +| url | The URL of your Link | String | true | +| about | A short description of your Link | String | true | diff --git a/models/actions/runner.go b/models/actions/runner.go index b646146ee..67f003387 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 8cb32f688..6df113138 100644 --- a/models/activities/action.go +++ b/models/activities/action.go @@ -227,8 +227,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 { @@ -238,8 +238,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 53920f059..1a3a1b20a 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 2c2151f35..a42ab77ca 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 071998b97..fd90f4fd5 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 c78fb3c5d..443effe08 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 49c3159f6..984fb9c9f 100644 --- a/models/issues/comment.go +++ b/models/issues/comment.go @@ -8,6 +8,7 @@ package issues import ( "context" "fmt" + "html/template" "strconv" "unicode/utf8" @@ -21,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" @@ -259,8 +261,8 @@ type Comment struct { CommitID int64 Line int64 // - previous line / + proposed line TreePath string - Content string `xorm:"LONGTEXT"` - RenderedContent string `xorm:"-"` + Content string `xorm:"LONGTEXT"` + RenderedContent template.HTML `xorm:"-"` // Path represents the 4 lines of code cemented by this comment Patch string `xorm:"-"` @@ -1043,8 +1045,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 @@ -1076,11 +1078,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 } @@ -1089,7 +1091,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.go b/models/issues/issue.go index b3b174496..baa79b30d 100644 --- a/models/issues/issue.go +++ b/models/issues/issue.go @@ -7,6 +7,7 @@ package issues import ( "context" "fmt" + "html/template" "regexp" "slices" @@ -105,7 +106,7 @@ type Issue struct { OriginalAuthorID int64 `xorm:"index"` Title string `xorm:"name"` Content string `xorm:"LONGTEXT"` - RenderedContent string `xorm:"-"` + RenderedContent template.HTML `xorm:"-"` Labels []*Label `xorm:"-"` MilestoneID int64 `xorm:"INDEX"` Milestone *Milestone `xorm:"-"` diff --git a/models/issues/issue_search.go b/models/issues/issue_search.go index 7dc277327..c5c9cecdb 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 99ca19f80..32c5674fc 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 527d8d785..f6ecc68cd 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 15987f222..4b3cb0e85 100644 --- a/models/issues/milestone.go +++ b/models/issues/milestone.go @@ -6,10 +6,12 @@ package issues import ( "context" "fmt" + "html/template" "strings" "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" @@ -47,8 +49,8 @@ type Milestone struct { RepoID int64 `xorm:"INDEX"` Repo *repo_model.Repository `xorm:"-"` Name string - Content string `xorm:"TEXT"` - RenderedContent string `xorm:"-"` + Content string `xorm:"TEXT"` + RenderedContent template.HTML `xorm:"-"` IsClosed bool NumIssues int NumClosedIssues int @@ -313,7 +315,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 a73bf73c1..d1b3f0301 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 7477af92c..e5f6f15ca 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 282f18b4f..ec6cb0798 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 91c4832e4..4063ca043 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 9beb862ff..d82bff967 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 f849ab5c0..b8ef698d3 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 53cdf2d4a..7a505ff08 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 8fc475691..505dbaa0a 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 d2fca6cdc..8f9ee2a99 100644 --- a/models/project/project.go +++ b/models/project/project.go @@ -6,11 +6,13 @@ package project import ( "context" "fmt" + "html/template" "code.gitea.io/gitea/models/db" 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" @@ -100,7 +102,7 @@ type Project struct { CardType CardType Type Type - RenderedContent string `xorm:"-"` + RenderedContent template.HTML `xorm:"-"` CreatedUnix timeutil.TimeStamp `xorm:"INDEX created"` UpdatedUnix timeutil.TimeStamp `xorm:"INDEX updated"` @@ -195,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 @@ -206,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/release.go b/models/repo/release.go index 1f37f11b2..a9f65f6c3 100644 --- a/models/repo/release.go +++ b/models/repo/release.go @@ -7,6 +7,7 @@ package repo import ( "context" "fmt" + "html/template" "net/url" "sort" "strconv" @@ -15,6 +16,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/optional" "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/timeutil" "code.gitea.io/gitea/modules/util" @@ -79,7 +81,7 @@ type Release struct { NumCommits int64 NumCommitsBehind int64 `xorm:"-"` Note string `xorm:"TEXT"` - RenderedNote string `xorm:"-"` + RenderedNote template.HTML `xorm:"-"` IsDraft bool `xorm:"NOT NULL DEFAULT false"` IsPrerelease bool `xorm:"NOT NULL DEFAULT false"` IsTag bool `xorm:"NOT NULL DEFAULT false"` // will be true only if the record is a tag and has no related releases @@ -228,10 +230,10 @@ type FindReleasesOptions struct { RepoID int64 IncludeDrafts bool IncludeTags bool - IsPreRelease util.OptionalBool - IsDraft util.OptionalBool + IsPreRelease optional.Option[bool] + IsDraft optional.Option[bool] TagNames []string - HasSha1 util.OptionalBool // useful to find draft releases which are created with existing tags + HasSha1 optional.Option[bool] // useful to find draft releases which are created with existing tags } func (opts FindReleasesOptions) ToConds() builder.Cond { @@ -246,14 +248,14 @@ func (opts FindReleasesOptions) ToConds() builder.Cond { if len(opts.TagNames) > 0 { cond = cond.And(builder.In("tag_name", opts.TagNames)) } - if !opts.IsPreRelease.IsNone() { - cond = cond.And(builder.Eq{"is_prerelease": opts.IsPreRelease.IsTrue()}) + if opts.IsPreRelease.Has() { + cond = cond.And(builder.Eq{"is_prerelease": opts.IsPreRelease.Value()}) } - if !opts.IsDraft.IsNone() { - cond = cond.And(builder.Eq{"is_draft": opts.IsDraft.IsTrue()}) + if opts.IsDraft.Has() { + cond = cond.And(builder.Eq{"is_draft": opts.IsDraft.Value()}) } - if !opts.HasSha1.IsNone() { - if opts.HasSha1.IsTrue() { + if opts.HasSha1.Has() { + if opts.HasSha1.Value() { cond = cond.And(builder.Neq{"sha1": ""}) } else { cond = cond.And(builder.Eq{"sha1": ""}) @@ -275,7 +277,7 @@ func GetTagNamesByRepoID(ctx context.Context, repoID int64) ([]string, error) { ListOptions: listOptions, IncludeDrafts: true, IncludeTags: true, - HasSha1: util.OptionalBoolTrue, + HasSha1: optional.Some(true), RepoID: repoID, } diff --git a/models/repo/repo.go b/models/repo/repo.go index b24e5c1db..81ed6efa2 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" @@ -873,7 +874,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. @@ -885,8 +886,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_list.go b/models/repo/repo_list.go index 533ca5251..6b452291e 100644 --- a/models/repo/repo_list.go +++ b/models/repo/repo_list.go @@ -13,6 +13,7 @@ import ( "code.gitea.io/gitea/models/unit" user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/container" + "code.gitea.io/gitea/modules/optional" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/util" @@ -125,11 +126,11 @@ type SearchRepoOptions struct { // None -> include public and private // True -> include just private // False -> include just public - IsPrivate util.OptionalBool + IsPrivate optional.Option[bool] // None -> include collaborative AND non-collaborative // True -> include just collaborative // False -> include just non-collaborative - Collaborate util.OptionalBool + Collaborate optional.Option[bool] // What type of unit the user can be collaborative in, // it is ignored if Collaborate is False. // TypeInvalid means any unit type. @@ -137,19 +138,19 @@ type SearchRepoOptions struct { // None -> include forks AND non-forks // True -> include just forks // False -> include just non-forks - Fork util.OptionalBool + Fork optional.Option[bool] // None -> include templates AND non-templates // True -> include just templates // False -> include just non-templates - Template util.OptionalBool + Template optional.Option[bool] // None -> include mirrors AND non-mirrors // True -> include just mirrors // False -> include just non-mirrors - Mirror util.OptionalBool + Mirror optional.Option[bool] // None -> include archived AND non-archived // True -> include just archived // False -> include just non-archived - Archived util.OptionalBool + Archived optional.Option[bool] // only search topic name TopicOnly bool // only search repositories with specified primary language @@ -159,7 +160,7 @@ type SearchRepoOptions struct { // None -> include has milestones AND has no milestone // True -> include just has milestones // False -> include just has no milestone - HasMilestones util.OptionalBool + HasMilestones optional.Option[bool] // LowerNames represents valid lower names to restrict to LowerNames []string // When specified true, apply some filters over the conditions: @@ -359,12 +360,12 @@ func SearchRepositoryCondition(opts *SearchRepoOptions) builder.Cond { ))) } - if opts.IsPrivate != util.OptionalBoolNone { - cond = cond.And(builder.Eq{"is_private": opts.IsPrivate.IsTrue()}) + if opts.IsPrivate.Has() { + cond = cond.And(builder.Eq{"is_private": opts.IsPrivate.Value()}) } - if opts.Template != util.OptionalBoolNone { - cond = cond.And(builder.Eq{"is_template": opts.Template == util.OptionalBoolTrue}) + if opts.Template.Has() { + cond = cond.And(builder.Eq{"is_template": opts.Template.Value()}) } // Restrict to starred repositories @@ -380,11 +381,11 @@ func SearchRepositoryCondition(opts *SearchRepoOptions) builder.Cond { // Restrict repositories to those the OwnerID owns or contributes to as per opts.Collaborate if opts.OwnerID > 0 { accessCond := builder.NewCond() - if opts.Collaborate != util.OptionalBoolTrue { + if !opts.Collaborate.Value() { accessCond = builder.Eq{"owner_id": opts.OwnerID} } - if opts.Collaborate != util.OptionalBoolFalse { + if opts.Collaborate.ValueOrDefault(true) { // A Collaboration is: collaborateCond := builder.NewCond() @@ -472,31 +473,32 @@ func SearchRepositoryCondition(opts *SearchRepoOptions) builder.Cond { Where(builder.Eq{"language": opts.Language}).And(builder.Eq{"is_primary": true}))) } - if opts.Fork != util.OptionalBoolNone || opts.OnlyShowRelevant { - if opts.OnlyShowRelevant && opts.Fork == util.OptionalBoolNone { + if opts.Fork.Has() || opts.OnlyShowRelevant { + if opts.OnlyShowRelevant && !opts.Fork.Has() { cond = cond.And(builder.Eq{"is_fork": false}) } else { - cond = cond.And(builder.Eq{"is_fork": opts.Fork == util.OptionalBoolTrue}) + cond = cond.And(builder.Eq{"is_fork": opts.Fork.Value()}) } } - if opts.Mirror != util.OptionalBoolNone { - cond = cond.And(builder.Eq{"is_mirror": opts.Mirror == util.OptionalBoolTrue}) + if opts.Mirror.Has() { + cond = cond.And(builder.Eq{"is_mirror": opts.Mirror.Value()}) } if opts.Actor != nil && opts.Actor.IsRestricted { cond = cond.And(AccessibleRepositoryCondition(opts.Actor, unit.TypeInvalid)) } - if opts.Archived != util.OptionalBoolNone { - cond = cond.And(builder.Eq{"is_archived": opts.Archived == util.OptionalBoolTrue}) + if opts.Archived.Has() { + cond = cond.And(builder.Eq{"is_archived": opts.Archived.Value()}) } - switch opts.HasMilestones { - case util.OptionalBoolTrue: - cond = cond.And(builder.Gt{"num_milestones": 0}) - case util.OptionalBoolFalse: - cond = cond.And(builder.Eq{"num_milestones": 0}.Or(builder.IsNull{"num_milestones"})) + if opts.HasMilestones.Has() { + if opts.HasMilestones.Value() { + cond = cond.And(builder.Gt{"num_milestones": 0}) + } else { + cond = cond.And(builder.Eq{"num_milestones": 0}.Or(builder.IsNull{"num_milestones"})) + } } if opts.OnlyShowRelevant { diff --git a/models/repo/repo_list_test.go b/models/repo/repo_list_test.go index 800628946..ca6007f6c 100644 --- a/models/repo/repo_list_test.go +++ b/models/repo/repo_list_test.go @@ -10,7 +10,7 @@ import ( "code.gitea.io/gitea/models/db" repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/models/unittest" - "code.gitea.io/gitea/modules/util" + "code.gitea.io/gitea/modules/optional" "github.com/stretchr/testify/assert" ) @@ -27,62 +27,62 @@ func getTestCases() []struct { }{ { name: "PublicRepositoriesByName", - opts: &repo_model.SearchRepoOptions{Keyword: "big_test_", ListOptions: db.ListOptions{PageSize: 10}, Collaborate: util.OptionalBoolFalse}, + opts: &repo_model.SearchRepoOptions{Keyword: "big_test_", ListOptions: db.ListOptions{PageSize: 10}, Collaborate: optional.Some(false)}, count: 7, }, { name: "PublicAndPrivateRepositoriesByName", - opts: &repo_model.SearchRepoOptions{Keyword: "big_test_", ListOptions: db.ListOptions{Page: 1, PageSize: 10}, Private: true, Collaborate: util.OptionalBoolFalse}, + opts: &repo_model.SearchRepoOptions{Keyword: "big_test_", ListOptions: db.ListOptions{Page: 1, PageSize: 10}, Private: true, Collaborate: optional.Some(false)}, count: 14, }, { name: "PublicAndPrivateRepositoriesByNameWithPagesizeLimitFirstPage", - opts: &repo_model.SearchRepoOptions{Keyword: "big_test_", ListOptions: db.ListOptions{Page: 1, PageSize: 5}, Private: true, Collaborate: util.OptionalBoolFalse}, + opts: &repo_model.SearchRepoOptions{Keyword: "big_test_", ListOptions: db.ListOptions{Page: 1, PageSize: 5}, Private: true, Collaborate: optional.Some(false)}, count: 14, }, { name: "PublicAndPrivateRepositoriesByNameWithPagesizeLimitSecondPage", - opts: &repo_model.SearchRepoOptions{Keyword: "big_test_", ListOptions: db.ListOptions{Page: 2, PageSize: 5}, Private: true, Collaborate: util.OptionalBoolFalse}, + opts: &repo_model.SearchRepoOptions{Keyword: "big_test_", ListOptions: db.ListOptions{Page: 2, PageSize: 5}, Private: true, Collaborate: optional.Some(false)}, count: 14, }, { name: "PublicAndPrivateRepositoriesByNameWithPagesizeLimitThirdPage", - opts: &repo_model.SearchRepoOptions{Keyword: "big_test_", ListOptions: db.ListOptions{Page: 3, PageSize: 5}, Private: true, Collaborate: util.OptionalBoolFalse}, + opts: &repo_model.SearchRepoOptions{Keyword: "big_test_", ListOptions: db.ListOptions{Page: 3, PageSize: 5}, Private: true, Collaborate: optional.Some(false)}, count: 14, }, { name: "PublicAndPrivateRepositoriesByNameWithPagesizeLimitFourthPage", - opts: &repo_model.SearchRepoOptions{Keyword: "big_test_", ListOptions: db.ListOptions{Page: 3, PageSize: 5}, Private: true, Collaborate: util.OptionalBoolFalse}, + opts: &repo_model.SearchRepoOptions{Keyword: "big_test_", ListOptions: db.ListOptions{Page: 3, PageSize: 5}, Private: true, Collaborate: optional.Some(false)}, count: 14, }, { name: "PublicRepositoriesOfUser", - opts: &repo_model.SearchRepoOptions{ListOptions: db.ListOptions{Page: 1, PageSize: 10}, OwnerID: 15, Collaborate: util.OptionalBoolFalse}, + opts: &repo_model.SearchRepoOptions{ListOptions: db.ListOptions{Page: 1, PageSize: 10}, OwnerID: 15, Collaborate: optional.Some(false)}, count: 2, }, { name: "PublicRepositoriesOfUser2", - opts: &repo_model.SearchRepoOptions{ListOptions: db.ListOptions{Page: 1, PageSize: 10}, OwnerID: 18, Collaborate: util.OptionalBoolFalse}, + opts: &repo_model.SearchRepoOptions{ListOptions: db.ListOptions{Page: 1, PageSize: 10}, OwnerID: 18, Collaborate: optional.Some(false)}, count: 0, }, { name: "PublicRepositoriesOfOrg3", - opts: &repo_model.SearchRepoOptions{ListOptions: db.ListOptions{Page: 1, PageSize: 10}, OwnerID: 20, Collaborate: util.OptionalBoolFalse}, + opts: &repo_model.SearchRepoOptions{ListOptions: db.ListOptions{Page: 1, PageSize: 10}, OwnerID: 20, Collaborate: optional.Some(false)}, count: 2, }, { name: "PublicAndPrivateRepositoriesOfUser", - opts: &repo_model.SearchRepoOptions{ListOptions: db.ListOptions{Page: 1, PageSize: 10}, OwnerID: 15, Private: true, Collaborate: util.OptionalBoolFalse}, + opts: &repo_model.SearchRepoOptions{ListOptions: db.ListOptions{Page: 1, PageSize: 10}, OwnerID: 15, Private: true, Collaborate: optional.Some(false)}, count: 4, }, { name: "PublicAndPrivateRepositoriesOfUser2", - opts: &repo_model.SearchRepoOptions{ListOptions: db.ListOptions{Page: 1, PageSize: 10}, OwnerID: 18, Private: true, Collaborate: util.OptionalBoolFalse}, + opts: &repo_model.SearchRepoOptions{ListOptions: db.ListOptions{Page: 1, PageSize: 10}, OwnerID: 18, Private: true, Collaborate: optional.Some(false)}, count: 0, }, { name: "PublicAndPrivateRepositoriesOfOrg3", - opts: &repo_model.SearchRepoOptions{ListOptions: db.ListOptions{Page: 1, PageSize: 10}, OwnerID: 20, Private: true, Collaborate: util.OptionalBoolFalse}, + opts: &repo_model.SearchRepoOptions{ListOptions: db.ListOptions{Page: 1, PageSize: 10}, OwnerID: 20, Private: true, Collaborate: optional.Some(false)}, count: 4, }, { @@ -117,32 +117,32 @@ func getTestCases() []struct { }, { name: "PublicRepositoriesOfOrganization", - opts: &repo_model.SearchRepoOptions{ListOptions: db.ListOptions{Page: 1, PageSize: 10}, OwnerID: 17, Collaborate: util.OptionalBoolFalse}, + opts: &repo_model.SearchRepoOptions{ListOptions: db.ListOptions{Page: 1, PageSize: 10}, OwnerID: 17, Collaborate: optional.Some(false)}, count: 1, }, { name: "PublicAndPrivateRepositoriesOfOrganization", - opts: &repo_model.SearchRepoOptions{ListOptions: db.ListOptions{Page: 1, PageSize: 10}, OwnerID: 17, Private: true, Collaborate: util.OptionalBoolFalse}, + opts: &repo_model.SearchRepoOptions{ListOptions: db.ListOptions{Page: 1, PageSize: 10}, OwnerID: 17, Private: true, Collaborate: optional.Some(false)}, count: 2, }, { name: "AllPublic/PublicRepositoriesByName", - opts: &repo_model.SearchRepoOptions{Keyword: "big_test_", ListOptions: db.ListOptions{PageSize: 10}, AllPublic: true, Collaborate: util.OptionalBoolFalse}, + opts: &repo_model.SearchRepoOptions{Keyword: "big_test_", ListOptions: db.ListOptions{PageSize: 10}, AllPublic: true, Collaborate: optional.Some(false)}, count: 7, }, { name: "AllPublic/PublicAndPrivateRepositoriesByName", - opts: &repo_model.SearchRepoOptions{Keyword: "big_test_", ListOptions: db.ListOptions{Page: 1, PageSize: 10}, Private: true, AllPublic: true, Collaborate: util.OptionalBoolFalse}, + opts: &repo_model.SearchRepoOptions{Keyword: "big_test_", ListOptions: db.ListOptions{Page: 1, PageSize: 10}, Private: true, AllPublic: true, Collaborate: optional.Some(false)}, count: 14, }, { name: "AllPublic/PublicRepositoriesOfUserIncludingCollaborative", - opts: &repo_model.SearchRepoOptions{ListOptions: db.ListOptions{Page: 1, PageSize: 10}, OwnerID: 15, AllPublic: true, Template: util.OptionalBoolFalse}, + opts: &repo_model.SearchRepoOptions{ListOptions: db.ListOptions{Page: 1, PageSize: 10}, OwnerID: 15, AllPublic: true, Template: optional.Some(false)}, count: 34, }, { name: "AllPublic/PublicAndPrivateRepositoriesOfUserIncludingCollaborative", - opts: &repo_model.SearchRepoOptions{ListOptions: db.ListOptions{Page: 1, PageSize: 10}, OwnerID: 15, Private: true, AllPublic: true, AllLimited: true, Template: util.OptionalBoolFalse}, + opts: &repo_model.SearchRepoOptions{ListOptions: db.ListOptions{Page: 1, PageSize: 10}, OwnerID: 15, Private: true, AllPublic: true, AllLimited: true, Template: optional.Some(false)}, count: 39, }, { @@ -157,12 +157,12 @@ func getTestCases() []struct { }, { name: "AllPublic/PublicRepositoriesOfOrganization", - opts: &repo_model.SearchRepoOptions{ListOptions: db.ListOptions{Page: 1, PageSize: 10}, OwnerID: 17, AllPublic: true, Collaborate: util.OptionalBoolFalse, Template: util.OptionalBoolFalse}, + opts: &repo_model.SearchRepoOptions{ListOptions: db.ListOptions{Page: 1, PageSize: 10}, OwnerID: 17, AllPublic: true, Collaborate: optional.Some(false), Template: optional.Some(false)}, count: 34, }, { name: "AllTemplates", - opts: &repo_model.SearchRepoOptions{ListOptions: db.ListOptions{Page: 1, PageSize: 10}, Template: util.OptionalBoolTrue}, + opts: &repo_model.SearchRepoOptions{ListOptions: db.ListOptions{Page: 1, PageSize: 10}, Template: optional.Some(true)}, count: 2, }, { @@ -190,7 +190,7 @@ func TestSearchRepository(t *testing.T) { PageSize: 10, }, Keyword: "repo_12", - Collaborate: util.OptionalBoolFalse, + Collaborate: optional.Some(false), }) assert.NoError(t, err) @@ -205,7 +205,7 @@ func TestSearchRepository(t *testing.T) { PageSize: 10, }, Keyword: "test_repo", - Collaborate: util.OptionalBoolFalse, + Collaborate: optional.Some(false), }) assert.NoError(t, err) @@ -220,7 +220,7 @@ func TestSearchRepository(t *testing.T) { }, Keyword: "repo_13", Private: true, - Collaborate: util.OptionalBoolFalse, + Collaborate: optional.Some(false), }) assert.NoError(t, err) @@ -236,7 +236,7 @@ func TestSearchRepository(t *testing.T) { }, Keyword: "test_repo", Private: true, - Collaborate: util.OptionalBoolFalse, + Collaborate: optional.Some(false), }) assert.NoError(t, err) @@ -257,7 +257,7 @@ func TestSearchRepository(t *testing.T) { PageSize: 10, }, Keyword: "description_14", - Collaborate: util.OptionalBoolFalse, + Collaborate: optional.Some(false), IncludeDescription: true, }) @@ -274,7 +274,7 @@ func TestSearchRepository(t *testing.T) { PageSize: 10, }, Keyword: "description_14", - Collaborate: util.OptionalBoolFalse, + Collaborate: optional.Some(false), IncludeDescription: false, }) @@ -327,30 +327,25 @@ func TestSearchRepository(t *testing.T) { assert.False(t, repo.IsPrivate) } - if testCase.opts.Fork == util.OptionalBoolTrue && testCase.opts.Mirror == util.OptionalBoolTrue { - assert.True(t, repo.IsFork || repo.IsMirror) + if testCase.opts.Fork.Value() && testCase.opts.Mirror.Value() { + assert.True(t, repo.IsFork && repo.IsMirror) } else { - switch testCase.opts.Fork { - case util.OptionalBoolFalse: - assert.False(t, repo.IsFork) - case util.OptionalBoolTrue: - assert.True(t, repo.IsFork) + if testCase.opts.Fork.Has() { + assert.Equal(t, testCase.opts.Fork.Value(), repo.IsFork) } - switch testCase.opts.Mirror { - case util.OptionalBoolFalse: - assert.False(t, repo.IsMirror) - case util.OptionalBoolTrue: - assert.True(t, repo.IsMirror) + if testCase.opts.Mirror.Has() { + assert.Equal(t, testCase.opts.Mirror.Value(), repo.IsMirror) } } if testCase.opts.OwnerID > 0 && !testCase.opts.AllPublic { - switch testCase.opts.Collaborate { - case util.OptionalBoolFalse: - assert.Equal(t, testCase.opts.OwnerID, repo.Owner.ID) - case util.OptionalBoolTrue: - assert.NotEqual(t, testCase.opts.OwnerID, repo.Owner.ID) + if testCase.opts.Collaborate.Has() { + if testCase.opts.Collaborate.Value() { + assert.NotEqual(t, testCase.opts.OwnerID, repo.Owner.ID) + } else { + assert.Equal(t, testCase.opts.OwnerID, repo.Owner.ID) + } } } } diff --git a/models/repo/repo_test.go b/models/repo/repo_test.go index ca9209d75..1a870224b 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/email_address.go b/models/user/email_address.go index cc62620e0..6f3d5b1dd 100644 --- a/models/user/email_address.go +++ b/models/user/email_address.go @@ -14,6 +14,7 @@ import ( "code.gitea.io/gitea/models/db" "code.gitea.io/gitea/modules/base" "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/validation" @@ -425,8 +426,8 @@ type SearchEmailOptions struct { db.ListOptions Keyword string SortType SearchEmailOrderBy - IsPrimary util.OptionalBool - IsActivated util.OptionalBool + IsPrimary optional.Option[bool] + IsActivated optional.Option[bool] } // SearchEmailResult is an e-mail address found in the user or email_address table @@ -453,18 +454,12 @@ func SearchEmails(ctx context.Context, opts *SearchEmailOptions) ([]*SearchEmail )) } - switch { - case opts.IsPrimary.IsTrue(): - cond = cond.And(builder.Eq{"email_address.is_primary": true}) - case opts.IsPrimary.IsFalse(): - cond = cond.And(builder.Eq{"email_address.is_primary": false}) + if opts.IsPrimary.Has() { + cond = cond.And(builder.Eq{"email_address.is_primary": opts.IsPrimary.Value()}) } - switch { - case opts.IsActivated.IsTrue(): - cond = cond.And(builder.Eq{"email_address.is_activated": true}) - case opts.IsActivated.IsFalse(): - cond = cond.And(builder.Eq{"email_address.is_activated": false}) + if opts.IsActivated.Has() { + cond = cond.And(builder.Eq{"email_address.is_activated": opts.IsActivated.Value()}) } count, err := db.GetEngine(ctx).Join("INNER", "`user`", "`user`.ID = email_address.uid"). diff --git a/models/user/email_address_test.go b/models/user/email_address_test.go index be1ccea54..65befa566 100644 --- a/models/user/email_address_test.go +++ b/models/user/email_address_test.go @@ -10,7 +10,7 @@ import ( "code.gitea.io/gitea/models/db" "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" ) @@ -138,14 +138,14 @@ func TestListEmails(t *testing.T) { assert.True(t, contains(func(s *user_model.SearchEmailResult) bool { return s.UID == 27 })) // Must find only primary addresses (i.e. from the `user` table) - opts = &user_model.SearchEmailOptions{IsPrimary: util.OptionalBoolTrue} + opts = &user_model.SearchEmailOptions{IsPrimary: optional.Some(true)} emails, _, err = user_model.SearchEmails(db.DefaultContext, opts) assert.NoError(t, err) assert.True(t, contains(func(s *user_model.SearchEmailResult) bool { return s.IsPrimary })) assert.False(t, contains(func(s *user_model.SearchEmailResult) bool { return !s.IsPrimary })) // Must find only inactive addresses (i.e. not validated) - opts = &user_model.SearchEmailOptions{IsActivated: util.OptionalBoolFalse} + opts = &user_model.SearchEmailOptions{IsActivated: optional.Some(false)} emails, _, err = user_model.SearchEmails(db.DefaultContext, opts) assert.NoError(t, err) assert.True(t, contains(func(s *user_model.SearchEmailResult) bool { return !s.IsActivated })) diff --git a/models/user/search.go b/models/user/search.go index 0fa278c25..45b051187 100644 --- a/models/user/search.go +++ b/models/user/search.go @@ -9,8 +9,9 @@ import ( "strings" "code.gitea.io/gitea/models/db" + "code.gitea.io/gitea/modules/container" + "code.gitea.io/gitea/modules/optional" "code.gitea.io/gitea/modules/structs" - "code.gitea.io/gitea/modules/util" "xorm.io/builder" "xorm.io/xorm" @@ -30,11 +31,13 @@ type SearchUserOptions struct { Actor *User // The user doing the search SearchByEmail bool // Search by email as well as username/full name - IsActive util.OptionalBool - IsAdmin util.OptionalBool - IsRestricted util.OptionalBool - IsTwoFactorEnabled util.OptionalBool - IsProhibitLogin util.OptionalBool + SupportedSortOrders container.Set[string] // if not nil, only allow to use the sort orders in this set + + IsActive optional.Option[bool] + IsAdmin optional.Option[bool] + IsRestricted optional.Option[bool] + IsTwoFactorEnabled optional.Option[bool] + IsProhibitLogin optional.Option[bool] IncludeReserved bool ExtraParamStrings map[string]string @@ -86,24 +89,24 @@ func (opts *SearchUserOptions) toSearchQueryBase(ctx context.Context) *xorm.Sess cond = cond.And(builder.Eq{"login_name": opts.LoginName}) } - if !opts.IsActive.IsNone() { - cond = cond.And(builder.Eq{"is_active": opts.IsActive.IsTrue()}) + if opts.IsActive.Has() { + cond = cond.And(builder.Eq{"is_active": opts.IsActive.Value()}) } - 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()}) } - if !opts.IsRestricted.IsNone() { - cond = cond.And(builder.Eq{"is_restricted": opts.IsRestricted.IsTrue()}) + if opts.IsRestricted.Has() { + cond = cond.And(builder.Eq{"is_restricted": opts.IsRestricted.Value()}) } - if !opts.IsProhibitLogin.IsNone() { - cond = cond.And(builder.Eq{"prohibit_login": opts.IsProhibitLogin.IsTrue()}) + if opts.IsProhibitLogin.Has() { + cond = cond.And(builder.Eq{"prohibit_login": opts.IsProhibitLogin.Value()}) } e := db.GetEngine(ctx) - if opts.IsTwoFactorEnabled.IsNone() { + if !opts.IsTwoFactorEnabled.Has() { return e.Where(cond) } @@ -111,7 +114,7 @@ func (opts *SearchUserOptions) toSearchQueryBase(ctx context.Context) *xorm.Sess // While using LEFT JOIN, sometimes the performance might not be good, but it won't be a problem now, such SQL is seldom executed. // There are some possible methods to refactor this SQL in future when we really need to optimize the performance (but not now): // (1) add a column in user table (2) add a setting value in user_setting table (3) use search engines (bleve/elasticsearch) - if opts.IsTwoFactorEnabled.IsTrue() { + if opts.IsTwoFactorEnabled.Value() { cond = cond.And(builder.Expr("two_factor.uid IS NOT NULL")) } else { cond = cond.And(builder.Expr("two_factor.uid IS NULL")) @@ -128,7 +131,7 @@ func SearchUsers(ctx context.Context, opts *SearchUserOptions) (users []*User, _ defer sessCount.Close() count, err := sessCount.Count(new(User)) if err != nil { - return nil, 0, fmt.Errorf("Count: %w", err) + return nil, 0, fmt.Errorf("count: %w", err) } if len(opts.OrderBy) == 0 { diff --git a/models/user/user.go b/models/user/user.go index 9ff4881ec..710fab9f4 100644 --- a/models/user/user.go +++ b/models/user/user.go @@ -727,7 +727,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 @@ -736,7 +736,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. @@ -754,8 +754,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/user/user_test.go b/models/user/user_test.go index 87a842a4d..bb7274330 100644 --- a/models/user/user_test.go +++ b/models/user/user_test.go @@ -16,10 +16,10 @@ import ( "code.gitea.io/gitea/models/unittest" user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/auth/password/hash" + "code.gitea.io/gitea/modules/optional" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/timeutil" - "code.gitea.io/gitea/modules/util" "github.com/stretchr/testify/assert" ) @@ -103,29 +103,29 @@ func TestSearchUsers(t *testing.T) { testUserSuccess(&user_model.SearchUserOptions{OrderBy: "id ASC", ListOptions: db.ListOptions{Page: 1}}, []int64{1, 2, 4, 5, 8, 9, 10, 11, 12, 13, 14, 15, 16, 18, 20, 21, 24, 27, 28, 29, 30, 32, 34, 37, 38, 39, 40}) - testUserSuccess(&user_model.SearchUserOptions{ListOptions: db.ListOptions{Page: 1}, IsActive: util.OptionalBoolFalse}, + testUserSuccess(&user_model.SearchUserOptions{ListOptions: db.ListOptions{Page: 1}, IsActive: optional.Some(false)}, []int64{9}) - testUserSuccess(&user_model.SearchUserOptions{OrderBy: "id ASC", ListOptions: db.ListOptions{Page: 1}, IsActive: util.OptionalBoolTrue}, + testUserSuccess(&user_model.SearchUserOptions{OrderBy: "id ASC", ListOptions: db.ListOptions{Page: 1}, IsActive: optional.Some(true)}, []int64{1, 2, 4, 5, 8, 10, 11, 12, 13, 14, 15, 16, 18, 20, 21, 24, 27, 28, 29, 30, 32, 34, 37, 38, 39, 40}) - testUserSuccess(&user_model.SearchUserOptions{Keyword: "user1", OrderBy: "id ASC", ListOptions: db.ListOptions{Page: 1}, IsActive: util.OptionalBoolTrue}, + testUserSuccess(&user_model.SearchUserOptions{Keyword: "user1", OrderBy: "id ASC", ListOptions: db.ListOptions{Page: 1}, IsActive: optional.Some(true)}, []int64{1, 10, 11, 12, 13, 14, 15, 16, 18}) // order by name asc default - testUserSuccess(&user_model.SearchUserOptions{Keyword: "user1", ListOptions: db.ListOptions{Page: 1}, IsActive: util.OptionalBoolTrue}, + testUserSuccess(&user_model.SearchUserOptions{Keyword: "user1", ListOptions: db.ListOptions{Page: 1}, IsActive: optional.Some(true)}, []int64{1, 10, 11, 12, 13, 14, 15, 16, 18}) - testUserSuccess(&user_model.SearchUserOptions{ListOptions: db.ListOptions{Page: 1}, IsAdmin: util.OptionalBoolTrue}, + testUserSuccess(&user_model.SearchUserOptions{ListOptions: db.ListOptions{Page: 1}, IsAdmin: optional.Some(true)}, []int64{1}) - testUserSuccess(&user_model.SearchUserOptions{ListOptions: db.ListOptions{Page: 1}, IsRestricted: util.OptionalBoolTrue}, + testUserSuccess(&user_model.SearchUserOptions{ListOptions: db.ListOptions{Page: 1}, IsRestricted: optional.Some(true)}, []int64{29}) - testUserSuccess(&user_model.SearchUserOptions{ListOptions: db.ListOptions{Page: 1}, IsProhibitLogin: util.OptionalBoolTrue}, + testUserSuccess(&user_model.SearchUserOptions{ListOptions: db.ListOptions{Page: 1}, IsProhibitLogin: optional.Some(true)}, []int64{37}) - testUserSuccess(&user_model.SearchUserOptions{ListOptions: db.ListOptions{Page: 1}, IsTwoFactorEnabled: util.OptionalBoolTrue}, + testUserSuccess(&user_model.SearchUserOptions{ListOptions: db.ListOptions{Page: 1}, IsTwoFactorEnabled: optional.Some(true)}, []int64{24}) } diff --git a/models/webhook/webhook.go b/models/webhook/webhook.go index 4a84a3d41..894357e36 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 2e89f9547..a2a9ee321 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 694fd7a87..c70c8e99f 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/actions/task_state.go b/modules/actions/task_state.go index cbbc0b357..fe925bbb5 100644 --- a/modules/actions/task_state.go +++ b/modules/actions/task_state.go @@ -35,6 +35,9 @@ func FullSteps(task *actions_model.ActionTask) []*actions_model.ActionTaskStep { } else if task.Status.IsDone() { preStep.Stopped = task.Stopped preStep.Status = actions_model.StatusFailure + if task.Status.IsSkipped() { + preStep.Status = actions_model.StatusSkipped + } } logIndex += preStep.LogLength diff --git a/modules/actions/workflows.go b/modules/actions/workflows.go index 81ab26bc2..8317f16db 100644 --- a/modules/actions/workflows.go +++ b/modules/actions/workflows.go @@ -406,6 +406,9 @@ func matchPullRequestEvent(gitRepo *git.Repository, commit *git.Commit, prPayloa // all acts conditions should be satisfied for cond, vals := range acts { switch cond { + case "types": + // types have been checked + continue case "branches": refName := git.RefName(prPayload.PullRequest.Base.Ref) patterns, err := workflowpattern.CompilePatterns(vals...) diff --git a/modules/git/command.go b/modules/git/command.go index 9305ef6f9..371109730 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 7c82cfbb7..6a5d65cb6 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 5406715bb..69146573a 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 d059f76b3..3acd3ade7 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.go b/modules/indexer/issues/indexer.go index 57037d294..e3bc21b49 100644 --- a/modules/indexer/issues/indexer.go +++ b/modules/indexer/issues/indexer.go @@ -20,10 +20,10 @@ import ( "code.gitea.io/gitea/modules/indexer/issues/internal" "code.gitea.io/gitea/modules/indexer/issues/meilisearch" "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/optional" "code.gitea.io/gitea/modules/process" "code.gitea.io/gitea/modules/queue" "code.gitea.io/gitea/modules/setting" - "code.gitea.io/gitea/modules/util" ) // IndexerMetadata is used to send data to the queue, so it contains only the ids. @@ -220,7 +220,7 @@ func PopulateIssueIndexer(ctx context.Context) error { ListOptions: db_model.ListOptions{Page: page, PageSize: repo_model.RepositoryListDefaultPageSize}, OrderBy: db_model.SearchOrderByID, Private: true, - Collaborate: util.OptionalBoolFalse, + Collaborate: optional.Some(false), }) if err != nil { log.Error("SearchRepositoryByName: %v", err) diff --git a/modules/indexer/issues/indexer_test.go b/modules/indexer/issues/indexer_test.go index 3b96686d9..10ffa7cbe 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 031745dd2..947335d8c 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 06fddeb65..672447153 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 ab8dcd0af..325883196 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/issue/template/template.go b/modules/issue/template/template.go index 4e813fc91..3be48b9ed 100644 --- a/modules/issue/template/template.go +++ b/modules/issue/template/template.go @@ -122,7 +122,13 @@ func validateRequired(field *api.IssueFormField, idx int) error { // The label is not required for a markdown or checkboxes field return nil } - return validateBoolItem(newErrorPosition(idx, field.Type), field.Validations, "required") + if err := validateBoolItem(newErrorPosition(idx, field.Type), field.Validations, "required"); err != nil { + return err + } + if required, _ := field.Validations["required"].(bool); required && !field.VisibleOnForm() { + return newErrorPosition(idx, field.Type).Errorf("can not require a hidden field") + } + return nil } func validateID(field *api.IssueFormField, idx int, ids container.Set[string]) error { @@ -172,10 +178,38 @@ func validateOptions(field *api.IssueFormField, idx int) error { return position.Errorf("'label' is required and should be a string") } + if visibility, ok := opt["visible"]; ok { + visibilityList, ok := visibility.([]any) + if !ok { + return position.Errorf("'visible' should be list") + } + for _, visibleType := range visibilityList { + visibleType, ok := visibleType.(string) + if !ok || !(visibleType == "form" || visibleType == "content") { + return position.Errorf("'visible' list can only contain strings of 'form' and 'content'") + } + } + } + if required, ok := opt["required"]; ok { if _, ok := required.(bool); !ok { return position.Errorf("'required' should be a bool") } + + // validate if hidden field is required + if visibility, ok := opt["visible"]; ok { + visibilityList, _ := visibility.([]any) + isVisible := false + for _, v := range visibilityList { + if vv, _ := v.(string); vv == "form" { + isVisible = true + break + } + } + if !isVisible { + return position.Errorf("can not require a hidden checkbox") + } + } } } } @@ -238,7 +272,7 @@ func RenderToMarkdown(template *api.IssueTemplate, values url.Values) string { IssueFormField: field, Values: values, } - if f.ID == "" { + if f.ID == "" || !f.VisibleInContent() { continue } f.WriteTo(builder) @@ -253,11 +287,6 @@ type valuedField struct { } func (f *valuedField) WriteTo(builder *strings.Builder) { - if f.Type == api.IssueFormFieldTypeMarkdown { - // markdown blocks do not appear in output - return - } - // write label if !f.HideLabel() { _, _ = fmt.Fprintf(builder, "### %s\n\n", f.Label()) @@ -269,6 +298,9 @@ func (f *valuedField) WriteTo(builder *strings.Builder) { switch f.Type { case api.IssueFormFieldTypeCheckboxes: for _, option := range f.Options() { + if !option.VisibleInContent() { + continue + } checked := " " if option.IsChecked() { checked = "x" @@ -302,6 +334,10 @@ func (f *valuedField) WriteTo(builder *strings.Builder) { } else { _, _ = fmt.Fprintf(builder, "%s\n", value) } + case api.IssueFormFieldTypeMarkdown: + if value, ok := f.Attributes["value"].(string); ok { + _, _ = fmt.Fprintf(builder, "%s\n", value) + } } _, _ = fmt.Fprintln(builder) } @@ -314,6 +350,9 @@ func (f *valuedField) Label() string { } func (f *valuedField) HideLabel() bool { + if f.Type == api.IssueFormFieldTypeMarkdown { + return true + } if label, ok := f.Attributes["hide_label"].(bool); ok { return label } @@ -385,6 +424,22 @@ func (o *valuedOption) IsChecked() bool { return false } +func (o *valuedOption) VisibleInContent() bool { + if o.field.Type == api.IssueFormFieldTypeCheckboxes { + if vs, ok := o.data.(map[string]any); ok { + if vl, ok := vs["visible"].([]any); ok { + for _, v := range vl { + if vv, _ := v.(string); vv == "content" { + return true + } + } + return false + } + } + } + return true +} + var minQuotesRegex = regexp.MustCompilePOSIX("^`{3,}") // minQuotes return 3 or more back-quotes. diff --git a/modules/issue/template/template_test.go b/modules/issue/template/template_test.go index 06e6b70d3..e24b962d6 100644 --- a/modules/issue/template/template_test.go +++ b/modules/issue/template/template_test.go @@ -10,6 +10,7 @@ import ( "code.gitea.io/gitea/modules/json" api "code.gitea.io/gitea/modules/structs" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) @@ -318,6 +319,42 @@ body: `, wantErr: "body[0](checkboxes), option[0]: 'required' should be a bool", }, + { + name: "field is required but hidden", + content: ` +name: "test" +about: "this is about" +body: + - type: "input" + id: "1" + attributes: + label: "a" + validations: + required: true + visible: [content] +`, + wantErr: "body[0](input): can not require a hidden field", + }, + { + name: "checkboxes is required but hidden", + content: ` +name: "test" +about: "this is about" +body: + - type: checkboxes + id: "1" + attributes: + label: Label of checkboxes + description: Description of checkboxes + options: + - label: Option 1 + required: false + - label: Required and hidden + required: true + visible: [content] +`, + wantErr: "body[0](checkboxes), option[1]: can not require a hidden checkbox", + }, { name: "valid", content: ` @@ -374,8 +411,11 @@ body: required: true - label: Option 2 of checkboxes required: false - - label: Option 3 of checkboxes + - label: Hidden Option 3 of checkboxes + visible: [content] + - label: Required but not submitted required: true + visible: [form] `, want: &api.IssueTemplate{ Name: "Name", @@ -390,6 +430,7 @@ body: Attributes: map[string]any{ "value": "Value of the markdown", }, + Visible: []api.IssueFormFieldVisible{api.IssueFormFieldVisibleForm}, }, { Type: "textarea", @@ -404,6 +445,7 @@ body: Validations: map[string]any{ "required": true, }, + Visible: []api.IssueFormFieldVisible{api.IssueFormFieldVisibleForm, api.IssueFormFieldVisibleContent}, }, { Type: "input", @@ -419,6 +461,7 @@ body: "is_number": true, "regex": "[a-zA-Z0-9]+", }, + Visible: []api.IssueFormFieldVisible{api.IssueFormFieldVisibleForm, api.IssueFormFieldVisibleContent}, }, { Type: "dropdown", @@ -436,6 +479,7 @@ body: Validations: map[string]any{ "required": true, }, + Visible: []api.IssueFormFieldVisible{api.IssueFormFieldVisibleForm, api.IssueFormFieldVisibleContent}, }, { Type: "checkboxes", @@ -446,9 +490,11 @@ body: "options": []any{ map[string]any{"label": "Option 1 of checkboxes", "required": true}, map[string]any{"label": "Option 2 of checkboxes", "required": false}, - map[string]any{"label": "Option 3 of checkboxes", "required": true}, + map[string]any{"label": "Hidden Option 3 of checkboxes", "visible": []string{"content"}}, + map[string]any{"label": "Required but not submitted", "required": true, "visible": []string{"form"}}, }, }, + Visible: []api.IssueFormFieldVisible{api.IssueFormFieldVisibleForm, api.IssueFormFieldVisibleContent}, }, }, FileName: "test.yaml", @@ -467,7 +513,12 @@ body: - type: markdown id: id1 attributes: - value: Value of the markdown + value: Value of the markdown shown in form + - type: markdown + id: id2 + attributes: + value: Value of the markdown shown in created issue + visible: [content] `, want: &api.IssueTemplate{ Name: "Name", @@ -480,8 +531,17 @@ body: Type: "markdown", ID: "id1", Attributes: map[string]any{ - "value": "Value of the markdown", + "value": "Value of the markdown shown in form", }, + Visible: []api.IssueFormFieldVisible{api.IssueFormFieldVisibleForm}, + }, + { + Type: "markdown", + ID: "id2", + Attributes: map[string]any{ + "value": "Value of the markdown shown in created issue", + }, + Visible: []api.IssueFormFieldVisible{api.IssueFormFieldVisibleContent}, }, }, FileName: "test.yaml", @@ -515,6 +575,7 @@ body: Attributes: map[string]any{ "value": "Value of the markdown", }, + Visible: []api.IssueFormFieldVisible{api.IssueFormFieldVisibleForm}, }, }, FileName: "test.yaml", @@ -548,6 +609,7 @@ body: Attributes: map[string]any{ "value": "Value of the markdown", }, + Visible: []api.IssueFormFieldVisible{api.IssueFormFieldVisibleForm}, }, }, FileName: "test.yaml", @@ -622,9 +684,14 @@ body: - type: markdown id: id1 attributes: - value: Value of the markdown - - type: textarea + value: Value of the markdown shown in form + - type: markdown id: id2 + attributes: + value: Value of the markdown shown in created issue + visible: [content] + - type: textarea + id: id3 attributes: label: Label of textarea description: Description of textarea @@ -634,7 +701,7 @@ body: validations: required: true - type: input - id: id3 + id: id4 attributes: label: Label of input description: Description of input @@ -646,7 +713,7 @@ body: is_number: true regex: "[a-zA-Z0-9]+" - type: dropdown - id: id4 + id: id5 attributes: label: Label of dropdown description: Description of dropdown @@ -658,7 +725,7 @@ body: validations: required: true - type: checkboxes - id: id5 + id: id6 attributes: label: Label of checkboxes description: Description of checkboxes @@ -669,20 +736,26 @@ body: required: false - label: Option 3 of checkboxes required: true + visible: [form] + - label: Hidden Option of checkboxes + visible: [content] `, values: map[string][]string{ - "form-field-id2": {"Value of id2"}, "form-field-id3": {"Value of id3"}, - "form-field-id4": {"0,1"}, - "form-field-id5-0": {"on"}, - "form-field-id5-2": {"on"}, + "form-field-id4": {"Value of id4"}, + "form-field-id5": {"0,1"}, + "form-field-id6-0": {"on"}, + "form-field-id6-2": {"on"}, }, }, - want: `### Label of textarea -` + "```bash\nValue of id2\n```" + ` + want: `Value of the markdown shown in created issue -Value of id3 +### Label of textarea + +` + "```bash\nValue of id3\n```" + ` + +Value of id4 ### Label of dropdown @@ -692,7 +765,7 @@ Option 1 of dropdown, Option 2 of dropdown - [x] Option 1 of checkboxes - [ ] Option 2 of checkboxes -- [x] Option 3 of checkboxes +- [ ] Hidden Option of checkboxes `, }, @@ -704,7 +777,7 @@ Option 1 of dropdown, Option 2 of dropdown t.Fatal(err) } if got := RenderToMarkdown(template, tt.args.values); got != tt.want { - t.Errorf("RenderToMarkdown() = %v, want %v", got, tt.want) + assert.EqualValues(t, tt.want, got) } }) } diff --git a/modules/issue/template/unmarshal.go b/modules/issue/template/unmarshal.go index 8cae8d4c4..0fc13d7dd 100644 --- a/modules/issue/template/unmarshal.go +++ b/modules/issue/template/unmarshal.go @@ -128,9 +128,18 @@ func unmarshal(filename string, content []byte) (*api.IssueTemplate, error) { } } for i, v := range it.Fields { + // set default id value if v.ID == "" { v.ID = strconv.Itoa(i) } + // set default visibility + if v.Visible == nil { + v.Visible = []api.IssueFormFieldVisible{api.IssueFormFieldVisibleForm} + // markdown is not submitted by default + if v.Type != api.IssueFormFieldTypeMarkdown { + v.Visible = append(v.Visible, api.IssueFormFieldVisibleContent) + } + } } } diff --git a/modules/markup/html_test.go b/modules/markup/html_test.go index 89ecfc036..132955c01 100644 --- a/modules/markup/html_test.go +++ b/modules/markup/html_test.go @@ -388,7 +388,7 @@ func TestRender_ShortLinks(t *testing.T) { }, }, input) assert.NoError(t, err) - assert.Equal(t, strings.TrimSpace(expected), strings.TrimSpace(buffer)) + assert.Equal(t, strings.TrimSpace(expected), strings.TrimSpace(string(buffer))) buffer, err = markdown.RenderString(&markup.RenderContext{ Ctx: git.DefaultContext, Links: markup.Links{ @@ -398,7 +398,7 @@ func TestRender_ShortLinks(t *testing.T) { IsWiki: true, }, input) assert.NoError(t, err) - assert.Equal(t, strings.TrimSpace(expectedWiki), strings.TrimSpace(buffer)) + assert.Equal(t, strings.TrimSpace(expectedWiki), strings.TrimSpace(string(buffer))) } mediatree := util.URLJoin(markup.TestRepoURL, "media", "master") @@ -501,7 +501,7 @@ func TestRender_RelativeImages(t *testing.T) { Metas: localMetas, }, input) assert.NoError(t, err) - assert.Equal(t, strings.TrimSpace(expected), strings.TrimSpace(buffer)) + assert.Equal(t, strings.TrimSpace(expected), strings.TrimSpace(string(buffer))) buffer, err = markdown.RenderString(&markup.RenderContext{ Ctx: git.DefaultContext, Links: markup.Links{ @@ -511,7 +511,7 @@ func TestRender_RelativeImages(t *testing.T) { IsWiki: true, }, input) assert.NoError(t, err) - assert.Equal(t, strings.TrimSpace(expectedWiki), strings.TrimSpace(buffer)) + assert.Equal(t, strings.TrimSpace(expectedWiki), strings.TrimSpace(string(buffer))) } rawwiki := util.URLJoin(markup.TestRepoURL, "wiki", "raw") diff --git a/modules/markup/markdown/markdown.go b/modules/markup/markdown/markdown.go index 00d01a2f5..7750279ef 100644 --- a/modules/markup/markdown/markdown.go +++ b/modules/markup/markdown/markdown.go @@ -6,6 +6,7 @@ package markdown import ( "fmt" + "html/template" "io" "strings" "sync" @@ -266,12 +267,12 @@ func Render(ctx *markup.RenderContext, input io.Reader, output io.Writer) error } // RenderString renders Markdown string to HTML with all specific handling stuff and return string -func RenderString(ctx *markup.RenderContext, content string) (string, error) { +func RenderString(ctx *markup.RenderContext, content string) (template.HTML, error) { var buf strings.Builder if err := Render(ctx, strings.NewReader(content), &buf); err != nil { return "", err } - return buf.String(), nil + return template.HTML(buf.String()), nil } // RenderRaw renders Markdown to HTML without handling special links. diff --git a/modules/markup/markdown/markdown_test.go b/modules/markup/markdown/markdown_test.go index 1be8c6a27..e7c496a91 100644 --- a/modules/markup/markdown/markdown_test.go +++ b/modules/markup/markdown/markdown_test.go @@ -5,6 +5,7 @@ package markdown_test import ( "context" + "html/template" "os" "strings" "testing" @@ -59,7 +60,7 @@ func TestRender_StandardLinks(t *testing.T) { }, }, input) assert.NoError(t, err) - assert.Equal(t, strings.TrimSpace(expected), strings.TrimSpace(buffer)) + assert.Equal(t, strings.TrimSpace(expected), strings.TrimSpace(string(buffer))) buffer, err = markdown.RenderString(&markup.RenderContext{ Ctx: git.DefaultContext, @@ -69,7 +70,7 @@ func TestRender_StandardLinks(t *testing.T) { IsWiki: true, }, input) assert.NoError(t, err) - assert.Equal(t, strings.TrimSpace(expectedWiki), strings.TrimSpace(buffer)) + assert.Equal(t, strings.TrimSpace(expectedWiki), strings.TrimSpace(string(buffer))) } googleRendered := `

https://google.com/

` @@ -94,7 +95,7 @@ func TestRender_Images(t *testing.T) { }, }, input) assert.NoError(t, err) - assert.Equal(t, strings.TrimSpace(expected), strings.TrimSpace(buffer)) + assert.Equal(t, strings.TrimSpace(expected), strings.TrimSpace(string(buffer))) } url := "../../.images/src/02/train.jpg" @@ -304,7 +305,7 @@ func TestTotal_RenderWiki(t *testing.T) { IsWiki: true, }, sameCases[i]) assert.NoError(t, err) - assert.Equal(t, answers[i], line) + assert.Equal(t, template.HTML(answers[i]), line) } testCases := []string{ @@ -329,7 +330,7 @@ func TestTotal_RenderWiki(t *testing.T) { IsWiki: true, }, testCases[i]) assert.NoError(t, err) - assert.Equal(t, testCases[i+1], line) + assert.Equal(t, template.HTML(testCases[i+1]), line) } } @@ -349,7 +350,7 @@ func TestTotal_RenderString(t *testing.T) { Metas: localMetas, }, sameCases[i]) assert.NoError(t, err) - assert.Equal(t, answers[i], line) + assert.Equal(t, template.HTML(answers[i]), line) } testCases := []string{} @@ -362,7 +363,7 @@ func TestTotal_RenderString(t *testing.T) { }, }, testCases[i]) assert.NoError(t, err) - assert.Equal(t, testCases[i+1], line) + assert.Equal(t, template.HTML(testCases[i+1]), line) } } @@ -429,7 +430,7 @@ func TestRenderEmojiInLinks_Issue12331(t *testing.T) { ` res, err := markdown.RenderString(&markup.RenderContext{Ctx: git.DefaultContext}, testcase) assert.NoError(t, err) - assert.Equal(t, expected, res) + assert.Equal(t, template.HTML(expected), res) } func TestColorPreview(t *testing.T) { @@ -463,7 +464,7 @@ func TestColorPreview(t *testing.T) { for _, test := range positiveTests { res, err := markdown.RenderString(&markup.RenderContext{Ctx: git.DefaultContext}, test.testcase) assert.NoError(t, err, "Unexpected error in testcase: %q", test.testcase) - assert.Equal(t, test.expected, res, "Unexpected result in testcase %q", test.testcase) + assert.Equal(t, template.HTML(test.expected), res, "Unexpected result in testcase %q", test.testcase) } @@ -542,7 +543,7 @@ func TestMathBlock(t *testing.T) { for _, test := range testcases { res, err := markdown.RenderString(&markup.RenderContext{Ctx: git.DefaultContext}, test.testcase) assert.NoError(t, err, "Unexpected error in testcase: %q", test.testcase) - assert.Equal(t, test.expected, res, "Unexpected result in testcase %q", test.testcase) + assert.Equal(t, template.HTML(test.expected), res, "Unexpected result in testcase %q", test.testcase) } } @@ -741,7 +742,7 @@ Citation needed[^0].`, for _, test := range testcases { res, err := markdown.RenderString(&markup.RenderContext{Ctx: git.DefaultContext}, test.testcase) assert.NoError(t, err, "Unexpected error in testcase: %q", test.testcase) - assert.Equal(t, test.expected, res, "Unexpected result in testcase %q", test.testcase) + assert.Equal(t, test.expected, string(res), "Unexpected result in testcase %q", test.testcase) } } @@ -778,12 +779,12 @@ foo: bar for _, test := range testcases { res, err := markdown.RenderString(&markup.RenderContext{Ctx: git.DefaultContext}, test.testcase) assert.NoError(t, err, "Unexpected error in testcase: %q", test.testcase) - assert.Equal(t, test.expected, res, "Unexpected result in testcase %q", test.testcase) + assert.Equal(t, template.HTML(test.expected), res, "Unexpected result in testcase %q", test.testcase) } } func TestRenderLinks(t *testing.T) { - input := ` space @mention-user + input := ` space @mention-user${SPACE}${SPACE} /just/a/path.bin https://example.com/file.bin [local link](file.bin) @@ -804,8 +805,9 @@ com 88fc37a3c0a4dda553bdcfc80c178a58247f42fb mit mail@domain.com @mention-user test #123 - space + space${SPACE}${SPACE} ` + input = strings.ReplaceAll(input, "${SPACE}", " ") // replace ${SPACE} with " ", to avoid some editor's auto-trimming cases := []struct { Links markup.Links IsWiki bool @@ -1168,7 +1170,7 @@ space

for i, c := range cases { result, err := markdown.RenderString(&markup.RenderContext{Ctx: context.Background(), Links: c.Links, IsWiki: c.IsWiki}, input) assert.NoError(t, err, "Unexpected error in testcase: %v", i) - assert.Equal(t, c.Expected, result, "Unexpected result in testcase %v", i) + assert.Equal(t, template.HTML(c.Expected), result, "Unexpected result in testcase %v", i) } } @@ -1187,7 +1189,7 @@ func TestCustomMarkdownURL(t *testing.T) { }, }, input) assert.NoError(t, err) - assert.Equal(t, strings.TrimSpace(expected), strings.TrimSpace(buffer)) + assert.Equal(t, strings.TrimSpace(expected), strings.TrimSpace(string(buffer))) } test("[test](abp:subscribe?location=https://codeberg.org/filters.txt&title=joy)", diff --git a/modules/optional/option_test.go b/modules/optional/option_test.go index 410fd7357..4f5560800 100644 --- a/modules/optional/option_test.go +++ b/modules/optional/option_test.go @@ -27,6 +27,16 @@ func TestOption(t *testing.T) { assert.Equal(t, int(1), some.Value()) assert.Equal(t, int(1), some.ValueOrDefault(2)) + noneBool := optional.None[bool]() + assert.False(t, noneBool.Has()) + assert.False(t, noneBool.Value()) + assert.True(t, noneBool.ValueOrDefault(true)) + + someBool := optional.Some(true) + assert.True(t, someBool.Has()) + assert.True(t, someBool.Value()) + assert.True(t, someBool.ValueOrDefault(false)) + var ptr *int assert.False(t, optional.FromPtr(ptr).Has()) diff --git a/modules/queue/workergroup.go b/modules/queue/workergroup.go index 147a4f335..e3801ef2b 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 b28fd8802..4160622d8 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 e60120162..e09669c54 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 fce893cf5..fd10992e8 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 3f1f52401..498374b2a 100644 --- a/modules/references/references_test.go +++ b/modules/references/references_test.go @@ -432,6 +432,8 @@ func TestRegExp_issueNumericPattern(t *testing.T) { " #12", "#12:", "ref: #12: msg", + "\"#1234\"", + "'#1234'", } falseTestCases := []string{ "# 1234", @@ -462,6 +464,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/repository/init.go b/modules/repository/init.go index b90b234a7..5f500c523 100644 --- a/modules/repository/init.go +++ b/modules/repository/init.go @@ -6,22 +6,18 @@ package repository import ( "context" "fmt" - "os" "path/filepath" "sort" "strings" - "time" issues_model "code.gitea.io/gitea/models/issues" repo_model "code.gitea.io/gitea/models/repo" - user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/label" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/options" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/util" - asymkey_service "code.gitea.io/gitea/services/asymkey" ) type OptionFile struct { @@ -124,70 +120,6 @@ func LoadRepoConfig() error { return nil } -// InitRepoCommit temporarily changes with work directory. -func InitRepoCommit(ctx context.Context, tmpPath string, repo *repo_model.Repository, u *user_model.User, defaultBranch string) (err error) { - commitTimeStr := time.Now().Format(time.RFC3339) - - sig := u.NewGitSig() - // Because this may call hooks we should pass in the environment - env := append(os.Environ(), - "GIT_AUTHOR_NAME="+sig.Name, - "GIT_AUTHOR_EMAIL="+sig.Email, - "GIT_AUTHOR_DATE="+commitTimeStr, - "GIT_COMMITTER_DATE="+commitTimeStr, - ) - committerName := sig.Name - committerEmail := sig.Email - - if stdout, _, err := git.NewCommand(ctx, "add", "--all"). - SetDescription(fmt.Sprintf("initRepoCommit (git add): %s", tmpPath)). - RunStdString(&git.RunOpts{Dir: tmpPath}); err != nil { - log.Error("git add --all failed: Stdout: %s\nError: %v", stdout, err) - return fmt.Errorf("git add --all: %w", err) - } - - cmd := git.NewCommand(ctx, "commit", "--message=Initial commit"). - AddOptionFormat("--author='%s <%s>'", sig.Name, sig.Email) - - sign, keyID, signer, _ := asymkey_service.SignInitialCommit(ctx, tmpPath, u) - if sign { - cmd.AddOptionFormat("-S%s", keyID) - - if repo.GetTrustModel() == repo_model.CommitterTrustModel || repo.GetTrustModel() == repo_model.CollaboratorCommitterTrustModel { - // need to set the committer to the KeyID owner - committerName = signer.Name - committerEmail = signer.Email - } - } else { - cmd.AddArguments("--no-gpg-sign") - } - - env = append(env, - "GIT_COMMITTER_NAME="+committerName, - "GIT_COMMITTER_EMAIL="+committerEmail, - ) - - if stdout, _, err := cmd. - SetDescription(fmt.Sprintf("initRepoCommit (git commit): %s", tmpPath)). - RunStdString(&git.RunOpts{Dir: tmpPath, Env: env}); err != nil { - log.Error("Failed to commit: %v: Stdout: %s\nError: %v", cmd.String(), stdout, err) - return fmt.Errorf("git commit: %w", err) - } - - if len(defaultBranch) == 0 { - defaultBranch = setting.Repository.DefaultBranch - } - - if stdout, _, err := git.NewCommand(ctx, "push", "origin").AddDynamicArguments("HEAD:" + defaultBranch). - SetDescription(fmt.Sprintf("initRepoCommit (git push): %s", tmpPath)). - RunStdString(&git.RunOpts{Dir: tmpPath, Env: InternalPushingEnvironment(u, repo)}); err != nil { - log.Error("Failed to push back to HEAD: Stdout: %s\nError: %v", stdout, err) - return fmt.Errorf("git push: %w", err) - } - - return nil -} - func CheckInitRepository(ctx context.Context, owner, name, objectFormatName string) (err error) { // Somehow the directory could exist. repoPath := repo_model.RepoPath(owner, name) diff --git a/modules/setting/admin.go b/modules/setting/admin.go index 502efd0eb..c292db9c8 100644 --- a/modules/setting/admin.go +++ b/modules/setting/admin.go @@ -21,5 +21,6 @@ func loadAdminFrom(rootCfg ConfigProvider) { } const ( - UserFeatureDeletion = "deletion" + UserFeatureDeletion = "deletion" + UserFeatureManageGPGKeys = "manage_gpg_keys" ) diff --git a/modules/setting/session.go b/modules/setting/session.go index 664c66f86..e9637fdfc 100644 --- a/modules/setting/session.go +++ b/modules/setting/session.go @@ -21,7 +21,7 @@ var SessionConfig = struct { ProviderConfig string // Cookie name to save session ID. Default is "MacaronSession". CookieName string - // Cookie path to store. Default is "/". HINT: there was a bug, the old value doesn't have trailing slash, and could be empty "". + // Cookie path to store. Default is "/". CookiePath string // GC interval time in seconds. Default is 3600. Gclifetime int64 @@ -49,7 +49,10 @@ func loadSessionFrom(rootCfg ConfigProvider) { SessionConfig.ProviderConfig = path.Join(AppWorkPath, SessionConfig.ProviderConfig) } SessionConfig.CookieName = sec.Key("COOKIE_NAME").MustString("i_like_gitea") - SessionConfig.CookiePath = AppSubURL + "/" // there was a bug, old code only set CookePath=AppSubURL, no trailing slash + SessionConfig.CookiePath = AppSubURL + if SessionConfig.CookiePath == "" { + SessionConfig.CookiePath = "/" + } SessionConfig.Secure = sec.Key("COOKIE_SECURE").MustBool(strings.HasPrefix(strings.ToLower(AppURL), "https://")) SessionConfig.Gclifetime = sec.Key("GC_INTERVAL_TIME").MustInt64(86400) SessionConfig.Maxlifetime = sec.Key("SESSION_LIFE_TIME").MustInt64(86400) diff --git a/modules/structs/issue.go b/modules/structs/issue.go index 331dbc1f8..e2b49e94c 100644 --- a/modules/structs/issue.go +++ b/modules/structs/issue.go @@ -6,6 +6,7 @@ package structs import ( "fmt" "path" + "slices" "strings" "time" @@ -143,12 +144,37 @@ const ( // IssueFormField represents a form field // swagger:model type IssueFormField struct { - Type IssueFormFieldType `json:"type" yaml:"type"` - ID string `json:"id" yaml:"id"` - Attributes map[string]any `json:"attributes" yaml:"attributes"` - Validations map[string]any `json:"validations" yaml:"validations"` + Type IssueFormFieldType `json:"type" yaml:"type"` + ID string `json:"id" yaml:"id"` + Attributes map[string]any `json:"attributes" yaml:"attributes"` + Validations map[string]any `json:"validations" yaml:"validations"` + Visible []IssueFormFieldVisible `json:"visible,omitempty"` } +func (iff IssueFormField) VisibleOnForm() bool { + if len(iff.Visible) == 0 { + return true + } + return slices.Contains(iff.Visible, IssueFormFieldVisibleForm) +} + +func (iff IssueFormField) VisibleInContent() bool { + if len(iff.Visible) == 0 { + // we have our markdown exception + return iff.Type != IssueFormFieldTypeMarkdown + } + return slices.Contains(iff.Visible, IssueFormFieldVisibleContent) +} + +// IssueFormFieldVisible defines issue form field visible +// swagger:model +type IssueFormFieldVisible string + +const ( + IssueFormFieldVisibleForm IssueFormFieldVisible = "form" + IssueFormFieldVisibleContent IssueFormFieldVisible = "content" +) + // IssueTemplate represents an issue template for a repository // swagger:model type IssueTemplate struct { diff --git a/modules/templates/helper.go b/modules/templates/helper.go index 708de57c9..9afcb96fc 100644 --- a/modules/templates/helper.go +++ b/modules/templates/helper.go @@ -33,16 +33,16 @@ func NewFuncMap() template.FuncMap { // ----------------------------------------------------------------- // html/template related functions - "dict": dict, // it's lowercase because this name has been widely used. Our other functions should have uppercase names. - "Eval": Eval, - "SafeHTML": SafeHTML, - "HTMLFormat": HTMLFormat, - "HTMLEscape": HTMLEscape, - "QueryEscape": url.QueryEscape, - "JSEscape": JSEscapeSafe, - "Str2html": Str2html, // TODO: rename it to SanitizeHTML - "URLJoin": util.URLJoin, - "DotEscape": DotEscape, + "dict": dict, // it's lowercase because this name has been widely used. Our other functions should have uppercase names. + "Eval": Eval, + "SafeHTML": SafeHTML, + "HTMLFormat": HTMLFormat, + "HTMLEscape": HTMLEscape, + "QueryEscape": url.QueryEscape, + "JSEscape": JSEscapeSafe, + "SanitizeHTML": SanitizeHTML, + "URLJoin": util.URLJoin, + "DotEscape": DotEscape, "PathEscape": url.PathEscape, "PathEscapeSegments": util.PathEscapeSegments, @@ -210,8 +210,8 @@ func SafeHTML(s any) template.HTML { panic(fmt.Sprintf("unexpected type %T", s)) } -// Str2html sanitizes the input by pre-defined markdown rules -func Str2html(s any) template.HTML { +// SanitizeHTML sanitizes the input by pre-defined markdown rules +func SanitizeHTML(s any) template.HTML { switch v := s.(type) { case string: return template.HTML(markup.Sanitize(v)) diff --git a/modules/templates/helper_test.go b/modules/templates/helper_test.go index 8f5d633d4..3365278ac 100644 --- a/modules/templates/helper_test.go +++ b/modules/templates/helper_test.go @@ -61,3 +61,8 @@ func TestJSEscapeSafe(t *testing.T) { func TestHTMLFormat(t *testing.T) { assert.Equal(t, template.HTML("< < 1"), HTMLFormat("%s %s %d", "<", template.HTML("<"), 1)) } + +func TestSanitizeHTML(t *testing.T) { + assert.Equal(t, template.HTML(`link xss
inline
`), SanitizeHTML(`link xss
inline
`)) + assert.Equal(t, template.HTML(`link xss
inline
`), SanitizeHTML(template.HTML(`link xss
inline
`))) +} diff --git a/modules/templates/mailer.go b/modules/templates/mailer.go index 54d857a8f..f1832cba0 100644 --- a/modules/templates/mailer.go +++ b/modules/templates/mailer.go @@ -5,6 +5,7 @@ package templates import ( "context" + "fmt" "html/template" "regexp" "strings" @@ -33,7 +34,7 @@ func mailSubjectTextFuncMap() texttmpl.FuncMap { } } -func buildSubjectBodyTemplate(stpl *texttmpl.Template, btpl *template.Template, name string, content []byte) { +func buildSubjectBodyTemplate(stpl *texttmpl.Template, btpl *template.Template, name string, content []byte) error { // Split template into subject and body var subjectContent []byte bodyContent := content @@ -42,14 +43,13 @@ func buildSubjectBodyTemplate(stpl *texttmpl.Template, btpl *template.Template, subjectContent = content[0:loc[0]] bodyContent = content[loc[1]:] } - if _, err := stpl.New(name). - Parse(string(subjectContent)); err != nil { - log.Warn("Failed to parse template [%s/subject]: %v", name, err) + if _, err := stpl.New(name).Parse(string(subjectContent)); err != nil { + return fmt.Errorf("failed to parse template [%s/subject]: %w", name, err) } - if _, err := btpl.New(name). - Parse(string(bodyContent)); err != nil { - log.Warn("Failed to parse template [%s/body]: %v", name, err) + if _, err := btpl.New(name).Parse(string(bodyContent)); err != nil { + return fmt.Errorf("failed to parse template [%s/body]: %w", name, err) } + return nil } // Mailer provides the templates required for sending notification mails. @@ -81,7 +81,13 @@ func Mailer(ctx context.Context) (*texttmpl.Template, *template.Template) { if firstRun { log.Trace("Adding mail template %s: %s by %s", tmplName, assetPath, layerName) } - buildSubjectBodyTemplate(subjectTemplates, bodyTemplates, tmplName, content) + if err = buildSubjectBodyTemplate(subjectTemplates, bodyTemplates, tmplName, content); err != nil { + if firstRun { + log.Fatal("Failed to parse mail template, err: %v", err) + } else { + log.Error("Failed to parse mail template, err: %v", err) + } + } } } diff --git a/modules/templates/util_render.go b/modules/templates/util_render.go index 1d9635410..cdff31698 100644 --- a/modules/templates/util_render.go +++ b/modules/templates/util_render.go @@ -208,7 +208,7 @@ func RenderMarkdownToHtml(ctx context.Context, input string) template.HTML { //n if err != nil { log.Error("RenderString: %v", err) } - return template.HTML(output) + return output } func RenderLabels(ctx context.Context, labels []*issues_model.Label, repoLink string) template.HTML { diff --git a/modules/templates/util_string.go b/modules/templates/util_string.go index 3f51c122b..f23b74786 100644 --- a/modules/templates/util_string.go +++ b/modules/templates/util_string.go @@ -4,6 +4,7 @@ package templates import ( + "fmt" "html/template" "strings" @@ -28,6 +29,19 @@ func (su *StringUtils) HasPrefix(s any, prefix string) bool { return false } +func (su *StringUtils) ToString(v any) string { + switch v := v.(type) { + case string: + return v + case template.HTML: + return string(v) + case fmt.Stringer: + return v.String() + default: + return fmt.Sprint(v) + } +} + func (su *StringUtils) Contains(s, substr string) bool { return strings.Contains(s, substr) } diff --git a/modules/translation/mock.go b/modules/translation/mock.go index 1f0559f38..18fbc1044 100644 --- a/modules/translation/mock.go +++ b/modules/translation/mock.go @@ -9,7 +9,9 @@ import ( ) // MockLocale provides a mocked locale without any translations -type MockLocale struct{} +type MockLocale struct { + Lang, LangName string // these fields are used directly in templates: ctx.Locale.Lang +} var _ Locale = (*MockLocale)(nil) diff --git a/modules/translation/translation.go b/modules/translation/translation.go index b7c18f610..36ae58a9f 100644 --- a/modules/translation/translation.go +++ b/modules/translation/translation.go @@ -144,7 +144,7 @@ func Match(tags ...language.Tag) language.Tag { // locale represents the information of localization. type locale struct { i18n.Locale - Lang, LangName string // these fields are used directly in templates: .i18n.Lang + Lang, LangName string // these fields are used directly in templates: ctx.Locale.Lang msgPrinter *message.Printer } diff --git a/modules/util/util.go b/modules/util/util.go index 28b549f40..5c7515819 100644 --- a/modules/util/util.go +++ b/modules/util/util.go @@ -17,64 +17,13 @@ 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() { +// 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) + if e != nil { 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 OptionalBool of a string using strconv.ParseBool -func OptionalBoolParse(s string) OptionalBool { - b, e := strconv.ParseBool(s) - if e != nil { - return OptionalBoolNone - } - return OptionalBoolOf(b) + return optional.Some(v) } // IsEmptyString checks if the provided string is empty diff --git a/modules/util/util_test.go b/modules/util/util_test.go index c5830ce01..819e12ee9 100644 --- a/modules/util/util_test.go +++ b/modules/util/util_test.go @@ -8,6 +8,8 @@ import ( "strings" "testing" + "code.gitea.io/gitea/modules/optional" + "github.com/stretchr/testify/assert" ) @@ -173,17 +175,17 @@ func Test_RandomBytes(t *testing.T) { assert.NotEqual(t, bytes3, bytes4) } -func Test_OptionalBool(t *testing.T) { - assert.Equal(t, OptionalBoolNone, OptionalBoolParse("")) - assert.Equal(t, OptionalBoolNone, OptionalBoolParse("x")) +func TestOptionalBoolParse(t *testing.T) { + assert.Equal(t, optional.None[bool](), OptionalBoolParse("")) + assert.Equal(t, optional.None[bool](), OptionalBoolParse("x")) - assert.Equal(t, OptionalBoolFalse, OptionalBoolParse("0")) - assert.Equal(t, OptionalBoolFalse, OptionalBoolParse("f")) - assert.Equal(t, OptionalBoolFalse, OptionalBoolParse("False")) + assert.Equal(t, optional.Some(false), OptionalBoolParse("0")) + assert.Equal(t, optional.Some(false), OptionalBoolParse("f")) + assert.Equal(t, optional.Some(false), OptionalBoolParse("False")) - assert.Equal(t, OptionalBoolTrue, OptionalBoolParse("1")) - assert.Equal(t, OptionalBoolTrue, OptionalBoolParse("t")) - assert.Equal(t, OptionalBoolTrue, OptionalBoolParse("True")) + assert.Equal(t, optional.Some(true), OptionalBoolParse("1")) + assert.Equal(t, optional.Some(true), OptionalBoolParse("t")) + assert.Equal(t, optional.Some(true), OptionalBoolParse("True")) } // Test case for any function which accepts and returns a single string. diff --git a/options/license/MIT-Khronos-old b/options/license/MIT-Khronos-old new file mode 100644 index 000000000..430863bc9 --- /dev/null +++ b/options/license/MIT-Khronos-old @@ -0,0 +1,23 @@ +Copyright (c) 2014-2020 The Khronos Group Inc. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and/or associated documentation files (the "Materials"), +to deal in the Materials without restriction, including without limitation +the rights to use, copy, modify, merge, publish, distribute, sublicense, +and/or sell copies of the Materials, and to permit persons to whom the +Materials are furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Materials. + +MODIFICATIONS TO THIS FILE MAY MEAN IT NO LONGER ACCURATELY REFLECTS KHRONOS +STANDARDS. THE UNMODIFIED, NORMATIVE VERSIONS OF KHRONOS SPECIFICATIONS AND +HEADER INFORMATION ARE LOCATED AT https://www.khronos.org/registry/ + +THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM,OUT OF OR IN CONNECTION WITH THE MATERIALS OR THE USE OR OTHER DEALINGS +IN THE MATERIALS. diff --git a/options/locale/locale_cs-CZ.ini b/options/locale/locale_cs-CZ.ini index be798000f..409b014fa 100644 --- a/options/locale/locale_cs-CZ.ini +++ b/options/locale/locale_cs-CZ.ini @@ -124,6 +124,7 @@ pin=Připnout unpin=Odepnout artifacts=Artefakty +confirm_delete_artifact=Jste si jisti, že chcete odstranit artefakt „%s“? archived=Archivováno @@ -434,7 +435,7 @@ password_pwned_err=Nelze dokončit požadavek na HaveIBeenPwned change_unconfirmed_email = Pokud jste při registraci zadali nesprávnou e-mailovou adresu, můžete ji změnit níže. Potvrzovací e-mail bude místo toho odeslán na novou adresu. change_unconfirmed_email_error = Nepodařilo se změnit e-mailovou adresu: %v change_unconfirmed_email_summary = Změna e-mailové adresy, na kterou bude odeslán aktivační e-mail. -last_admin = Nemůžete odebrat posledního administrátora. Vždy musí existovat alespoň jeden administrátor. +last_admin=Nelze odstranit posledního správce. Musí existovat alespoň jeden správce. [mail] view_it_on=Zobrazit na %s @@ -605,6 +606,7 @@ target_branch_not_exist=Cílová větev neexistuje. admin_cannot_delete_self = Nemůžete odstranit sami sebe, když jste administrátorem. Nejprve prosím odeberte svá práva administrátora. username_error_no_dots = ` může obsahovat pouze alfanumerické znaky („0-9“, „a-z“, „A-Z“), pomlčky („-“) a podtržítka („_“). Nemůže začínat nebo končit nealfanumerickými znaky. Jsou také zakázány po sobě jdoucí nealfanumerické znaky.` +admin_cannot_delete_self=Nemůžete se smazat, dokud jste správce. Nejdříve prosím odeberte svá administrátorská oprávnění. [user] change_avatar=Změnit váš avatar… @@ -999,6 +1001,8 @@ issue_labels_helper=Vyberte sadu štítků úkolů. license=Licence license_helper=Vyberte licenční soubor. license_helper_desc=Licence řídí, co ostatní mohou a nemohou dělat s vaším kódem. Nejste si jisti, která je pro váš projekt správná? Podívejte se na Zvolte licenci +object_format=Formát objektu +object_format_helper=Objektový formát repozitáře. Nelze později změnit. SHA1 je nejvíce kompatibilní. readme=README readme_helper=Vyberte šablonu souboru README. readme_helper_desc=Toto je místo, kde můžete napsat úplný popis vašeho projektu. @@ -1065,6 +1069,7 @@ desc.public=Veřejný desc.template=Šablona desc.internal=Interní desc.archived=Archivováno +desc.sha256=SHA256 template.items=Položky šablony template.git_content=Obsah gitu (výchozí větev) @@ -1215,6 +1220,8 @@ audio_not_supported_in_browser=Váš prohlížeč nepodporuje značku HTML5 „a stored_lfs=Uloženo pomocí Git LFS symbolic_link=Symbolický odkaz executable_file=Spustitelný soubor +vendored=Vendorováno +generated=Generováno commit_graph=Graf commitů commit_graph.select=Vybrat větve commit_graph.hide_pr_refs=Skrýt požadavky na natažení @@ -1550,7 +1557,11 @@ issues.label_title=Název štítku issues.label_description=Popis štítku issues.label_color=Barva štítku issues.label_exclusive=Exkluzivní +issues.label_archive=Archivovat štítek issues.label_archived_filter=Zobrazit archivované popisky +issues.label_archive_tooltip=Archivované štítky jsou ve výchozím nastavení vyloučeny z návrhů při hledání podle popisku. +issues.label_exclusive_desc=Pojmenujte štítek rozsah/položka, aby se stal vzájemně exkluzivním s jinými štítky rozsah/. +issues.label_exclusive_warning=Jakékoliv protichůdné rozsahy štítků budou odstraněny při úpravě štítků u úkolů nebo u požadavku na natažení. issues.label_count=%d štítků issues.label_open_issues=%d otevřených úkolů issues.label_edit=Upravit @@ -1651,6 +1662,7 @@ issues.dependency.issue_closing_blockedby=Uzavření tohoto úkolu je blokováno issues.dependency.issue_close_blocks=Tento úkol blokuje uzavření následujících úkolů issues.dependency.pr_close_blocks=Tento požadavek na natažení blokuje uzavření následujících úkolů issues.dependency.issue_close_blocked=Musíte zavřít všechny úkoly, které blokují tento úkol, aby jej bylo možné zavřít. +issues.dependency.issue_batch_close_blocked=Nelze uzavřít úkoly, které jste vybrali, protože úkol #%d má stále otevřené závislosti issues.dependency.pr_close_blocked=Musíte zavřít všechny úkoly, které blokují tento požadavek na natažení, aby jej bylo možné sloučit. issues.dependency.blocks_short=Blokuje issues.dependency.blocked_by_short=Závisí na @@ -1732,6 +1744,7 @@ pulls.select_commit_hold_shift_for_range=Vyberte commit. Podržte klávesu shift pulls.review_only_possible_for_full_diff=Posouzení je možné pouze při zobrazení plného rozlišení pulls.filter_changes_by_commit=Filtrovat podle commitu pulls.nothing_to_compare=Tyto větve jsou stejné. Není potřeba vytvářet požadavek na natažení. +pulls.nothing_to_compare_have_tag=Vybraná větev/značka je stejná. pulls.nothing_to_compare_and_allow_empty_pr=Tyto větve jsou stejné. Tento požadavek na natažení bude prázdný. pulls.has_pull_request=`Požadavek na natažení mezi těmito větvemi již existuje: %[2]s#%[3]d` pulls.create=Vytvořit požadavek na natažení @@ -1854,6 +1867,7 @@ milestones.update_ago=Aktualizováno %s milestones.no_due_date=Bez lhůty dokončení milestones.open=Otevřít milestones.close=Zavřít +milestones.new_subheader=Milníky vám pomohou organizovat úkoly a sledovat jejich pokrok. milestones.completeness=%d%% Dokončeno milestones.create=Vytvořit milník milestones.title=Název @@ -1987,6 +2001,7 @@ activity.git_stats_and_deletions=a activity.git_stats_deletion_1=%d odebrání activity.git_stats_deletion_n=%d odebrání +contributors.contribution_type.filter_label=Typ příspěvku: contributors.contribution_type.commits=Commity search=Vyhledat @@ -2374,6 +2389,7 @@ settings.matrix.room_id=ID místnosti settings.matrix.message_type=Typ zprávy settings.archive.button=Archivovat repozitář settings.archive.header=Archivovat tento repozitář +settings.archive.text=Archivace repozitáře způsobí, že bude zcela určen pouze pro čtení. Bude skryt z ovládacího panelu. Nikdo (ani vy!) nebude moci vytvářet nové revize ani otevírat nové úkoly nebo žádosti o natažení. settings.archive.success=Repozitář byl úspěšně archivován. settings.archive.error=Nastala chyba při archivování repozitáře. Prohlédněte si záznam pro více detailů. settings.archive.error_ismirror=Nemůžete archivovat zrcadlený repozitář. @@ -2835,6 +2851,7 @@ dashboard.delete_repo_archives.started=Spuštěna úloha smazání všech archiv dashboard.delete_missing_repos=Smazat všechny repozitáře, které nemají Git soubory dashboard.delete_missing_repos.started=Spuštěna úloha mazání všech repozitářů, které nemají Git soubory. dashboard.delete_generated_repository_avatars=Odstranit vygenerované avatary repozitářů +dashboard.sync_repo_tags=Synchronizovat značky z git dat do databáze dashboard.update_mirrors=Aktualizovat zrcadla dashboard.repo_health_check=Kontrola stavu všech repozitářů dashboard.check_repo_stats=Zkontrolovat všechny statistiky repositáře @@ -2882,11 +2899,14 @@ dashboard.delete_old_actions=Odstranit všechny staré akce z databáze dashboard.delete_old_actions.started=Začalo odstraňování všech starých akcí z databáze. dashboard.update_checker=Kontrola aktualizací dashboard.delete_old_system_notices=Odstranit všechna stará systémová upozornění z databáze +dashboard.gc_lfs=Úklid LFS meta objektů dashboard.stop_zombie_tasks=Zastavit zombie úlohy dashboard.stop_endless_tasks=Zastavit nekonečné úlohy dashboard.cancel_abandoned_jobs=Zrušit opuštěné úlohy dashboard.start_schedule_tasks=Spustit naplánované úlohy dashboard.sync_branch.started=Synchronizace větví byla spuštěna +dashboard.sync_tag.started=Synchronizace značek spuštěna +dashboard.rebuild_issue_indexer=Znovu sestavit index úkolů users.user_manage_panel=Správa uživatelských účtů users.new_account=Vytvořit uživatelský účet @@ -3326,6 +3346,12 @@ self_check.database_fix_mssql = Uživatelé MSSQL mohou tento problém vyřešit auths.oauth2_map_group_to_team = Zmapovat zabrané skupiny u týmů organizací (volitelné - vyžaduje název zabrání výše) monitor.queue.settings.desc = Pooly dynamicky rostou podle blokování fronty jejich workerů. +self_check.no_problem_found=Zatím nebyl nalezen žádný problém. +self_check.database_collation_mismatch=Očekávejte, že databáze použije collation: %s +self_check.database_collation_case_insensitive=Databáze používá collation %s, což je collation nerozlišující velká a malá písmena. Ačkoli s ní Gitea může pracovat, mohou se vyskytnout vzácné případy, kdy nebude fungovat podle očekávání. +self_check.database_inconsistent_collation_columns=Databáze používá collation %s, ale tyto sloupce používají chybné collation. To může způsobit neočekávané problémy. +self_check.database_fix_mysql=Pro uživatele MySQL/MariaDB můžete použít příkaz "gitea doctor convert", který opraví problémy s collation, nebo můžete také problém vyřešit příkazem "ALTER ... COLLATE ..." SQL ručně. +self_check.database_fix_mssql=Uživatelé MSSQL mohou problém vyřešit pouze pomocí příkazu "ALTER ... COLLATE ..." SQL ručně. [action] create_repo=vytvořil/a repozitář %s @@ -3513,6 +3539,7 @@ rpm.distros.suse=na distribuce založené na SUSE rpm.install=Pro instalaci balíčku spusťte následující příkaz: rpm.repository=Informace o repozitáři rpm.repository.architectures=Architektury +rpm.repository.multiple_groups=Tento balíček je k dispozici ve více skupinách. rubygems.install=Pro instalaci balíčku pomocí gem spusťte následující příkaz: rubygems.install2=nebo ho přidejte do Gemfie: rubygems.dependencies.runtime=Běhové závislosti @@ -3642,6 +3669,8 @@ runs.actors_no_select=Všichni aktéři runs.status_no_select=Všechny stavy runs.no_results=Nebyly nalezeny žádné výsledky. runs.no_workflows=Zatím neexistují žádné pracovní postupy. +runs.no_workflows.quick_start=Nevíte jak začít s Gitea Actions? Podívejte se na průvodce rychlým startem. +runs.no_workflows.documentation=Další informace o Gitea Actions naleznete v dokumentaci. runs.no_runs=Pracovní postup zatím nebyl spuštěn. runs.empty_commit_message=(prázdná zpráva commitu) @@ -3659,6 +3688,7 @@ variables.none=Zatím nejsou žádné proměnné. variables.deletion=Odstranit proměnnou variables.deletion.description=Odstranění proměnné je trvalé a nelze jej vrátit zpět. Pokračovat? variables.description=Proměnné budou předány určitým akcím a nelze je přečíst jinak. +variables.id_not_exist=Proměnná s ID %d neexistuje. variables.edit=Upravit proměnnou variables.deletion.failed=Nepodařilo se odstranit proměnnou. variables.deletion.success=Proměnná byla odstraněna. diff --git a/options/locale/locale_en-US.ini b/options/locale/locale_en-US.ini index f01542ed2..07ad19aa7 100644 --- a/options/locale/locale_en-US.ini +++ b/options/locale/locale_en-US.ini @@ -143,6 +143,19 @@ confirm_delete_selected = Confirm to delete all selected items? name = Name value = Value +filter = Filter +filter.clear = Clear Filter +filter.is_archived = Archived +filter.not_archived = Not Archived +filter.is_fork = Forked +filter.not_fork = Not Forked +filter.is_mirror = Mirrored +filter.not_mirror = Not Mirrored +filter.is_template = Template +filter.not_template = Not Template +filter.public = Public +filter.private = Private + [aria] navbar = Navigation Bar footer = Footer @@ -1834,9 +1847,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/options/locale/locale_fr-FR.ini b/options/locale/locale_fr-FR.ini index 98c524ac8..4cfde206a 100644 --- a/options/locale/locale_fr-FR.ini +++ b/options/locale/locale_fr-FR.ini @@ -124,6 +124,7 @@ pin=Épingler unpin=Désépingler artifacts=Artefacts +confirm_delete_artifact=Êtes-vous sûr de vouloir supprimer l‘artefact « %s » ? archived=Archivé @@ -366,6 +367,7 @@ disable_register_prompt=Les inscriptions sont désactivées. Veuillez contacter disable_register_mail=La confirmation par courriel à l’inscription est désactivée. manual_activation_only=Contactez l'administrateur de votre site pour terminer l'activation. remember_me=Mémoriser cet appareil +remember_me.compromised=Le jeton de connexion n’est plus valide, ce qui peut indiquer un compte compromis. Veuillez inspecter les activités inhabituelles de votre compte. forgot_password_title=Mot de passe oublié forgot_password=Mot de passe oublié ? sign_up_now=Pas de compte ? Inscrivez-vous maintenant. @@ -602,6 +604,7 @@ target_branch_not_exist=La branche cible n'existe pas. username_error_no_dots = ` peut uniquement contenir des caractères alphanumériques ('0-9','a-z','A-Z'), tiret ('-') et souligné ('_'). Ne peut commencer ou terminer avec un caractère non-alphanumérique, et l'utilisation de caractères non-alphanumériques consécutifs n'est pas permise.` admin_cannot_delete_self = Vous ne pouvez supprimer votre compte lorsque vous disposez de droits d'administration. Veuillez d'abord renoncer à vos droits d'administration. +admin_cannot_delete_self=Vous ne pouvez pas vous supprimer vous-même lorsque vous êtes admin. Veuillez d’abord supprimer vos privilèges d’administrateur. [user] change_avatar=Changer votre avatar… @@ -817,7 +820,7 @@ valid_until_date=Valable jusqu'au %s valid_forever=Valide pour toujours last_used=Dernière utilisation le no_activity=Aucune activité récente -can_read_info=Lue(s) +can_read_info=Lecture can_write_info=Écriture key_state_desc=Cette clé a été utilisée au cours des 7 derniers jours token_state_desc=Ce jeton a été utilisé au cours des 7 derniers jours @@ -850,7 +853,7 @@ permissions_public_only=Publique uniquement permissions_access_all=Tout (public, privé et limité) select_permissions=Sélectionner les autorisations permission_no_access=Aucun accès -permission_read=Lue(s) +permission_read=Lecture permission_write=Lecture et écriture access_token_desc=Les autorisations des jetons sélectionnées se limitent aux routes API correspondantes. Lisez la documentation pour plus d’informations. at_least_one_permission=Vous devez sélectionner au moins une permission pour créer un jeton @@ -1013,6 +1016,7 @@ mirror_prune=Purger mirror_prune_desc=Supprimer les références externes obsolètes mirror_interval=Intervalle de synchronisation (les unités de temps valides sont 'h', 'm' et 's'). 0 pour désactiver la synchronisation automatique. (Intervalle minimum : %s) mirror_interval_invalid=L'intervalle de synchronisation est invalide. +mirror_sync=synchronisé mirror_sync_on_commit=Synchroniser quand les révisions sont soumis mirror_address=Cloner depuis une URL mirror_address_desc=Insérez tous les identifiants requis dans la section Autorisation. @@ -1063,6 +1067,7 @@ desc.public=Publique desc.template=Modèle desc.internal=Interne desc.archived=Archivé +desc.sha256=SHA256 template.items=Élément du modèle template.git_content=Contenu Git (branche par défaut) @@ -1213,6 +1218,8 @@ audio_not_supported_in_browser=Votre navigateur ne supporte pas la balise « au stored_lfs=Stocké avec Git LFS symbolic_link=Lien symbolique executable_file=Fichiers exécutables +vendored=Externe +generated=Générée commit_graph=Graphe des révisions commit_graph.select=Sélectionner les branches commit_graph.hide_pr_refs=Masquer les demandes d'ajout @@ -1794,6 +1801,7 @@ pulls.merge_pull_request=Créer une révision de fusion pulls.rebase_merge_pull_request=Rebaser puis avancer rapidement pulls.rebase_merge_commit_pull_request=Rebaser puis créer une révision de fusion pulls.squash_merge_pull_request=Créer une révision de concaténation +pulls.fast_forward_only_merge_pull_request=Avance rapide uniquement pulls.merge_manually=Fusionner manuellement pulls.merge_commit_id=L'ID de la révision de fusion pulls.require_signed_wont_sign=La branche nécessite des révisions signées mais cette fusion ne sera pas signée @@ -1930,6 +1938,7 @@ wiki.page_name_desc=Entrez un nom pour cette page Wiki. Certains noms spéciaux wiki.original_git_entry_tooltip=Voir le fichier Git original au lieu d'utiliser un lien convivial. activity=Activité +activity.navbar.contributors=Contributeurs activity.period.filter_label=Période : activity.period.daily=1 jour activity.period.halfweekly=3 jours @@ -1995,7 +2004,10 @@ activity.git_stats_and_deletions=et activity.git_stats_deletion_1=%d suppression activity.git_stats_deletion_n=%d suppressions +contributors.contribution_type.filter_label=Type de contribution : contributors.contribution_type.commits=Révisions +contributors.contribution_type.additions=Ajouts +contributors.contribution_type.deletions=Suppressions search=Chercher search.search_repo=Rechercher dans le dépôt @@ -2344,6 +2356,8 @@ settings.protect_approvals_whitelist_users=Évaluateurs autorisés : settings.protect_approvals_whitelist_teams=Équipes d’évaluateurs autorisés : settings.dismiss_stale_approvals=Révoquer automatiquement les approbations périmées settings.dismiss_stale_approvals_desc=Lorsque des nouvelles révisions changent le contenu de la demande d’ajout, les approbations existantes sont révoquées. +settings.ignore_stale_approvals=Ignorer les approbations obsolètes +settings.ignore_stale_approvals_desc=Ignorer les approbations d’anciennes révisions (évaluations obsolètes) du décompte des approbations de la demande d’ajout. Non pertinent quand les évaluations obsolètes sont déjà révoquées. settings.require_signed_commits=Exiger des révisions signées settings.require_signed_commits_desc=Rejeter les soumissions sur cette branche lorsqu'ils ne sont pas signés ou vérifiables. settings.protect_branch_name_pattern=Motif de nom de branche protégé @@ -2399,6 +2413,7 @@ settings.archive.error=Une erreur s'est produite lors de l'archivage du dépôt. settings.archive.error_ismirror=Vous ne pouvez pas archiver un dépôt en miroir. settings.archive.branchsettings_unavailable=Le paramétrage des branches n'est pas disponible quand le dépôt est archivé. settings.archive.tagsettings_unavailable=Le paramétrage des étiquettes n'est pas disponible si le dépôt est archivé. +settings.archive.mirrors_unavailable=Les miroirs ne sont pas disponibles lorsque le dépôt est archivé. settings.unarchive.button=Réhabiliter settings.unarchive.header=Réhabiliter ce dépôt settings.unarchive.text=Réhabiliter un dépôt dégèle les actions de révisions et de soumissions, la gestion des tickets et des demandes d'ajouts. @@ -2652,6 +2667,11 @@ activity.navbar.code_frequency = Fréquence de code activity.navbar.recent_commits = Commits récents [graphs] +component_loading=Chargement de %s… +component_loading_failed=Impossible de charger %s. +component_loading_info=Ça prend son temps… +component_failed_to_load=Une erreur inattendue s’est produite. +contributors.what=contributions [org] org_name_holder=Nom de l'organisation @@ -2780,6 +2800,7 @@ follow_blocked_user = Vous ne pouvez pas suivre cette organisation car elle vous [admin] dashboard=Tableau de bord +self_check=Autodiagnostique identity_access=Identité et accès users=Comptes utilisateurs organizations=Organisations @@ -2825,6 +2846,7 @@ dashboard.delete_missing_repos=Supprimer tous les dépôts dont les fichiers Git dashboard.delete_missing_repos.started=Tâche de suppression de tous les dépôts sans fichiers Git démarrée. dashboard.delete_generated_repository_avatars=Supprimer les avatars de dépôt générés dashboard.sync_repo_branches=Synchroniser les branches manquantes depuis Git vers la base de donnée. +dashboard.sync_repo_tags=Synchroniser les étiquettes git depuis les dépôts vers la base de données dashboard.update_mirrors=Actualiser les miroirs dashboard.repo_health_check=Vérifier l'état de santé de tous les dépôts dashboard.check_repo_stats=Voir les statistiques de tous les dépôts @@ -2879,6 +2901,7 @@ dashboard.stop_endless_tasks=Arrêter les tâches sans fin dashboard.cancel_abandoned_jobs=Annuler les jobs abandonnés dashboard.start_schedule_tasks=Démarrer les tâches planifiées dashboard.sync_branch.started=Début de la synchronisation des branches +dashboard.sync_tag.started=Synchronisation des étiquettes dashboard.rebuild_issue_indexer=Reconstruire l’indexeur des tickets users.user_manage_panel=Gestion du compte utilisateur @@ -3314,6 +3337,12 @@ self_check.database_inconsistent_collation_columns = La base de donnée utilise self_check.database_fix_mysql = Les utilisateurs de MySQL/MariaDB peuvent utiliser la commande "forgejo doctor convert" pour corriger les problèmes de collation, ou bien manuellement avec la commande SQL "ALTER ... COLLATE ...". self_check.database_fix_mssql = Les utilisateurs de MSSQL sont pour l'instant contraint d'utiliser la commande SQL "ALTER ... COLLATE ..." pour corriger ce problème. +self_check.no_problem_found=Aucun problème trouvé pour l’instant. +self_check.database_collation_mismatch=Exige que la base de données utilise la collation %s. +self_check.database_collation_case_insensitive=La base de données utilise la collation %s, insensible à la casse. Bien que Gitea soit compatible, il peut y avoir quelques rares cas qui ne fonctionnent pas comme prévu. +self_check.database_inconsistent_collation_columns=La base de données utilise la collation %s, mais ces colonnes utilisent des collations différentes. Cela peut causer des problèmes imprévus. +self_check.database_fix_mysql=Pour les utilisateurs de MySQL ou MariaDB, vous pouvez utiliser la commande « gitea doctor convert » dans un terminal ou exécuter une requête du type « ALTER … COLLATE ... » pour résoudre les problèmes de collation. +self_check.database_fix_mssql=Pour les utilisateurs de MSSQL, vous ne pouvez résoudre le problème qu’en exécutant une requête SQL du type « ALTER … COLLATE … ». [action] create_repo=a créé le dépôt %s @@ -3501,6 +3530,7 @@ rpm.distros.suse=sur les distributions basées sur SUSE rpm.install=Pour installer le paquet, exécutez la commande suivante : rpm.repository=Informations sur le Dépôt rpm.repository.architectures=Architectures +rpm.repository.multiple_groups=Ce paquet est disponible en plusieurs groupes. rubygems.install=Pour installer le paquet en utilisant gem, exécutez la commande suivante : rubygems.install2=ou ajoutez-le au Gemfile : rubygems.dependencies.runtime=Dépendances d'exécution @@ -3636,6 +3666,8 @@ runs.actors_no_select=Tous les acteurs runs.status_no_select=Touts les statuts runs.no_results=Aucun résultat correspondant. runs.no_workflows=Il n'y a pas encore de workflows. +runs.no_workflows.quick_start=Vous découvrez les Actions Gitea ? Consultez le didacticiel. +runs.no_workflows.documentation=Pour plus d’informations sur les actions Gitea, voir la documentation. runs.no_runs=Le flux de travail n'a pas encore d'exécution. runs.empty_commit_message=(message de révision vide) @@ -3654,6 +3686,7 @@ variables.none=Il n'y a pas encore de variables. variables.deletion=Retirer la variable variables.deletion.description=La suppression d’une variable est permanente et ne peut être défaite. Continuer ? variables.description=Les variables sont passées aux actions et ne peuvent être lues autrement. +variables.id_not_exist=La variable avec l’ID %d n’existe pas. variables.edit=Modifier la variable variables.deletion.failed=Impossible de retirer la variable. variables.deletion.success=La variable a bien été retirée. diff --git a/options/locale/locale_ja-JP.ini b/options/locale/locale_ja-JP.ini index 210b4e230..fcccac21c 100644 --- a/options/locale/locale_ja-JP.ini +++ b/options/locale/locale_ja-JP.ini @@ -124,6 +124,7 @@ pin=ピン留め unpin=ピン留め解除 artifacts=成果物 +confirm_delete_artifact=アーティファクト %s を削除してよろしいですか? archived=アーカイブ @@ -429,7 +430,7 @@ password_pwned_err=HaveIBeenPwnedへのリクエストを完了できません change_unconfirmed_email = 登録時に間違ったメール アドレスを入力した場合は、以下で変更できます。代わりに確認メールが新しいアドレスに送信されます。 change_unconfirmed_email_error = メール アドレスを変更できません: %v change_unconfirmed_email_summary = アクティベーションメールの送信先メールアドレスを変更します。 -last_admin = 最後の管理者を削除することはできません。少なくとも 1 人の管理者が必要です。 +last_admin=最後の管理者は削除できません。少なくとも一人の管理者が必要です。 [mail] view_it_on=%s で見る @@ -600,6 +601,7 @@ target_branch_not_exist=ターゲットのブランチが存在していませ admin_cannot_delete_self = 管理者である場合、自分自身を削除することはできません。最初に管理者権限を削除してください。 username_error_no_dots = `英数字 (「0-9」、「a-z」、「A-Z」)、ダッシュ (「-」)、およびアンダースコア (「_」) のみを含めることができます。英数字以外の文字で開始または終了することはできず、連続した英数字以外の文字も禁止されています。` +admin_cannot_delete_self=あなたが管理者である場合、自分自身を削除することはできません。最初に管理者権限を削除してください。 [user] change_avatar=アバターを変更… @@ -993,6 +995,8 @@ issue_labels_helper=イシューのラベルセットを選択 license=ライセンス license_helper=ライセンス ファイルを選択してください。 license_helper_desc=ライセンスにより、他人があなたのコードに対して何ができて何ができないのかを規定します。 どれがプロジェクトにふさわしいか迷っていますか? ライセンス選択サイト も確認してみてください。 +object_format=オブジェクトのフォーマット +object_format_helper=リポジトリのオブジェクトフォーマット。後で変更することはできません。SHA1 は最も互換性があります。 readme=README readme_helper=READMEファイル テンプレートを選択してください。 readme_helper_desc=プロジェクトについての説明をひととおり書く場所です。 @@ -1060,6 +1064,7 @@ desc.public=公開 desc.template=テンプレート desc.internal=組織内 desc.archived=アーカイブ +desc.sha256=SHA256 template.items=テンプレート項目 template.git_content=Gitコンテンツ (デフォルトブランチ) diff --git a/options/locale/locale_lv-LV.ini b/options/locale/locale_lv-LV.ini index 15d24558d..718f3dc9a 100644 --- a/options/locale/locale_lv-LV.ini +++ b/options/locale/locale_lv-LV.ini @@ -1036,6 +1036,7 @@ desc.public=Publisks desc.template=Sagatave desc.internal=Iekšējs desc.archived=Arhivēts +desc.sha256=SHA256 template.items=Sagataves ieraksti template.git_content=Git saturs (noklusētais atzars) @@ -2571,6 +2572,10 @@ error.csv.unexpected=Nevar attēlot šo failu, jo tas satur neparedzētu simbolu error.csv.invalid_field_count=Nevar attēlot šo failu, jo tas satur nepareizu skaitu ar laukiem %d. līnijā. [graphs] +component_loading=Ielādē %s... +component_loading_failed=Nevarēja ielādēt %s +component_loading_info=Šis var aizņemt kādu brīdi… +component_failed_to_load=Atgadījās neparedzēta kļūda. [org] org_name_holder=Organizācijas nosaukums @@ -2698,6 +2703,7 @@ teams.invite.description=Nospiediet pogu zemāk, lai pievienotos komandai. [admin] dashboard=Infopanelis +self_check=Pašpārbaude identity_access=Identitāte un piekļuve users=Lietotāju konti organizations=Organizācijas @@ -3223,6 +3229,7 @@ notices.desc=Apraksts notices.op=Op. notices.delete_success=Sistēmas paziņojumi ir dzēsti. +self_check.no_problem_found=Pašlaik nav atrasta neviena problēma. [action] create_repo=izveidoja repozitoriju %s @@ -3560,6 +3567,7 @@ variables.none=Vēl nav neviena mainīgā. variables.deletion=Noņemt mainīgo variables.deletion.description=Mainīgā noņemšana ir neatgriezeniska un nav atsaucama. Vai turpināt? variables.description=Mainīgie tiks padoti noteiktām darbībām, un citādāk tos nevar nolasīt. +variables.id_not_exist=Mainīgais ar identifikatoru %d nepastāv. variables.edit=Labot mainīgo variables.deletion.failed=Neizdevās noņemt mainīgo. variables.deletion.success=Mainīgais tika noņemts. diff --git a/options/locale/locale_zh-CN.ini b/options/locale/locale_zh-CN.ini index 226561100..8e2dee8ec 100644 --- a/options/locale/locale_zh-CN.ini +++ b/options/locale/locale_zh-CN.ini @@ -2140,7 +2140,7 @@ settings.trust_model.collaborator.long=协作者:信任协作者的签名 settings.trust_model.collaborator.desc=此仓库中协作者的有效签名将被标记为「可信」(无论它们是否是提交者),签名只符合提交者时将标记为「不可信」,都不匹配时标记为「不匹配」。 settings.trust_model.committer=提交者 settings.trust_model.committer.long=提交者: 信任与提交者相符的签名 (此特性类似 GitHub,这会强制采用 Forgejo 作为提交者和签名者) -settings.trust_model.committer.desc=有效签名只有和提交者相匹配才会被标记为“受信任”,否则它们将被标记为“不匹配”。这强制 Forgejo 成为签名提交的提交者,而实际提交者被加上 Co-authored-by: 和 Co-committed-by: 的标记。 默认的 Forgejo 密钥必须撇撇数据库种的一名用户。 +settings.trust_model.committer.desc=有效签名只有和提交者相匹配才会被标记为“受信任”,否则它们将被标记为“不匹配”。这强制 Forgejo 成为签名提交的提交者,而实际提交者被加上 Co-authored-by: 和 Co-committed-by: 的标记。 默认的 Forgejo 密钥必须匹配数据库中的一名用户。 settings.trust_model.collaboratorcommitter=协作者+提交者 settings.trust_model.collaboratorcommitter.long=协作者+提交者:信任协作者同时是提交者的签名 settings.trust_model.collaboratorcommitter.desc=此仓库中协作者的有效签名在他同时是提交者时将被标记为「可信」,签名只匹配了提交者时将标记为「不可信」,都不匹配时标记为「不匹配」。这会强制 Forgejo 成为签名者和提交者,实际的提交者将被标记于提交消息结尾处的「Co-Authored-By:」和「Co-Committed-By:」。默认的 Forgejo 签名密钥必须匹配数据库中的一个用户密钥。 @@ -3325,7 +3325,9 @@ self_check.database_fix_mssql = 对于 MSSQL 用户,目前您只能通过SQL self_check.no_problem_found=尚未发现问题。 self_check.database_collation_mismatch=期望数据库使用的校验方式:%s self_check.database_collation_case_insensitive=数据库正在使用一个校验 %s, 这是一个不敏感的校验. 虽然Gitea可以与它合作,但可能有一些罕见的情况不如预期的那样起作用。 +self_check.database_inconsistent_collation_columns=数据库正在使用%s的排序规则,但是这些列使用了不匹配的排序规则。这可能会造成一些意外问题。 self_check.database_fix_mysql=对于MySQL/MariaDB用户,您可以使用“gitea doctor convert”命令来解决校验问题。 或者您也可以通过 "ALTER ... COLLATE ..." 这样的SQL 来手动解决这个问题。 +self_check.database_fix_mssql=对于MSSQL用户,您现在只能通过"ALTER ... COLLATE ..."SQLs手动解决这个问题。 [action] create_repo=创建了仓库 %s diff --git a/package-lock.json b/package-lock.json index c833670f7..6d1d2850c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,7 +10,7 @@ "@citation-js/plugin-csl": "0.7.6", "@citation-js/plugin-software-formats": "0.6.1", "@claviska/jquery-minicolors": "2.3.6", - "@github/markdown-toolbar-element": "2.2.1", + "@github/markdown-toolbar-element": "2.2.3", "@github/relative-time-element": "4.3.1", "@github/text-expander-element": "2.6.1", "@mcaptcha/vanilla-glue": "0.1.0-alpha-3", @@ -18,11 +18,11 @@ "@webcomponents/custom-elements": "1.6.0", "add-asset-webpack-plugin": "2.0.1", "ansi_up": "6.0.2", - "asciinema-player": "3.6.4", - "chart.js": "4.4.1", + "asciinema-player": "3.7.0", + "chart.js": "4.4.2", "chartjs-adapter-dayjs-4": "1.0.4", "chartjs-plugin-zoom": "2.0.1", - "clippie": "4.0.6", + "clippie": "4.0.7", "css-loader": "6.10.0", "css-variables-parser": "1.0.1", "dayjs": "1.11.10", @@ -37,16 +37,16 @@ "katex": "0.16.9", "license-checker-webpack-plugin": "0.2.1", "mermaid": "10.8.0", - "mini-css-extract-plugin": "2.8.0", + "mini-css-extract-plugin": "2.8.1", "minimatch": "9.0.3", "monaco-editor": "0.46.0", "monaco-editor-webpack-plugin": "7.1.0", "pdfobject": "2.3.0", "postcss": "8.4.35", - "postcss-loader": "8.1.0", + "postcss-loader": "8.1.1", "pretty-ms": "9.0.0", "sortablejs": "1.15.2", - "swagger-ui-dist": "5.11.6", + "swagger-ui-dist": "5.11.8", "tailwindcss": "3.4.1", "throttle-debounce": "5.0.0", "tinycolor2": "1.6.0", @@ -54,25 +54,25 @@ "toastify-js": "1.12.0", "tributejs": "5.1.3", "uint8-to-base64": "0.2.0", - "vue": "3.4.19", + "vue": "3.4.21", "vue-bar-graph": "2.0.0", "vue-chartjs": "5.3.0", "vue-loader": "17.4.2", "vue3-calendar-heatmap": "2.0.5", - "webpack": "5.90.2", + "webpack": "5.90.3", "webpack-cli": "5.1.4", "wrap-ansi": "9.0.0" }, "devDependencies": { "@eslint-community/eslint-plugin-eslint-comments": "4.1.0", - "@playwright/test": "1.41.2", + "@playwright/test": "1.42.1", "@stoplight/spectral-cli": "6.11.0", - "@stylistic/eslint-plugin-js": "1.6.2", - "@stylistic/stylelint-plugin": "2.0.0", + "@stylistic/eslint-plugin-js": "1.6.3", + "@stylistic/stylelint-plugin": "2.1.0", "@vitejs/plugin-vue": "5.0.4", - "eslint": "8.56.0", + "eslint": "8.57.0", "eslint-plugin-array-func": "4.0.0", - "eslint-plugin-github": "4.10.1", + "eslint-plugin-github": "4.10.2", "eslint-plugin-i": "2.29.1", "eslint-plugin-jquery": "1.5.1", "eslint-plugin-no-jquery": "2.7.0", @@ -82,7 +82,7 @@ "eslint-plugin-unicorn": "51.0.1", "eslint-plugin-vitest": "0.3.22", "eslint-plugin-vitest-globals": "1.4.0", - "eslint-plugin-vue": "9.21.1", + "eslint-plugin-vue": "9.22.0", "eslint-plugin-vue-scoped-css": "2.7.2", "eslint-plugin-wc": "2.0.4", "jsdom": "24.0.0", @@ -94,7 +94,7 @@ "svgo": "3.2.0", "updates": "15.1.2", "vite-string-plugin": "1.1.5", - "vitest": "1.2.2" + "vitest": "1.3.1" }, "engines": { "node": ">= 18.0.0" @@ -296,9 +296,9 @@ } }, "node_modules/@babel/parser": { - "version": "7.23.9", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.9.tgz", - "integrity": "sha512-9tcKgqKbs3xGJ+NtKF2ndOBBLVwPjl1SHxPQkd36r3Dlirw3xWUeGaTbqr7uGZcTaxkVNwc+03SVP7aCdWrTlA==", + "version": "7.24.0", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.24.0.tgz", + "integrity": "sha512-QuP/FxEAzMSjXygs8v4N9dvdXzEHN4W1oF3PxuWAtPo08UdM17u89RDMgjLn/mlc56iM0HlLmVkO/wgR+rDgHg==", "bin": { "parser": "bin/babel-parser.js" }, @@ -307,9 +307,9 @@ } }, "node_modules/@babel/runtime": { - "version": "7.23.9", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.23.9.tgz", - "integrity": "sha512-0CX6F+BI2s9dkUqr08KFrAIZgNFj75rdBU/DjCyYLIaV/quFjkk6T+EJ2LkZHyZTbEV4L5p97mNkUsHl2wLFAw==", + "version": "7.24.0", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.24.0.tgz", + "integrity": "sha512-Chk32uHMg6TnQdvw2e9IlqPpFX/6NLuK0Ys2PqLb7/gL5uFn9mXvK715FGLlOLQrcO4qIkNHkvPGktzzXexsFw==", "dependencies": { "regenerator-runtime": "^0.14.0" }, @@ -466,9 +466,9 @@ } }, "node_modules/@csstools/css-parser-algorithms": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/@csstools/css-parser-algorithms/-/css-parser-algorithms-2.5.0.tgz", - "integrity": "sha512-abypo6m9re3clXA00eu5syw+oaPHbJTPapu9C4pzNsJ4hdZDzushT50Zhu+iIYXgEe1CxnRMn7ngsbV+MLrlpQ==", + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/@csstools/css-parser-algorithms/-/css-parser-algorithms-2.6.0.tgz", + "integrity": "sha512-YfEHq0eRH98ffb5/EsrrDspVWAuph6gDggAE74ZtjecsmyyWpW768hOyiONa8zwWGbIWYfa2Xp4tRTrpQQ00CQ==", "dev": true, "funding": [ { @@ -507,9 +507,9 @@ } }, "node_modules/@csstools/media-query-list-parser": { - "version": "2.1.7", - "resolved": "https://registry.npmjs.org/@csstools/media-query-list-parser/-/media-query-list-parser-2.1.7.tgz", - "integrity": "sha512-lHPKJDkPUECsyAvD60joYfDmp8UERYxHGkFfyLJFTVK/ERJe0sVlIFLXU5XFxdjNDTerp5L4KeaKG+Z5S94qxQ==", + "version": "2.1.8", + "resolved": "https://registry.npmjs.org/@csstools/media-query-list-parser/-/media-query-list-parser-2.1.8.tgz", + "integrity": "sha512-DiD3vG5ciNzeuTEoh74S+JMjQDs50R3zlxHnBnfd04YYfA/kh2KiBCGhzqLxlJcNq+7yNQ3stuZZYLX6wK/U2g==", "dev": true, "funding": [ { @@ -525,14 +525,14 @@ "node": "^14 || ^16 || >=18" }, "peerDependencies": { - "@csstools/css-parser-algorithms": "^2.5.0", + "@csstools/css-parser-algorithms": "^2.6.0", "@csstools/css-tokenizer": "^2.2.3" } }, "node_modules/@csstools/selector-specificity": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@csstools/selector-specificity/-/selector-specificity-3.0.1.tgz", - "integrity": "sha512-NPljRHkq4a14YzZ3YD406uaxh7s0g6eAq3L9aLOWywoqe8PkYamAvtsh7KNX6c++ihDrJ0RiU+/z7rGnhlZ5ww==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@csstools/selector-specificity/-/selector-specificity-3.0.2.tgz", + "integrity": "sha512-RpHaZ1h9LE7aALeQXmXrJkRG84ZxIsctEN2biEUmFyKpzFM3zZ35eUMcIzZFsw/2olQE6v69+esEqU2f1MKycg==", "dev": true, "funding": [ { @@ -1012,9 +1012,9 @@ } }, "node_modules/@eslint/js": { - "version": "8.56.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.56.0.tgz", - "integrity": "sha512-gMsVel9D7f2HLkBma9VbtzZRehRogVRfbr++f06nL2vnCGCNlzOD+/MUov/F4p8myyAHspEhVobgjpX64q5m6A==", + "version": "8.57.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.0.tgz", + "integrity": "sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g==", "dev": true, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -1032,9 +1032,9 @@ "integrity": "sha512-gwxPzLw8XKecy1nP63i9lOBritS3bWmxl02UX6G0TwMQZbMem1BCS1tEZgYd3mkrkiDrUMWaX+DbFCuDFo3K+A==" }, "node_modules/@github/markdown-toolbar-element": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/@github/markdown-toolbar-element/-/markdown-toolbar-element-2.2.1.tgz", - "integrity": "sha512-ap+ulyqzG3aVqwKsKjbDdYwM75TQXZpPtmIuPwm+54OTgcC96267oX3cEqd1wSqGsH7O5PonZ//fE9jH7Q4JkA==" + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/@github/markdown-toolbar-element/-/markdown-toolbar-element-2.2.3.tgz", + "integrity": "sha512-AlquKGee+IWiAMYVB0xyHFZRMnu4n3X4HTvJHu79GiVJ1ojTukCWyxMlF5NMsecoLcBKsuBhx3QPv2vkE/zQ0A==" }, "node_modules/@github/relative-time-element": { "version": "4.3.1", @@ -1142,11 +1142,6 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/@isaacs/cliui/node_modules/emoji-regex": { - "version": "9.2.2", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", - "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==" - }, "node_modules/@isaacs/cliui/node_modules/string-width": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", @@ -1206,13 +1201,13 @@ } }, "node_modules/@jridgewell/gen-mapping": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz", - "integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==", + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", + "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", "dependencies": { - "@jridgewell/set-array": "^1.0.1", + "@jridgewell/set-array": "^1.2.1", "@jridgewell/sourcemap-codec": "^1.4.10", - "@jridgewell/trace-mapping": "^0.3.9" + "@jridgewell/trace-mapping": "^0.3.24" }, "engines": { "node": ">=6.0.0" @@ -1227,9 +1222,9 @@ } }, "node_modules/@jridgewell/set-array": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", - "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", + "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", "engines": { "node": ">=6.0.0" } @@ -1249,9 +1244,9 @@ "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==" }, "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.22", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.22.tgz", - "integrity": "sha512-Wf963MzWtA2sjrNt+g18IAln9lKnlRp+K2eH4jjIoF1wYeq3aMREpG09xhlhdzS0EjwU7qmUJYangWa+151vZw==", + "version": "0.3.25", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", + "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" @@ -1389,12 +1384,12 @@ } }, "node_modules/@playwright/test": { - "version": "1.41.2", - "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.41.2.tgz", - "integrity": "sha512-qQB9h7KbibJzrDpkXkYvsmiDJK14FULCCZgEcoe2AvFAS64oCirWTwzTlAYEbKaRxWs5TFesE1Na6izMv3HfGg==", + "version": "1.42.1", + "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.42.1.tgz", + "integrity": "sha512-Gq9rmS54mjBL/7/MvBaNOBwbfnh7beHvS6oS4srqXFcQHpQCV1+c8JXWE8VLPyRDhgS3H8x8A7hztqI9VnwrAQ==", "dev": true, "dependencies": { - "playwright": "1.41.2" + "playwright": "1.42.1" }, "bin": { "playwright": "cli.js" @@ -1465,9 +1460,9 @@ "dev": true }, "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.11.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.11.0.tgz", - "integrity": "sha512-BV+u2QSfK3i1o6FucqJh5IK9cjAU6icjFFhvknzFgu472jzl0bBojfDAkJLBEsHFMo+YZg6rthBvBBt8z12IBQ==", + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.12.0.tgz", + "integrity": "sha512-+ac02NL/2TCKRrJu2wffk1kZ+RyqxVUlbjSagNgPm94frxtr+XDL12E5Ll1enWskLrtrZ2r8L3wED1orIibV/w==", "cpu": [ "arm" ], @@ -1478,9 +1473,9 @@ ] }, "node_modules/@rollup/rollup-android-arm64": { - "version": "4.11.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.11.0.tgz", - "integrity": "sha512-0ij3iw7sT5jbcdXofWO2NqDNjSVVsf6itcAkV2I6Xsq4+6wjW1A8rViVB67TfBEan7PV2kbLzT8rhOVWLI2YXw==", + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.12.0.tgz", + "integrity": "sha512-OBqcX2BMe6nvjQ0Nyp7cC90cnumt8PXmO7Dp3gfAju/6YwG0Tj74z1vKrfRz7qAv23nBcYM8BCbhrsWqO7PzQQ==", "cpu": [ "arm64" ], @@ -1491,9 +1486,9 @@ ] }, "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.11.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.11.0.tgz", - "integrity": "sha512-yPLs6RbbBMupArf6qv1UDk6dzZvlH66z6NLYEwqTU0VHtss1wkI4UYeeMS7TVj5QRVvaNAWYKP0TD/MOeZ76Zg==", + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.12.0.tgz", + "integrity": "sha512-X64tZd8dRE/QTrBIEs63kaOBG0b5GVEd3ccoLtyf6IdXtHdh8h+I56C2yC3PtC9Ucnv0CpNFJLqKFVgCYe0lOQ==", "cpu": [ "arm64" ], @@ -1504,9 +1499,9 @@ ] }, "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.11.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.11.0.tgz", - "integrity": "sha512-OvqIgwaGAwnASzXaZEeoJY3RltOFg+WUbdkdfoluh2iqatd090UeOG3A/h0wNZmE93dDew9tAtXgm3/+U/B6bw==", + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.12.0.tgz", + "integrity": "sha512-cc71KUZoVbUJmGP2cOuiZ9HSOP14AzBAThn3OU+9LcA1+IUqswJyR1cAJj3Mg55HbjZP6OLAIscbQsQLrpgTOg==", "cpu": [ "x64" ], @@ -1517,9 +1512,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.11.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.11.0.tgz", - "integrity": "sha512-X17s4hZK3QbRmdAuLd2EE+qwwxL8JxyVupEqAkxKPa/IgX49ZO+vf0ka69gIKsaYeo6c1CuwY3k8trfDtZ9dFg==", + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.12.0.tgz", + "integrity": "sha512-a6w/Y3hyyO6GlpKL2xJ4IOh/7d+APaqLYdMf86xnczU3nurFTaVN9s9jOXQg97BE4nYm/7Ga51rjec5nfRdrvA==", "cpu": [ "arm" ], @@ -1530,9 +1525,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.11.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.11.0.tgz", - "integrity": "sha512-673Lu9EJwxVB9NfYeA4AdNu0FOHz7g9t6N1DmT7bZPn1u6bTF+oZjj+fuxUcrfxWXE0r2jxl5QYMa9cUOj9NFg==", + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.12.0.tgz", + "integrity": "sha512-0fZBq27b+D7Ar5CQMofVN8sggOVhEtzFUwOwPppQt0k+VR+7UHMZZY4y+64WJ06XOhBTKXtQB/Sv0NwQMXyNAA==", "cpu": [ "arm64" ], @@ -1543,9 +1538,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.11.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.11.0.tgz", - "integrity": "sha512-yFW2msTAQNpPJaMmh2NpRalr1KXI7ZUjlN6dY/FhWlOclMrZezm5GIhy3cP4Ts2rIAC+IPLAjNibjp1BsxCVGg==", + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.12.0.tgz", + "integrity": "sha512-eTvzUS3hhhlgeAv6bfigekzWZjaEX9xP9HhxB0Dvrdbkk5w/b+1Sxct2ZuDxNJKzsRStSq1EaEkVSEe7A7ipgQ==", "cpu": [ "arm64" ], @@ -1556,9 +1551,9 @@ ] }, "node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.11.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.11.0.tgz", - "integrity": "sha512-kKT9XIuhbvYgiA3cPAGntvrBgzhWkGpBMzuk1V12Xuoqg7CI41chye4HU0vLJnGf9MiZzfNh4I7StPeOzOWJfA==", + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.12.0.tgz", + "integrity": "sha512-ix+qAB9qmrCRiaO71VFfY8rkiAZJL8zQRXveS27HS+pKdjwUfEhqo2+YF2oI+H/22Xsiski+qqwIBxVewLK7sw==", "cpu": [ "riscv64" ], @@ -1569,9 +1564,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.11.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.11.0.tgz", - "integrity": "sha512-6q4ESWlyTO+erp1PSCmASac+ixaDv11dBk1fqyIuvIUc/CmRAX2Zk+2qK1FGo5q7kyDcjHCFVwgGFCGIZGVwCA==", + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.12.0.tgz", + "integrity": "sha512-TenQhZVOtw/3qKOPa7d+QgkeM6xY0LtwzR8OplmyL5LrgTWIXpTQg2Q2ycBf8jm+SFW2Wt/DTn1gf7nFp3ssVA==", "cpu": [ "x64" ], @@ -1582,9 +1577,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.11.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.11.0.tgz", - "integrity": "sha512-vIAQUmXeMLmaDN78HSE4Kh6xqof2e3TJUKr+LPqXWU4NYNON0MDN9h2+t4KHrPAQNmU3w1GxBQ/n01PaWFwa5w==", + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.12.0.tgz", + "integrity": "sha512-LfFdRhNnW0zdMvdCb5FNuWlls2WbbSridJvxOvYWgSBOYZtgBfW9UGNJG//rwMqTX1xQE9BAodvMH9tAusKDUw==", "cpu": [ "x64" ], @@ -1595,9 +1590,9 @@ ] }, "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.11.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.11.0.tgz", - "integrity": "sha512-LVXo9dDTGPr0nezMdqa1hK4JeoMZ02nstUxGYY/sMIDtTYlli1ZxTXBYAz3vzuuvKO4X6NBETciIh7N9+abT1g==", + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.12.0.tgz", + "integrity": "sha512-JPDxovheWNp6d7AHCgsUlkuCKvtu3RB55iNEkaQcf0ttsDU/JZF+iQnYcQJSk/7PtT4mjjVG8N1kpwnI9SLYaw==", "cpu": [ "arm64" ], @@ -1608,9 +1603,9 @@ ] }, "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.11.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.11.0.tgz", - "integrity": "sha512-xZVt6K70Gr3I7nUhug2dN6VRR1ibot3rXqXS3wo+8JP64t7djc3lBFyqO4GiVrhNaAIhUCJtwQ/20dr0h0thmQ==", + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.12.0.tgz", + "integrity": "sha512-fjtuvMWRGJn1oZacG8IPnzIV6GF2/XG+h71FKn76OYFqySXInJtseAqdprVTDTyqPxQOG9Exak5/E9Z3+EJ8ZA==", "cpu": [ "ia32" ], @@ -1621,9 +1616,9 @@ ] }, "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.11.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.11.0.tgz", - "integrity": "sha512-f3I7h9oTg79UitEco9/2bzwdciYkWr8pITs3meSDSlr1TdvQ7IxkQaaYN2YqZXX5uZhiYL+VuYDmHwNzhx+HOg==", + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.12.0.tgz", + "integrity": "sha512-ZYmr5mS2wd4Dew/JjT0Fqi2NPB/ZhZ2VvPp7SmvPZb4Y1CG/LRcS6tcRo2cYU7zLK5A7cdbhWnnWmUjoI4qapg==", "cpu": [ "x64" ], @@ -2091,9 +2086,9 @@ "dev": true }, "node_modules/@stylistic/eslint-plugin-js": { - "version": "1.6.2", - "resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin-js/-/eslint-plugin-js-1.6.2.tgz", - "integrity": "sha512-ndT6X2KgWGxv8101pdMOxL8pihlYIHcOv3ICd70cgaJ9exwkPn8hJj4YQwslxoAlre1TFHnXd/G1/hYXgDrjIA==", + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin-js/-/eslint-plugin-js-1.6.3.tgz", + "integrity": "sha512-ckdz51oHxD2FaxgY2piJWJVJiwgp8Uu96s+as2yB3RMwavn3nHBrpliVukXY9S/DmMicPRB2+H8nBk23GDG+qA==", "dev": true, "dependencies": { "@types/eslint": "^8.56.2", @@ -2110,19 +2105,19 @@ } }, "node_modules/@stylistic/stylelint-plugin": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@stylistic/stylelint-plugin/-/stylelint-plugin-2.0.0.tgz", - "integrity": "sha512-dHKuT6PGd1WGZLOTuozAM7GdQzdmlmnFXYzvV1jYJXXpcCpV/OJ3+n8TXpMkoOeKHpJydY43EOoZTO1W/FOA4Q==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@stylistic/stylelint-plugin/-/stylelint-plugin-2.1.0.tgz", + "integrity": "sha512-mUZEW9uImHSbXeyzbFmHb8WPBv56UTaEnWL/3dGdAiJ54C+8GTfDwDVdI6gbqT9wV7zynkPu7tCXc5746H9mZQ==", "dev": true, "dependencies": { - "@csstools/css-parser-algorithms": "^2.3.2", - "@csstools/css-tokenizer": "^2.2.1", - "@csstools/media-query-list-parser": "^2.1.5", + "@csstools/css-parser-algorithms": "^2.5.0", + "@csstools/css-tokenizer": "^2.2.3", + "@csstools/media-query-list-parser": "^2.1.7", "is-plain-object": "^5.0.0", - "postcss-selector-parser": "^6.0.13", + "postcss-selector-parser": "^6.0.15", "postcss-value-parser": "^4.2.0", "style-search": "^0.1.0", - "stylelint": "^16.0.2" + "stylelint": "^16.2.1" }, "engines": { "node": "^18.12 || >=20.9" @@ -2189,9 +2184,9 @@ } }, "node_modules/@types/eslint": { - "version": "8.56.2", - "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.56.2.tgz", - "integrity": "sha512-uQDwm1wFHmbBbCZCqAlq6Do9LYwByNZHWzXppSnay9SuwJ+VRbjkbLABer54kcPnMSlG6Fdiy2yaFXm/z9Z5gw==", + "version": "8.56.5", + "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.56.5.tgz", + "integrity": "sha512-u5/YPJHo1tvkSF2CE0USEkxon82Z5DBy2xR+qfyYNszpX9qcs4sT6uq2kBbj4BXY1+DBGDPnrhMZV3pKWGNukw==", "dependencies": { "@types/estree": "*", "@types/json-schema": "*" @@ -2241,9 +2236,9 @@ "integrity": "sha512-nG96G3Wp6acyAgJqGasjODb+acrI7KltPiRxzHPXnP3NgI28bpQDRv53olbqGXbfcgF5aiiHmO3xpwEpS5Ld9g==" }, "node_modules/@types/node": { - "version": "20.11.19", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.11.19.tgz", - "integrity": "sha512-7xMnVEcZFu0DikYjWOlRq7NTPETrm7teqUT2WkQjrTIkEgUyyGdWsj/Zg8bEJt5TNklzbPD1X3fqfsHw3SpapQ==", + "version": "20.11.24", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.11.24.tgz", + "integrity": "sha512-Kza43ewS3xoLgCEpQrsT+xRo/EJej1y0kVYGiLFE1NEODXGzTfwiC6tXTLMQskn1X4/Rjlh0MQUvx9W+L9long==", "dependencies": { "undici-types": "~5.26.4" } @@ -2261,9 +2256,9 @@ "dev": true }, "node_modules/@types/semver": { - "version": "7.5.7", - "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.7.tgz", - "integrity": "sha512-/wdoPq1QqkSj9/QOeKkFquEuPzQbHTWAMPH/PaUMB+JuR31lXhlWXRZ52IpfDYVlDOUBvX09uBrPwxGT1hjNBg==", + "version": "7.5.8", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.8.tgz", + "integrity": "sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ==", "dev": true }, "node_modules/@types/tern": { @@ -2286,16 +2281,16 @@ "dev": true }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.21.0.tgz", - "integrity": "sha512-oy9+hTPCUFpngkEZUSzbf9MxI65wbKFoQYsgPdILTfbUldp5ovUuphZVe4i30emU9M/kP+T64Di0mxl7dSw3MA==", + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.1.0.tgz", + "integrity": "sha512-j6vT/kCulhG5wBmGtstKeiVr1rdXE4nk+DT1k6trYkwlrvW9eOF5ZbgKnd/YR6PcM4uTEXa0h6Fcvf6X7Dxl0w==", "dev": true, "dependencies": { "@eslint-community/regexpp": "^4.5.1", - "@typescript-eslint/scope-manager": "6.21.0", - "@typescript-eslint/type-utils": "6.21.0", - "@typescript-eslint/utils": "6.21.0", - "@typescript-eslint/visitor-keys": "6.21.0", + "@typescript-eslint/scope-manager": "7.1.0", + "@typescript-eslint/type-utils": "7.1.0", + "@typescript-eslint/utils": "7.1.0", + "@typescript-eslint/visitor-keys": "7.1.0", "debug": "^4.3.4", "graphemer": "^1.4.0", "ignore": "^5.2.4", @@ -2311,8 +2306,8 @@ "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "@typescript-eslint/parser": "^6.0.0 || ^6.0.0-alpha", - "eslint": "^7.0.0 || ^8.0.0" + "@typescript-eslint/parser": "^7.0.0", + "eslint": "^8.56.0" }, "peerDependenciesMeta": { "typescript": { @@ -2321,15 +2316,15 @@ } }, "node_modules/@typescript-eslint/parser": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.21.0.tgz", - "integrity": "sha512-tbsV1jPne5CkFQCgPBcDOt30ItF7aJoZL997JSF7MhGQqOeT3svWRYxiqlfA5RUdlHN6Fi+EI9bxqbdyAUZjYQ==", + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.1.0.tgz", + "integrity": "sha512-V1EknKUubZ1gWFjiOZhDSNToOjs63/9O0puCgGS8aDOgpZY326fzFu15QAUjwaXzRZjf/qdsdBrckYdv9YxB8w==", "dev": true, "dependencies": { - "@typescript-eslint/scope-manager": "6.21.0", - "@typescript-eslint/types": "6.21.0", - "@typescript-eslint/typescript-estree": "6.21.0", - "@typescript-eslint/visitor-keys": "6.21.0", + "@typescript-eslint/scope-manager": "7.1.0", + "@typescript-eslint/types": "7.1.0", + "@typescript-eslint/typescript-estree": "7.1.0", + "@typescript-eslint/visitor-keys": "7.1.0", "debug": "^4.3.4" }, "engines": { @@ -2340,7 +2335,7 @@ "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "eslint": "^7.0.0 || ^8.0.0" + "eslint": "^8.56.0" }, "peerDependenciesMeta": { "typescript": { @@ -2349,13 +2344,13 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.21.0.tgz", - "integrity": "sha512-OwLUIWZJry80O99zvqXVEioyniJMa+d2GrqpUTqi5/v5D5rOrppJVBPa0yKCblcigC0/aYAzxxqQ1B+DS2RYsg==", + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.1.0.tgz", + "integrity": "sha512-6TmN4OJiohHfoOdGZ3huuLhpiUgOGTpgXNUPJgeZOZR3DnIpdSgtt83RS35OYNNXxM4TScVlpVKC9jyQSETR1A==", "dev": true, "dependencies": { - "@typescript-eslint/types": "6.21.0", - "@typescript-eslint/visitor-keys": "6.21.0" + "@typescript-eslint/types": "7.1.0", + "@typescript-eslint/visitor-keys": "7.1.0" }, "engines": { "node": "^16.0.0 || >=18.0.0" @@ -2366,13 +2361,13 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.21.0.tgz", - "integrity": "sha512-rZQI7wHfao8qMX3Rd3xqeYSMCL3SoiSQLBATSiVKARdFGCYSRvmViieZjqc58jKgs8Y8i9YvVVhRbHSTA4VBag==", + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.1.0.tgz", + "integrity": "sha512-UZIhv8G+5b5skkcuhgvxYWHjk7FW7/JP5lPASMEUoliAPwIH/rxoUSQPia2cuOj9AmDZmwUl1usKm85t5VUMew==", "dev": true, "dependencies": { - "@typescript-eslint/typescript-estree": "6.21.0", - "@typescript-eslint/utils": "6.21.0", + "@typescript-eslint/typescript-estree": "7.1.0", + "@typescript-eslint/utils": "7.1.0", "debug": "^4.3.4", "ts-api-utils": "^1.0.1" }, @@ -2384,7 +2379,7 @@ "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "eslint": "^7.0.0 || ^8.0.0" + "eslint": "^8.56.0" }, "peerDependenciesMeta": { "typescript": { @@ -2393,9 +2388,9 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.21.0.tgz", - "integrity": "sha512-1kFmZ1rOm5epu9NZEZm1kckCDGj5UJEf7P1kliH4LKu/RkwpsfqqGmY2OOcUs18lSlQBKLDYBOGxRVtrMN5lpg==", + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.1.0.tgz", + "integrity": "sha512-qTWjWieJ1tRJkxgZYXx6WUYtWlBc48YRxgY2JN1aGeVpkhmnopq+SUC8UEVGNXIvWH7XyuTjwALfG6bFEgCkQA==", "dev": true, "engines": { "node": "^16.0.0 || >=18.0.0" @@ -2406,13 +2401,13 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.21.0.tgz", - "integrity": "sha512-6npJTkZcO+y2/kr+z0hc4HwNfrrP4kNYh57ek7yCNlrBjWQ1Y0OS7jiZTkgumrvkX5HkEKXFZkkdFNkaW2wmUQ==", + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.1.0.tgz", + "integrity": "sha512-k7MyrbD6E463CBbSpcOnwa8oXRdHzH1WiVzOipK3L5KSML92ZKgUBrTlehdi7PEIMT8k0bQixHUGXggPAlKnOQ==", "dev": true, "dependencies": { - "@typescript-eslint/types": "6.21.0", - "@typescript-eslint/visitor-keys": "6.21.0", + "@typescript-eslint/types": "7.1.0", + "@typescript-eslint/visitor-keys": "7.1.0", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -2434,17 +2429,17 @@ } }, "node_modules/@typescript-eslint/utils": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.21.0.tgz", - "integrity": "sha512-NfWVaC8HP9T8cbKQxHcsJBY5YE1O33+jpMwN45qzWWaPDZgLIbo12toGMWnmhvCpd3sIxkpDw3Wv1B3dYrbDQQ==", + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.1.0.tgz", + "integrity": "sha512-WUFba6PZC5OCGEmbweGpnNJytJiLG7ZvDBJJoUcX4qZYf1mGZ97mO2Mps6O2efxJcJdRNpqweCistDbZMwIVHw==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", "@types/json-schema": "^7.0.12", "@types/semver": "^7.5.0", - "@typescript-eslint/scope-manager": "6.21.0", - "@typescript-eslint/types": "6.21.0", - "@typescript-eslint/typescript-estree": "6.21.0", + "@typescript-eslint/scope-manager": "7.1.0", + "@typescript-eslint/types": "7.1.0", + "@typescript-eslint/typescript-estree": "7.1.0", "semver": "^7.5.4" }, "engines": { @@ -2455,16 +2450,16 @@ "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "eslint": "^7.0.0 || ^8.0.0" + "eslint": "^8.56.0" } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.21.0.tgz", - "integrity": "sha512-JJtkDduxLi9bivAB+cYOVMtbkqdPOhZ+ZI5LC47MIRrDV4Yn2o+ZnW10Nkmr28xRpSpdJ6Sm42Hjf2+REYXm0A==", + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.1.0.tgz", + "integrity": "sha512-FhUqNWluiGNzlvnDZiXad4mZRhtghdoKW6e98GoEOYSu5cND+E39rG5KwJMUzeENwm1ztYBRqof8wMLP+wNPIA==", "dev": true, "dependencies": { - "@typescript-eslint/types": "6.21.0", + "@typescript-eslint/types": "7.1.0", "eslint-visitor-keys": "^3.4.1" }, "engines": { @@ -2495,13 +2490,13 @@ } }, "node_modules/@vitest/expect": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-1.2.2.tgz", - "integrity": "sha512-3jpcdPAD7LwHUUiT2pZTj2U82I2Tcgg2oVPvKxhn6mDI2On6tfvPQTjAI4628GUGDZrCm4Zna9iQHm5cEexOAg==", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-1.3.1.tgz", + "integrity": "sha512-xofQFwIzfdmLLlHa6ag0dPV8YsnKOCP1KdAeVVh34vSjN2dcUiXYCD9htu/9eM7t8Xln4v03U9HLxLpPlsXdZw==", "dev": true, "dependencies": { - "@vitest/spy": "1.2.2", - "@vitest/utils": "1.2.2", + "@vitest/spy": "1.3.1", + "@vitest/utils": "1.3.1", "chai": "^4.3.10" }, "funding": { @@ -2509,12 +2504,12 @@ } }, "node_modules/@vitest/runner": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-1.2.2.tgz", - "integrity": "sha512-JctG7QZ4LSDXr5CsUweFgcpEvrcxOV1Gft7uHrvkQ+fsAVylmWQvnaAr/HDp3LAH1fztGMQZugIheTWjaGzYIg==", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-1.3.1.tgz", + "integrity": "sha512-5FzF9c3jG/z5bgCnjr8j9LNq/9OxV2uEBAITOXfoe3rdZJTdO7jzThth7FXv/6b+kdY65tpRQB7WaKhNZwX+Kg==", "dev": true, "dependencies": { - "@vitest/utils": "1.2.2", + "@vitest/utils": "1.3.1", "p-limit": "^5.0.0", "pathe": "^1.1.1" }, @@ -2550,9 +2545,9 @@ } }, "node_modules/@vitest/snapshot": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-1.2.2.tgz", - "integrity": "sha512-SmGY4saEw1+bwE1th6S/cZmPxz/Q4JWsl7LvbQIky2tKE35US4gd0Mjzqfr84/4OD0tikGWaWdMja/nWL5NIPA==", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-1.3.1.tgz", + "integrity": "sha512-EF++BZbt6RZmOlE3SuTPu/NfwBF6q4ABS37HHXzs2LUVPBLx2QoY/K0fKpRChSo8eLiuxcbCVfqKgx/dplCDuQ==", "dev": true, "dependencies": { "magic-string": "^0.30.5", @@ -2576,9 +2571,9 @@ } }, "node_modules/@vitest/spy": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-1.2.2.tgz", - "integrity": "sha512-k9Gcahssw8d7X3pSLq3e3XEu/0L78mUkCjivUqCQeXJm9clfXR/Td8+AP+VC1O6fKPIDLcHDTAmBOINVuv6+7g==", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-1.3.1.tgz", + "integrity": "sha512-xAcW+S099ylC9VLU7eZfdT9myV67Nor9w9zhf0mGCYJSO+zM2839tOeROTdikOi/8Qeusffvxb/MyBSOja1Uig==", "dev": true, "dependencies": { "tinyspy": "^2.2.0" @@ -2588,9 +2583,9 @@ } }, "node_modules/@vitest/utils": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-1.2.2.tgz", - "integrity": "sha512-WKITBHLsBHlpjnDQahr+XK6RE7MiAsgrIkr0pGhQ9ygoxBfUeG0lUG5iLlzqjmKSlBv3+j5EGsriBzh+C3Tq9g==", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-1.3.1.tgz", + "integrity": "sha512-d3Waie/299qqRyHTm2DjADeTaNdNSVsnwHPWrs20JMpjh6eiVq7ggggweO8rc4arhf6rRkWuHKwvxGvejUXZZQ==", "dev": true, "dependencies": { "diff-sequences": "^29.6.3", @@ -2618,39 +2613,39 @@ } }, "node_modules/@vue/compiler-core": { - "version": "3.4.19", - "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.4.19.tgz", - "integrity": "sha512-gj81785z0JNzRcU0Mq98E56e4ltO1yf8k5PQ+tV/7YHnbZkrM0fyFyuttnN8ngJZjbpofWE/m4qjKBiLl8Ju4w==", + "version": "3.4.21", + "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.4.21.tgz", + "integrity": "sha512-MjXawxZf2SbZszLPYxaFCjxfibYrzr3eYbKxwpLR9EQN+oaziSu3qKVbwBERj1IFIB8OLUewxB5m/BFzi613og==", "dependencies": { "@babel/parser": "^7.23.9", - "@vue/shared": "3.4.19", + "@vue/shared": "3.4.21", "entities": "^4.5.0", "estree-walker": "^2.0.2", "source-map-js": "^1.0.2" } }, "node_modules/@vue/compiler-dom": { - "version": "3.4.19", - "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.4.19.tgz", - "integrity": "sha512-vm6+cogWrshjqEHTzIDCp72DKtea8Ry/QVpQRYoyTIg9k7QZDX6D8+HGURjtmatfgM8xgCFtJJaOlCaRYRK3QA==", + "version": "3.4.21", + "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.4.21.tgz", + "integrity": "sha512-IZC6FKowtT1sl0CR5DpXSiEB5ayw75oT2bma1BEhV7RRR1+cfwLrxc2Z8Zq/RGFzJ8w5r9QtCOvTjQgdn0IKmA==", "dependencies": { - "@vue/compiler-core": "3.4.19", - "@vue/shared": "3.4.19" + "@vue/compiler-core": "3.4.21", + "@vue/shared": "3.4.21" } }, "node_modules/@vue/compiler-sfc": { - "version": "3.4.19", - "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.4.19.tgz", - "integrity": "sha512-LQ3U4SN0DlvV0xhr1lUsgLCYlwQfUfetyPxkKYu7dkfvx7g3ojrGAkw0AERLOKYXuAGnqFsEuytkdcComei3Yg==", + "version": "3.4.21", + "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.4.21.tgz", + "integrity": "sha512-me7epoTxYlY+2CUM7hy9PCDdpMPfIwrOvAXud2Upk10g4YLv9UBW7kL798TvMeDhPthkZ0CONNrK2GoeI1ODiQ==", "dependencies": { "@babel/parser": "^7.23.9", - "@vue/compiler-core": "3.4.19", - "@vue/compiler-dom": "3.4.19", - "@vue/compiler-ssr": "3.4.19", - "@vue/shared": "3.4.19", + "@vue/compiler-core": "3.4.21", + "@vue/compiler-dom": "3.4.21", + "@vue/compiler-ssr": "3.4.21", + "@vue/shared": "3.4.21", "estree-walker": "^2.0.2", - "magic-string": "^0.30.6", - "postcss": "^8.4.33", + "magic-string": "^0.30.7", + "postcss": "^8.4.35", "source-map-js": "^1.0.2" } }, @@ -2666,57 +2661,57 @@ } }, "node_modules/@vue/compiler-ssr": { - "version": "3.4.19", - "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.4.19.tgz", - "integrity": "sha512-P0PLKC4+u4OMJ8sinba/5Z/iDT84uMRRlrWzadgLA69opCpI1gG4N55qDSC+dedwq2fJtzmGald05LWR5TFfLw==", + "version": "3.4.21", + "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.4.21.tgz", + "integrity": "sha512-M5+9nI2lPpAsgXOGQobnIueVqc9sisBFexh5yMIMRAPYLa7+5wEJs8iqOZc1WAa9WQbx9GR2twgznU8LTIiZ4Q==", "dependencies": { - "@vue/compiler-dom": "3.4.19", - "@vue/shared": "3.4.19" + "@vue/compiler-dom": "3.4.21", + "@vue/shared": "3.4.21" } }, "node_modules/@vue/reactivity": { - "version": "3.4.19", - "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.4.19.tgz", - "integrity": "sha512-+VcwrQvLZgEclGZRHx4O2XhyEEcKaBi50WbxdVItEezUf4fqRh838Ix6amWTdX0CNb/b6t3Gkz3eOebfcSt+UA==", + "version": "3.4.21", + "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.4.21.tgz", + "integrity": "sha512-UhenImdc0L0/4ahGCyEzc/pZNwVgcglGy9HVzJ1Bq2Mm9qXOpP8RyNTjookw/gOCUlXSEtuZ2fUg5nrHcoqJcw==", "dependencies": { - "@vue/shared": "3.4.19" + "@vue/shared": "3.4.21" } }, "node_modules/@vue/runtime-core": { - "version": "3.4.19", - "resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.4.19.tgz", - "integrity": "sha512-/Z3tFwOrerJB/oyutmJGoYbuoadphDcJAd5jOuJE86THNZji9pYjZroQ2NFsZkTxOq0GJbb+s2kxTYToDiyZzw==", + "version": "3.4.21", + "resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.4.21.tgz", + "integrity": "sha512-pQthsuYzE1XcGZznTKn73G0s14eCJcjaLvp3/DKeYWoFacD9glJoqlNBxt3W2c5S40t6CCcpPf+jG01N3ULyrA==", "dependencies": { - "@vue/reactivity": "3.4.19", - "@vue/shared": "3.4.19" + "@vue/reactivity": "3.4.21", + "@vue/shared": "3.4.21" } }, "node_modules/@vue/runtime-dom": { - "version": "3.4.19", - "resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.4.19.tgz", - "integrity": "sha512-IyZzIDqfNCF0OyZOauL+F4yzjMPN2rPd8nhqPP2N1lBn3kYqJpPHHru+83Rkvo2lHz5mW+rEeIMEF9qY3PB94g==", + "version": "3.4.21", + "resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.4.21.tgz", + "integrity": "sha512-gvf+C9cFpevsQxbkRBS1NpU8CqxKw0ebqMvLwcGQrNpx6gqRDodqKqA+A2VZZpQ9RpK2f9yfg8VbW/EpdFUOJw==", "dependencies": { - "@vue/runtime-core": "3.4.19", - "@vue/shared": "3.4.19", + "@vue/runtime-core": "3.4.21", + "@vue/shared": "3.4.21", "csstype": "^3.1.3" } }, "node_modules/@vue/server-renderer": { - "version": "3.4.19", - "resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.4.19.tgz", - "integrity": "sha512-eAj2p0c429RZyyhtMRnttjcSToch+kTWxFPHlzGMkR28ZbF1PDlTcmGmlDxccBuqNd9iOQ7xPRPAGgPVj+YpQw==", + "version": "3.4.21", + "resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.4.21.tgz", + "integrity": "sha512-aV1gXyKSN6Rz+6kZ6kr5+Ll14YzmIbeuWe7ryJl5muJ4uwSwY/aStXTixx76TwkZFJLm1aAlA/HSWEJ4EyiMkg==", "dependencies": { - "@vue/compiler-ssr": "3.4.19", - "@vue/shared": "3.4.19" + "@vue/compiler-ssr": "3.4.21", + "@vue/shared": "3.4.21" }, "peerDependencies": { - "vue": "3.4.19" + "vue": "3.4.21" } }, "node_modules/@vue/shared": { - "version": "3.4.19", - "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.4.19.tgz", - "integrity": "sha512-/KliRRHMF6LoiThEy+4c1Z4KB/gbPrGjWwJR+crg2otgrf/egKzRaCPvJ51S5oetgsgXLfc4Rm5ZgrKHZrtMSw==" + "version": "3.4.21", + "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.4.21.tgz", + "integrity": "sha512-PuJe7vDIi6VYSinuEbUIQgMIRZGgM8e4R+G+/dQTk0X1NEdvgvvgv7m+rfmDH1gZzyA1OjjoWskvHlfRNfQf3g==" }, "node_modules/@webassemblyjs/ast": { "version": "1.11.6", @@ -3269,9 +3264,9 @@ } }, "node_modules/asciinema-player": { - "version": "3.6.4", - "resolved": "https://registry.npmjs.org/asciinema-player/-/asciinema-player-3.6.4.tgz", - "integrity": "sha512-yyMHTjoDuz82/BYPrc3J5GjOtlNI5t2VHTZWss8BmRcY/6nXv+Vilip+XzwIyRBa3/2SSn9FJIEg8bJXBc9o4w==", + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/asciinema-player/-/asciinema-player-3.7.0.tgz", + "integrity": "sha512-0RDc4j7TkjyhAwxkDe3vNqjAcizc7tubYW2VZi/06csY8iAoSC2uRvSyfNzh9ONDZu8pdf0bZJ91A84Gexb3tg==", "dependencies": { "@babel/runtime": "^7.21.0", "solid-js": "^1.3.0" @@ -3350,10 +3345,13 @@ } }, "node_modules/available-typed-arrays": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.6.tgz", - "integrity": "sha512-j1QzY8iPNPG4o4xmO3ptzpRxTciqD3MgEHtifP/YnJpIo58Xu+ne4BejlbkuaLfXn/nz6HFiw29bLpj2PNMdGg==", + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", + "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==", "dev": true, + "dependencies": { + "possible-typed-array-names": "^1.0.0" + }, "engines": { "node": ">= 0.4" }, @@ -3566,9 +3564,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001587", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001587.tgz", - "integrity": "sha512-HMFNotUmLXn71BQxg8cijvqxnIAofforZOwGsxyXJ0qugTdspUF4sPSJ2vhgprHCB996tIDzEq1ubumPDV8ULA==", + "version": "1.0.30001591", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001591.tgz", + "integrity": "sha512-PCzRMei/vXjJyL5mJtzNiUCKP59dm8Apqc3PH8gJkMnMXZGox93RbE76jHsmLwmIo6/3nsYIpJtx0O7u5PqFuQ==", "funding": [ { "type": "opencollective", @@ -3627,14 +3625,14 @@ } }, "node_modules/chart.js": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/chart.js/-/chart.js-4.4.1.tgz", - "integrity": "sha512-C74QN1bxwV1v2PEujhmKjOZ7iUM4w6BWs23Md/6aOZZSlwMzeCIDGuZay++rBgChYru7/+QFeoQW0fQoP534Dg==", + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/chart.js/-/chart.js-4.4.2.tgz", + "integrity": "sha512-6GD7iKwFpP5kbSD4MeRRRlTnQvxfQREy36uEtm1hzHzcOqwWx0YEHuspuoNlslu+nciLIB7fjjsHkUv/FzFcOg==", "dependencies": { "@kurkle/color": "^0.3.0" }, "engines": { - "pnpm": ">=7" + "pnpm": ">=8" } }, "node_modules/chartjs-adapter-dayjs-4": { @@ -3756,9 +3754,9 @@ } }, "node_modules/clippie": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/clippie/-/clippie-4.0.6.tgz", - "integrity": "sha512-E5EtOw8iMH0enuL3kBZJ+Po1nPnBD7O+HHpIaWpfWgHbHmdoOQoERrlNOcEEn2yMJQ98WqeKacouAcnRXn7oWA==" + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/clippie/-/clippie-4.0.7.tgz", + "integrity": "sha512-xmIARCRFQUoCR0kNNu4uIv5f/IFqM1fUts0vQwt1hQEdCPEqs3/dTaG38WenlWOgs3Fcn73PBYXbPIVSlOgFRw==" }, "node_modules/cliui": { "version": "7.0.4", @@ -4842,9 +4840,9 @@ } }, "node_modules/dompurify": { - "version": "3.0.8", - "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.0.8.tgz", - "integrity": "sha512-b7uwreMYL2eZhrSCRC4ahLTeZcPZxSmYfmcQGXGkXiZSNW1X85v+SDM5KsWcpivIiUBH47Ji7NtyUdpLeF5JZQ==" + "version": "3.0.9", + "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.0.9.tgz", + "integrity": "sha512-uyb4NDIvQ3hRn6NiC+SIFaP4mJ/MdXlvtunaqK9Bn6dD3RuB/1S/gasEjDHD8eiaqdSael2vBv+hOs7Y+jhYOQ==" }, "node_modules/domutils": { "version": "3.1.0", @@ -4887,19 +4885,19 @@ } }, "node_modules/electron-to-chromium": { - "version": "1.4.671", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.671.tgz", - "integrity": "sha512-UUlE+/rWbydmp+FW8xlnnTA5WNA0ZZd2XL8CuMS72rh+k4y1f8+z6yk3UQhEwqHQWj6IBdL78DwWOdGMvYfQyA==" + "version": "1.4.690", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.690.tgz", + "integrity": "sha512-+2OAGjUx68xElQhydpcbqH50hE8Vs2K6TkAeLhICYfndb67CVH0UsZaijmRUE3rHlIxU1u0jxwhgVe6fK3YANA==" }, "node_modules/elkjs": { - "version": "0.9.1", - "resolved": "https://registry.npmjs.org/elkjs/-/elkjs-0.9.1.tgz", - "integrity": "sha512-JWKDyqAdltuUcyxaECtYG6H4sqysXSLeoXuGUBfRNESMTkj+w+qdb0jya8Z/WI0jVd03WQtCGhS6FOFtlhD5FQ==" + "version": "0.9.2", + "resolved": "https://registry.npmjs.org/elkjs/-/elkjs-0.9.2.tgz", + "integrity": "sha512-2Y/RaA1pdgSHpY0YG4TYuYCD2wh97CRvu22eLG3Kz0pgQ/6KbIFTxsTnDc4MH/6hFlg2L/9qXrDMG0nMjP63iw==" }, "node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==" }, "node_modules/emojis-list": { "version": "3.0.0", @@ -4910,9 +4908,9 @@ } }, "node_modules/enhanced-resolve": { - "version": "5.15.0", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.15.0.tgz", - "integrity": "sha512-LXYT42KJ7lpIKECr2mAXIaMldcNCh/7E0KBKOu4KSfkHmP+mZmSs+8V5gBAqisWBy0OO4W5Oyys0GO1Y8KtdKg==", + "version": "5.15.1", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.15.1.tgz", + "integrity": "sha512-3d3JRbwsCLJsYgvb6NuWEG44jjPSOMuS73L/6+7BZuoKm3W+qXnSoIYVHi8dG7Qcg4inAY4jbzkZ7MnskePeDg==", "dependencies": { "graceful-fs": "^4.2.4", "tapable": "^2.2.0" @@ -4960,18 +4958,18 @@ } }, "node_modules/es-abstract": { - "version": "1.22.4", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.22.4.tgz", - "integrity": "sha512-vZYJlk2u6qHYxBOTjAeg7qUxHdNfih64Uu2J8QqWgXZ2cri0ZpJAkzDUK/q593+mvKwlxyaxr6F1Q+3LKoQRgg==", + "version": "1.22.5", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.22.5.tgz", + "integrity": "sha512-oW69R+4q2wG+Hc3KZePPZxOiisRIqfKBVo/HLx94QcJeWGU/8sZhCvc829rd1kS366vlJbzBfXf9yWwf0+Ko7w==", "dev": true, "dependencies": { "array-buffer-byte-length": "^1.0.1", "arraybuffer.prototype.slice": "^1.0.3", - "available-typed-arrays": "^1.0.6", + "available-typed-arrays": "^1.0.7", "call-bind": "^1.0.7", "es-define-property": "^1.0.0", "es-errors": "^1.3.0", - "es-set-tostringtag": "^2.0.2", + "es-set-tostringtag": "^2.0.3", "es-to-primitive": "^1.2.1", "function.prototype.name": "^1.1.6", "get-intrinsic": "^1.2.4", @@ -4979,15 +4977,15 @@ "globalthis": "^1.0.3", "gopd": "^1.0.1", "has-property-descriptors": "^1.0.2", - "has-proto": "^1.0.1", + "has-proto": "^1.0.3", "has-symbols": "^1.0.3", "hasown": "^2.0.1", "internal-slot": "^1.0.7", "is-array-buffer": "^3.0.4", "is-callable": "^1.2.7", - "is-negative-zero": "^2.0.2", + "is-negative-zero": "^2.0.3", "is-regex": "^1.1.4", - "is-shared-array-buffer": "^1.0.2", + "is-shared-array-buffer": "^1.0.3", "is-string": "^1.0.7", "is-typed-array": "^1.1.13", "is-weakref": "^1.0.2", @@ -5000,10 +4998,10 @@ "string.prototype.trim": "^1.2.8", "string.prototype.trimend": "^1.0.7", "string.prototype.trimstart": "^1.0.7", - "typed-array-buffer": "^1.0.1", - "typed-array-byte-length": "^1.0.0", - "typed-array-byte-offset": "^1.0.0", - "typed-array-length": "^1.0.4", + "typed-array-buffer": "^1.0.2", + "typed-array-byte-length": "^1.0.1", + "typed-array-byte-offset": "^1.0.2", + "typed-array-length": "^1.0.5", "unbox-primitive": "^1.0.2", "which-typed-array": "^1.1.14" }, @@ -5095,14 +5093,14 @@ "integrity": "sha512-cXLGjP0c4T3flZJKQSuziYoq7MlT+rnvfZjfp7h+I7K9BNX54kP9nyWvdbwjQ4u1iWbOL4u96fgeZLToQlZC7w==" }, "node_modules/es-set-tostringtag": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.2.tgz", - "integrity": "sha512-BuDyupZt65P9D2D2vA/zqcI3G5xRsklm5N3xCwuiy+/vKy8i0ifdsQP1sLgO4tZDSCaQUSnmC48khknGMV3D2Q==", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.3.tgz", + "integrity": "sha512-3T8uNMC3OQTHkFUsFq8r/BwAXLHvU/9O9mE0fBc/MY5iq/8H7ncvO947LmYA6ldWw9Uh8Yhf25zu6n7nML5QWQ==", "dev": true, "dependencies": { - "get-intrinsic": "^1.2.2", - "has-tostringtag": "^1.0.0", - "hasown": "^2.0.0" + "get-intrinsic": "^1.2.4", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.1" }, "engines": { "node": ">= 0.4" @@ -5220,16 +5218,16 @@ } }, "node_modules/eslint": { - "version": "8.56.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.56.0.tgz", - "integrity": "sha512-Go19xM6T9puCOWntie1/P997aXxFsOi37JIHRWI514Hc6ZnaHGKY9xFhrU65RT6CcBEzZoGG1e6Nq+DT04ZtZQ==", + "version": "8.57.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.0.tgz", + "integrity": "sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.6.1", "@eslint/eslintrc": "^2.1.4", - "@eslint/js": "8.56.0", - "@humanwhocodes/config-array": "^0.11.13", + "@eslint/js": "8.57.0", + "@humanwhocodes/config-array": "^0.11.14", "@humanwhocodes/module-importer": "^1.0.1", "@nodelib/fs.walk": "^1.2.8", "@ungap/structured-clone": "^1.2.0", @@ -5322,9 +5320,9 @@ } }, "node_modules/eslint-module-utils": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.8.0.tgz", - "integrity": "sha512-aWajIYfsqCKRDgUfjEXNN/JlrzauMuSEy5sbd7WXbtW3EH6A6MpwEh42c7qD+MqQo9QMJ6fWLAeIJynx0g6OAw==", + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.8.1.tgz", + "integrity": "sha512-rXDXR3h7cs7dy9RNpUlQf80nX31XWJEyGq1tRMo+6GsO5VmTe4UTwtmonAD4ZkAsrfMVDA2wlGJ3790Ys+D49Q==", "dev": true, "dependencies": { "debug": "^3.2.7" @@ -5415,14 +5413,14 @@ } }, "node_modules/eslint-plugin-github": { - "version": "4.10.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-github/-/eslint-plugin-github-4.10.1.tgz", - "integrity": "sha512-1AqQBockOM+m0ZUpwfjWtX0lWdX5cRi/hwJnSNvXoOmz/Hh+ULH6QFz6ENWueTWjoWpgPv0af3bj+snps6o4og==", + "version": "4.10.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-github/-/eslint-plugin-github-4.10.2.tgz", + "integrity": "sha512-F1F5aAFgi1Y5hYoTFzGQACBkw5W1hu2Fu5FSTrMlXqrojJnKl1S2pWO/rprlowRQpt+hzHhqSpsfnodJEVd5QA==", "dev": true, "dependencies": { "@github/browserslist-config": "^1.0.0", - "@typescript-eslint/eslint-plugin": "^6.0.0", - "@typescript-eslint/parser": "^6.0.0", + "@typescript-eslint/eslint-plugin": "^7.0.1", + "@typescript-eslint/parser": "^7.0.1", "aria-query": "^5.3.0", "eslint-config-prettier": ">=8.0.0", "eslint-plugin-escompat": "^3.3.3", @@ -5633,12 +5631,6 @@ "concat-map": "0.0.1" } }, - "node_modules/eslint-plugin-jsx-a11y/node_modules/emoji-regex": { - "version": "9.2.2", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", - "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", - "dev": true - }, "node_modules/eslint-plugin-jsx-a11y/node_modules/minimatch": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", @@ -5810,17 +5802,117 @@ "integrity": "sha512-WE+YlK9X9s4vf5EaYRU0Scw7WItDZStm+PapFSYlg2ABNtaQ4zIG7wEqpoUB3SlfM+SgkhgmzR0TeJOO5k3/Nw==", "dev": true }, + "node_modules/eslint-plugin-vitest/node_modules/@typescript-eslint/scope-manager": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.21.0.tgz", + "integrity": "sha512-OwLUIWZJry80O99zvqXVEioyniJMa+d2GrqpUTqi5/v5D5rOrppJVBPa0yKCblcigC0/aYAzxxqQ1B+DS2RYsg==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "6.21.0", + "@typescript-eslint/visitor-keys": "6.21.0" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/eslint-plugin-vitest/node_modules/@typescript-eslint/types": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.21.0.tgz", + "integrity": "sha512-1kFmZ1rOm5epu9NZEZm1kckCDGj5UJEf7P1kliH4LKu/RkwpsfqqGmY2OOcUs18lSlQBKLDYBOGxRVtrMN5lpg==", + "dev": true, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/eslint-plugin-vitest/node_modules/@typescript-eslint/typescript-estree": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.21.0.tgz", + "integrity": "sha512-6npJTkZcO+y2/kr+z0hc4HwNfrrP4kNYh57ek7yCNlrBjWQ1Y0OS7jiZTkgumrvkX5HkEKXFZkkdFNkaW2wmUQ==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "6.21.0", + "@typescript-eslint/visitor-keys": "6.21.0", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "minimatch": "9.0.3", + "semver": "^7.5.4", + "ts-api-utils": "^1.0.1" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/eslint-plugin-vitest/node_modules/@typescript-eslint/utils": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.21.0.tgz", + "integrity": "sha512-NfWVaC8HP9T8cbKQxHcsJBY5YE1O33+jpMwN45qzWWaPDZgLIbo12toGMWnmhvCpd3sIxkpDw3Wv1B3dYrbDQQ==", + "dev": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.4.0", + "@types/json-schema": "^7.0.12", + "@types/semver": "^7.5.0", + "@typescript-eslint/scope-manager": "6.21.0", + "@typescript-eslint/types": "6.21.0", + "@typescript-eslint/typescript-estree": "6.21.0", + "semver": "^7.5.4" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^7.0.0 || ^8.0.0" + } + }, + "node_modules/eslint-plugin-vitest/node_modules/@typescript-eslint/visitor-keys": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.21.0.tgz", + "integrity": "sha512-JJtkDduxLi9bivAB+cYOVMtbkqdPOhZ+ZI5LC47MIRrDV4Yn2o+ZnW10Nkmr28xRpSpdJ6Sm42Hjf2+REYXm0A==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "6.21.0", + "eslint-visitor-keys": "^3.4.1" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, "node_modules/eslint-plugin-vue": { - "version": "9.21.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-vue/-/eslint-plugin-vue-9.21.1.tgz", - "integrity": "sha512-XVtI7z39yOVBFJyi8Ljbn7kY9yHzznKXL02qQYn+ta63Iy4A9JFBw6o4OSB9hyD2++tVT+su9kQqetUyCCwhjw==", + "version": "9.22.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-vue/-/eslint-plugin-vue-9.22.0.tgz", + "integrity": "sha512-7wCXv5zuVnBtZE/74z4yZ0CM8AjH6bk4MQGm7hZjUC2DBppKU5ioeOk5LGSg/s9a1ZJnIsdPLJpXnu1Rc+cVHg==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", "natural-compare": "^1.4.0", "nth-check": "^2.1.1", - "postcss-selector-parser": "^6.0.13", - "semver": "^7.5.4", + "postcss-selector-parser": "^6.0.15", + "semver": "^7.6.0", "vue-eslint-parser": "^9.4.2", "xml-name-validator": "^4.0.0" }, @@ -6231,9 +6323,9 @@ } }, "node_modules/flatted": { - "version": "3.2.9", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.9.tgz", - "integrity": "sha512-36yxDn5H7OFZQla0/jFJmbIKTdZAQHngCedGxiMmpNfEZM0sdEeT+WczLQrjK6D7o2aiyLYDnkw0R3JK0Qv1RQ==", + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.1.tgz", + "integrity": "sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==", "dev": true }, "node_modules/for-each": { @@ -6681,9 +6773,9 @@ } }, "node_modules/has-proto": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz", - "integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz", + "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==", "dev": true, "engines": { "node": ">= 0.4" @@ -7218,9 +7310,9 @@ } }, "node_modules/is-negative-zero": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz", - "integrity": "sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.3.tgz", + "integrity": "sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==", "dev": true, "engines": { "node": ">= 0.4" @@ -7331,12 +7423,15 @@ } }, "node_modules/is-shared-array-buffer": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz", - "integrity": "sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.3.tgz", + "integrity": "sha512-nA2hv5XIhLR3uVzDDfCIknerhx8XUKnstuOERPNNIinXG7v9u+ohXF67vxm4TPTEPU6lm61ZkwP3c9PCB97rhg==", "dev": true, "dependencies": { - "call-bind": "^1.0.2" + "call-bind": "^1.0.7" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -8777,9 +8872,9 @@ } }, "node_modules/mini-css-extract-plugin": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-2.8.0.tgz", - "integrity": "sha512-CxmUYPFcTgET1zImteG/LZOy/4T5rTojesQXkSNBiquhydn78tfbCE9sjIjnJ/UcjNjOC1bphTCCW5rrS7cXAg==", + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-2.8.1.tgz", + "integrity": "sha512-/1HDlyFRxWIZPI1ZpgqlZ8jMw/1Dp/dl3P0L1jtZ+zVcHqwPhGwaJwKL00WVgfnBy6PWCde9W65or7IIETImuA==", "dependencies": { "schema-utils": "^4.0.0", "tapable": "^2.2.1" @@ -8827,9 +8922,9 @@ } }, "node_modules/mlly": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/mlly/-/mlly-1.5.0.tgz", - "integrity": "sha512-NPVQvAY1xr1QoVeG0cy8yUYC7FQcOx6evl/RjT1wL5FvzPnzOysoqB/jmx/DhssT2dYa8nxECLAaFI/+gVLhDQ==", + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/mlly/-/mlly-1.6.1.tgz", + "integrity": "sha512-vLgaHvaeunuOXHSmEbZ9izxPx3USsk8KCQ8iC+aTlp5sKRSoZvwhHh5L9VbKSaVC6sJDqbyohIS76E2VmHIPAA==", "dev": true, "dependencies": { "acorn": "^8.11.3", @@ -9031,9 +9126,9 @@ } }, "node_modules/npm-run-path": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.2.0.tgz", - "integrity": "sha512-W4/tgAXFqFA0iL7fk0+uQ3g7wkL8xJmx3XdK0VGb4cHW//eZTtKGvFBBoRKVTpY7n6ze4NL9ly7rgXcHufqXKg==", + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.3.0.tgz", + "integrity": "sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ==", "dev": true, "dependencies": { "path-key": "^4.0.0" @@ -9516,12 +9611,12 @@ "dev": true }, "node_modules/playwright": { - "version": "1.41.2", - "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.41.2.tgz", - "integrity": "sha512-v0bOa6H2GJChDL8pAeLa/LZC4feoAMbSQm1/jF/ySsWWoaNItvrMP7GEkvEEFyCTUYKMxjQKaTSg5up7nR6/8A==", + "version": "1.42.1", + "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.42.1.tgz", + "integrity": "sha512-PgwB03s2DZBcNRoW+1w9E+VkLBxweib6KTXM0M3tkiT4jVxKSi6PmVJ591J+0u10LUrgxB7dLRbiJqO5s2QPMg==", "dev": true, "dependencies": { - "playwright-core": "1.41.2" + "playwright-core": "1.42.1" }, "bin": { "playwright": "cli.js" @@ -9534,9 +9629,9 @@ } }, "node_modules/playwright-core": { - "version": "1.41.2", - "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.41.2.tgz", - "integrity": "sha512-VaTvwCA4Y8kxEe+kfm2+uUUw5Lubf38RxF7FpBxLPmGe5sdNkSg5e3ChEigaGrX7qdqT3pt2m/98LiyvU2x6CA==", + "version": "1.42.1", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.42.1.tgz", + "integrity": "sha512-mxz6zclokgrke9p1vtdy/COWBH+eOZgYUVVU34C73M+4j4HLlQJHtfcqiqqxpP0o8HhMkflvfbquLX5dg6wlfA==", "dev": true, "bin": { "playwright-core": "cli.js" @@ -9563,6 +9658,15 @@ "node": ">=12.0.0" } }, + "node_modules/possible-typed-array-names": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.0.0.tgz", + "integrity": "sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q==", + "dev": true, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/postcss": { "version": "8.4.35", "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.35.tgz", @@ -9640,9 +9744,9 @@ } }, "node_modules/postcss-loader": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/postcss-loader/-/postcss-loader-8.1.0.tgz", - "integrity": "sha512-AbperNcX3rlob7Ay7A/HQcrofug1caABBkopoFeOQMspZBqcqj6giYn1Bwey/0uiOPAcR+NQD0I2HC7rXzk91w==", + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/postcss-loader/-/postcss-loader-8.1.1.tgz", + "integrity": "sha512-0IeqyAsG6tYiDRCYKQJLAmgQr47DX6N7sFSWvQxt6AcupX8DIdmykuk/o/tx0Lze3ErGHJEp5OSRxrelC6+NdQ==", "dependencies": { "cosmiconfig": "^9.0.0", "jiti": "^1.20.0", @@ -10570,14 +10674,15 @@ } }, "node_modules/set-function-name": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.1.tgz", - "integrity": "sha512-tMNCiqYVkXIZgc2Hnoy2IvC/f8ezc5koaRFkCjrpWzGpCd3qbZXPzVy9MAZzK1ch/X0jvSkojys3oqJN0qCmdA==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.2.tgz", + "integrity": "sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==", "dev": true, "dependencies": { - "define-data-property": "^1.0.1", + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", "functions-have-names": "^1.2.3", - "has-property-descriptors": "^1.0.0" + "has-property-descriptors": "^1.0.2" }, "engines": { "node": ">= 0.4" @@ -10614,12 +10719,12 @@ } }, "node_modules/side-channel": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.5.tgz", - "integrity": "sha512-QcgiIWV4WV7qWExbN5llt6frQB/lBven9pqliLXfGPB+K9ZYXxDozp0wLkHS24kWCm+6YXH/f0HhnObZnZOBnQ==", + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz", + "integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==", "dev": true, "dependencies": { - "call-bind": "^1.0.6", + "call-bind": "^1.0.7", "es-errors": "^1.3.0", "get-intrinsic": "^1.2.4", "object-inspect": "^1.13.1" @@ -10860,6 +10965,16 @@ "node": ">=8" } }, + "node_modules/string-width-cjs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" + }, + "node_modules/string-width/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" + }, "node_modules/string.prototype.trim": { "version": "1.2.8", "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.8.tgz", @@ -10974,12 +11089,12 @@ } }, "node_modules/strip-literal": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/strip-literal/-/strip-literal-1.3.0.tgz", - "integrity": "sha512-PugKzOsyXpArk0yWmUwqOZecSO0GH0bPoctLcqNDH9J04pVW3lflYE0ujElBGTloevcxF5MofAOZ7C5l2b+wLg==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-literal/-/strip-literal-2.0.0.tgz", + "integrity": "sha512-f9vHgsCWBq2ugHAkGMiiYY+AYG0D/cbloKKg0nhaaaSNsujdGIpVXCNsrJpCKr5M0f4aI31mr13UjY6GAuXCKA==", "dev": true, "dependencies": { - "acorn": "^8.10.0" + "js-tokens": "^8.0.2" }, "funding": { "url": "https://github.com/sponsors/antfu" @@ -11102,41 +11217,18 @@ } }, "node_modules/stylelint/node_modules/flat-cache": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.0.tgz", - "integrity": "sha512-EryKbCE/wxpxKniQlyas6PY1I9vwtF3uCBweX+N8KYTCn3Y12RTGtQAJ/bd5pl7kxUAc8v/R3Ake/N17OZiFqA==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", + "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", "dev": true, "dependencies": { "flatted": "^3.2.9", - "keyv": "^4.5.4", - "rimraf": "^5.0.5" + "keyv": "^4.5.4" }, "engines": { "node": ">=16" } }, - "node_modules/stylelint/node_modules/glob": { - "version": "10.3.10", - "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.10.tgz", - "integrity": "sha512-fa46+tv1Ak0UPK1TOy/pZrIybNNt4HCv7SDzwyfiOZkvZLEbjsZkJBPtDHVshZjbecAoAGSC20MjLDG/qr679g==", - "dev": true, - "dependencies": { - "foreground-child": "^3.1.0", - "jackspeak": "^2.3.5", - "minimatch": "^9.0.1", - "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0", - "path-scurry": "^1.10.1" - }, - "bin": { - "glob": "dist/esm/bin.mjs" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/stylelint/node_modules/postcss-safe-parser": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/postcss-safe-parser/-/postcss-safe-parser-7.0.0.tgz", @@ -11172,24 +11264,6 @@ "node": ">=8" } }, - "node_modules/stylelint/node_modules/rimraf": { - "version": "5.0.5", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-5.0.5.tgz", - "integrity": "sha512-CqDakW+hMe/Bz202FPEymy68P+G50RfMQK+Qo5YUqc9SPipvbGjCGKd0RSKEelbsfQuw3g5NZDSrlZZAJurH1A==", - "dev": true, - "dependencies": { - "glob": "^10.3.7" - }, - "bin": { - "rimraf": "dist/esm/bin.mjs" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/stylelint/node_modules/strip-ansi": { "version": "7.1.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", @@ -11380,9 +11454,9 @@ } }, "node_modules/swagger-ui-dist": { - "version": "5.11.6", - "resolved": "https://registry.npmjs.org/swagger-ui-dist/-/swagger-ui-dist-5.11.6.tgz", - "integrity": "sha512-K5BpYuMoPpJY7NwCHIWohH6tU9o0fs1+plNT5KJ+3BBlVEh4H1CpeKJV8o91lpscVY9oqb2jmaAassnW3wVoTg==" + "version": "5.11.8", + "resolved": "https://registry.npmjs.org/swagger-ui-dist/-/swagger-ui-dist-5.11.8.tgz", + "integrity": "sha512-IfPtCPdf6opT5HXrzHO4kjL1eco0/8xJCtcs7ilhKuzatrpF2j9s+3QbOag6G3mVFKf+g+Ca5UG9DquVUs2obA==" }, "node_modules/symbol-tree": { "version": "3.2.4", @@ -11524,9 +11598,9 @@ } }, "node_modules/terser": { - "version": "5.27.1", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.27.1.tgz", - "integrity": "sha512-29wAr6UU/oQpnTw5HoadwjUZnFQXGdOfj0LjZ4sVxzqwHh/QVkvr7m8y9WoR4iN3FRitVduTc6KdjcW38Npsug==", + "version": "5.28.1", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.28.1.tgz", + "integrity": "sha512-wM+bZp54v/E9eRRGXb5ZFDvinrJIOaTapx3WUokyVGZu5ucVCK55zEgGd5Dl2fSr3jUo5sDiERErUWLY6QPFyA==", "dependencies": { "@jridgewell/source-map": "^0.3.3", "acorn": "^8.8.2", @@ -11839,12 +11913,12 @@ } }, "node_modules/typed-array-buffer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.1.tgz", - "integrity": "sha512-RSqu1UEuSlrBhHTWC8O9FnPjOduNs4M7rJ4pRKoEjtx1zUNOPN2sSXHLDX+Y2WPbHIxbvg4JFo2DNAEfPIKWoQ==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.2.tgz", + "integrity": "sha512-gEymJYKZtKXzzBzM4jqa9w6Q1Jjm7x2d+sh19AdsD4wqnMPDYyvwpsIc2Q/835kHuo3BEQ7CjelGhfTsoBb2MQ==", "dev": true, "dependencies": { - "call-bind": "^1.0.6", + "call-bind": "^1.0.7", "es-errors": "^1.3.0", "is-typed-array": "^1.1.13" }, @@ -11853,15 +11927,16 @@ } }, "node_modules/typed-array-byte-length": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.0.tgz", - "integrity": "sha512-Or/+kvLxNpeQ9DtSydonMxCx+9ZXOswtwJn17SNLvhptaXYDJvkFFP5zbfU/uLmvnBJlI4yrnXRxpdWH/M5tNA==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.1.tgz", + "integrity": "sha512-3iMJ9q0ao7WE9tWcaYKIptkNBuOIcZCCT0d4MRvuuH88fEoEH62IuQe0OtraD3ebQEoTRk8XCBoknUNc1Y67pw==", "dev": true, "dependencies": { - "call-bind": "^1.0.2", + "call-bind": "^1.0.7", "for-each": "^0.3.3", - "has-proto": "^1.0.1", - "is-typed-array": "^1.1.10" + "gopd": "^1.0.1", + "has-proto": "^1.0.3", + "is-typed-array": "^1.1.13" }, "engines": { "node": ">= 0.4" @@ -11871,16 +11946,17 @@ } }, "node_modules/typed-array-byte-offset": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.0.tgz", - "integrity": "sha512-RD97prjEt9EL8YgAgpOkf3O4IF9lhJFr9g0htQkm0rchFp/Vx7LW5Q8fSXXub7BXAODyUQohRMyOc3faCPd0hg==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.2.tgz", + "integrity": "sha512-Ous0vodHa56FviZucS2E63zkgtgrACj7omjwd/8lTEMEPFFyjfixMZ1ZXenpgCFBBt4EC1J2XsyVS2gkG0eTFA==", "dev": true, "dependencies": { - "available-typed-arrays": "^1.0.5", - "call-bind": "^1.0.2", + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.7", "for-each": "^0.3.3", - "has-proto": "^1.0.1", - "is-typed-array": "^1.1.10" + "gopd": "^1.0.1", + "has-proto": "^1.0.3", + "is-typed-array": "^1.1.13" }, "engines": { "node": ">= 0.4" @@ -11890,14 +11966,20 @@ } }, "node_modules/typed-array-length": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.4.tgz", - "integrity": "sha512-KjZypGq+I/H7HI5HlOoGHkWUUGq+Q0TPhQurLbyrVrvnKTBgzLhIJ7j6J/XTQOi0d1RjyZ0wdas8bKs2p0x3Ng==", + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.5.tgz", + "integrity": "sha512-yMi0PlwuznKHxKmcpoOdeLwxBoVPkqZxd7q2FgMkmD3bNwvF5VW0+UlUQ1k1vmktTu4Yu13Q0RIxEP8+B+wloA==", "dev": true, "dependencies": { - "call-bind": "^1.0.2", + "call-bind": "^1.0.7", "for-each": "^0.3.3", - "is-typed-array": "^1.1.9" + "gopd": "^1.0.1", + "has-proto": "^1.0.3", + "is-typed-array": "^1.1.13", + "possible-typed-array-names": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -11923,9 +12005,9 @@ "integrity": "sha512-Oy/k+tFle5NAA3J/yrrYGfvEnPVrDZ8s8/WCwjUE75k331QyKIsFss7byQ/PzBmXLY6h1moRnZbnaxWBe3I3CA==" }, "node_modules/uc.micro": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-2.0.0.tgz", - "integrity": "sha512-DffL94LsNOccVn4hyfRe5rdKa273swqeA5DJpMOeFmEn1wCDc7nAbbB0gXlgBCL7TNzeTv6G7XVWzan7iJtfig==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-2.1.0.tgz", + "integrity": "sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==", "dev": true }, "node_modules/ufo": { @@ -12108,9 +12190,9 @@ } }, "node_modules/vite": { - "version": "5.1.3", - "resolved": "https://registry.npmjs.org/vite/-/vite-5.1.3.tgz", - "integrity": "sha512-UfmUD36DKkqhi/F75RrxvPpry+9+tTkrXfMNZD+SboZqBCMsxKtO52XeGzzuh7ioz+Eo/SYDBbdb0Z7vgcDJew==", + "version": "5.1.4", + "resolved": "https://registry.npmjs.org/vite/-/vite-5.1.4.tgz", + "integrity": "sha512-n+MPqzq+d9nMVTKyewqw6kSt+R3CkvF9QAKY8obiQn8g1fwTscKxyfaYnC632HtBXAQGc1Yjomphwn1dtwGAHg==", "dev": true, "dependencies": { "esbuild": "^0.19.3", @@ -12163,9 +12245,9 @@ } }, "node_modules/vite-node": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-1.2.2.tgz", - "integrity": "sha512-1as4rDTgVWJO3n1uHmUYqq7nsFgINQ9u+mRcXpjeOMJUmviqNKjcZB7UfRZrlM7MjYXMKpuWp5oGkjaFLnjawg==", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-1.3.1.tgz", + "integrity": "sha512-azbRrqRxlWTJEVbzInZCTchx0X69M/XPTCz4H+TLvlTcR/xH/3hkRqhOakT41fMJCMzXTu4UvegkZiEoJAWvng==", "dev": true, "dependencies": { "cac": "^6.7.14", @@ -12211,9 +12293,9 @@ } }, "node_modules/vite/node_modules/rollup": { - "version": "4.11.0", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.11.0.tgz", - "integrity": "sha512-2xIbaXDXjf3u2tajvA5xROpib7eegJ9Y/uPlSFhXLNpK9ampCczXAhLEb5yLzJyG3LAdI1NWtNjDXiLyniNdjQ==", + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.12.0.tgz", + "integrity": "sha512-wz66wn4t1OHIJw3+XU7mJJQV/2NAfw5OAk6G6Hoo3zcvz/XOfQ52Vgi+AN4Uxoxi0KBBwk2g8zPrTDA4btSB/Q==", "dev": true, "dependencies": { "@types/estree": "1.0.5" @@ -12226,35 +12308,34 @@ "npm": ">=8.0.0" }, "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.11.0", - "@rollup/rollup-android-arm64": "4.11.0", - "@rollup/rollup-darwin-arm64": "4.11.0", - "@rollup/rollup-darwin-x64": "4.11.0", - "@rollup/rollup-linux-arm-gnueabihf": "4.11.0", - "@rollup/rollup-linux-arm64-gnu": "4.11.0", - "@rollup/rollup-linux-arm64-musl": "4.11.0", - "@rollup/rollup-linux-riscv64-gnu": "4.11.0", - "@rollup/rollup-linux-x64-gnu": "4.11.0", - "@rollup/rollup-linux-x64-musl": "4.11.0", - "@rollup/rollup-win32-arm64-msvc": "4.11.0", - "@rollup/rollup-win32-ia32-msvc": "4.11.0", - "@rollup/rollup-win32-x64-msvc": "4.11.0", + "@rollup/rollup-android-arm-eabi": "4.12.0", + "@rollup/rollup-android-arm64": "4.12.0", + "@rollup/rollup-darwin-arm64": "4.12.0", + "@rollup/rollup-darwin-x64": "4.12.0", + "@rollup/rollup-linux-arm-gnueabihf": "4.12.0", + "@rollup/rollup-linux-arm64-gnu": "4.12.0", + "@rollup/rollup-linux-arm64-musl": "4.12.0", + "@rollup/rollup-linux-riscv64-gnu": "4.12.0", + "@rollup/rollup-linux-x64-gnu": "4.12.0", + "@rollup/rollup-linux-x64-musl": "4.12.0", + "@rollup/rollup-win32-arm64-msvc": "4.12.0", + "@rollup/rollup-win32-ia32-msvc": "4.12.0", + "@rollup/rollup-win32-x64-msvc": "4.12.0", "fsevents": "~2.3.2" } }, "node_modules/vitest": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/vitest/-/vitest-1.2.2.tgz", - "integrity": "sha512-d5Ouvrnms3GD9USIK36KG8OZ5bEvKEkITFtnGv56HFaSlbItJuYr7hv2Lkn903+AvRAgSixiamozUVfORUekjw==", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/vitest/-/vitest-1.3.1.tgz", + "integrity": "sha512-/1QJqXs8YbCrfv/GPQ05wAZf2eakUPLPa18vkJAKE7RXOKfVHqMZZ1WlTjiwl6Gcn65M5vpNUB6EFLnEdRdEXQ==", "dev": true, "dependencies": { - "@vitest/expect": "1.2.2", - "@vitest/runner": "1.2.2", - "@vitest/snapshot": "1.2.2", - "@vitest/spy": "1.2.2", - "@vitest/utils": "1.2.2", + "@vitest/expect": "1.3.1", + "@vitest/runner": "1.3.1", + "@vitest/snapshot": "1.3.1", + "@vitest/spy": "1.3.1", + "@vitest/utils": "1.3.1", "acorn-walk": "^8.3.2", - "cac": "^6.7.14", "chai": "^4.3.10", "debug": "^4.3.4", "execa": "^8.0.1", @@ -12263,11 +12344,11 @@ "pathe": "^1.1.1", "picocolors": "^1.0.0", "std-env": "^3.5.0", - "strip-literal": "^1.3.0", + "strip-literal": "^2.0.0", "tinybench": "^2.5.1", "tinypool": "^0.8.2", "vite": "^5.0.0", - "vite-node": "1.2.2", + "vite-node": "1.3.1", "why-is-node-running": "^2.2.2" }, "bin": { @@ -12282,8 +12363,8 @@ "peerDependencies": { "@edge-runtime/vm": "*", "@types/node": "^18.0.0 || >=20.0.0", - "@vitest/browser": "^1.0.0", - "@vitest/ui": "^1.0.0", + "@vitest/browser": "1.3.1", + "@vitest/ui": "1.3.1", "happy-dom": "*", "jsdom": "*" }, @@ -12321,15 +12402,15 @@ } }, "node_modules/vue": { - "version": "3.4.19", - "resolved": "https://registry.npmjs.org/vue/-/vue-3.4.19.tgz", - "integrity": "sha512-W/7Fc9KUkajFU8dBeDluM4sRGc/aa4YJnOYck8dkjgZoXtVsn3OeTGni66FV1l3+nvPA7VBFYtPioaGKUmEADw==", + "version": "3.4.21", + "resolved": "https://registry.npmjs.org/vue/-/vue-3.4.21.tgz", + "integrity": "sha512-5hjyV/jLEIKD/jYl4cavMcnzKwjMKohureP8ejn3hhEjwhWIhWeuzL2kJAjzl/WyVsgPY56Sy4Z40C3lVshxXA==", "dependencies": { - "@vue/compiler-dom": "3.4.19", - "@vue/compiler-sfc": "3.4.19", - "@vue/runtime-dom": "3.4.19", - "@vue/server-renderer": "3.4.19", - "@vue/shared": "3.4.19" + "@vue/compiler-dom": "3.4.21", + "@vue/compiler-sfc": "3.4.21", + "@vue/runtime-dom": "3.4.21", + "@vue/server-renderer": "3.4.21", + "@vue/shared": "3.4.21" }, "peerDependencies": { "typescript": "*" @@ -12463,9 +12544,9 @@ } }, "node_modules/webpack": { - "version": "5.90.2", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.90.2.tgz", - "integrity": "sha512-ziXu8ABGr0InCMEYFnHrYweinHK2PWrMqnwdHk2oK3rRhv/1B+2FnfwYv5oD+RrknK/Pp/Hmyvu+eAsaMYhzCw==", + "version": "5.90.3", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.90.3.tgz", + "integrity": "sha512-h6uDYlWCctQRuXBs1oYpVe6sFcWedl0dpcVaTf/YF67J9bKvwJajFulMVSYKHrksMB3I/pIagRzDxwxkebuzKA==", "dependencies": { "@types/eslint-scope": "^3.7.3", "@types/estree": "^1.0.5", @@ -12964,9 +13045,12 @@ "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" }, "node_modules/yaml": { - "version": "2.3.4", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.3.4.tgz", - "integrity": "sha512-8aAvwVUSHpfEqTQ4w/KMlf3HcRdt50E5ODIQJBw1fQ5RL34xabzxtUlzTXVqc4rkZsPbvrXKWnABCD7kWSmocA==", + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.4.0.tgz", + "integrity": "sha512-j9iR8g+/t0lArF4V6NE/QCfT+CO7iLqrXAHZbJdo+LfjqP1vR8Fg5bSiaq6Q2lOD1AUEVrEVIgABvBFYojJVYQ==", + "bin": { + "yaml": "bin.mjs" + }, "engines": { "node": ">= 14" } diff --git a/package.json b/package.json index 3f0f9103c..1152bfef7 100644 --- a/package.json +++ b/package.json @@ -9,7 +9,7 @@ "@citation-js/plugin-csl": "0.7.6", "@citation-js/plugin-software-formats": "0.6.1", "@claviska/jquery-minicolors": "2.3.6", - "@github/markdown-toolbar-element": "2.2.1", + "@github/markdown-toolbar-element": "2.2.3", "@github/relative-time-element": "4.3.1", "@github/text-expander-element": "2.6.1", "@mcaptcha/vanilla-glue": "0.1.0-alpha-3", @@ -17,11 +17,11 @@ "@webcomponents/custom-elements": "1.6.0", "add-asset-webpack-plugin": "2.0.1", "ansi_up": "6.0.2", - "asciinema-player": "3.6.4", - "chart.js": "4.4.1", + "asciinema-player": "3.7.0", + "chart.js": "4.4.2", "chartjs-adapter-dayjs-4": "1.0.4", "chartjs-plugin-zoom": "2.0.1", - "clippie": "4.0.6", + "clippie": "4.0.7", "css-loader": "6.10.0", "css-variables-parser": "1.0.1", "dayjs": "1.11.10", @@ -36,16 +36,16 @@ "katex": "0.16.9", "license-checker-webpack-plugin": "0.2.1", "mermaid": "10.8.0", - "mini-css-extract-plugin": "2.8.0", + "mini-css-extract-plugin": "2.8.1", "minimatch": "9.0.3", "monaco-editor": "0.46.0", "monaco-editor-webpack-plugin": "7.1.0", "pdfobject": "2.3.0", "postcss": "8.4.35", - "postcss-loader": "8.1.0", + "postcss-loader": "8.1.1", "pretty-ms": "9.0.0", "sortablejs": "1.15.2", - "swagger-ui-dist": "5.11.6", + "swagger-ui-dist": "5.11.8", "tailwindcss": "3.4.1", "throttle-debounce": "5.0.0", "tinycolor2": "1.6.0", @@ -53,25 +53,25 @@ "toastify-js": "1.12.0", "tributejs": "5.1.3", "uint8-to-base64": "0.2.0", - "vue": "3.4.19", + "vue": "3.4.21", "vue-bar-graph": "2.0.0", "vue-chartjs": "5.3.0", "vue-loader": "17.4.2", "vue3-calendar-heatmap": "2.0.5", - "webpack": "5.90.2", + "webpack": "5.90.3", "webpack-cli": "5.1.4", "wrap-ansi": "9.0.0" }, "devDependencies": { "@eslint-community/eslint-plugin-eslint-comments": "4.1.0", - "@playwright/test": "1.41.2", + "@playwright/test": "1.42.1", "@stoplight/spectral-cli": "6.11.0", - "@stylistic/eslint-plugin-js": "1.6.2", - "@stylistic/stylelint-plugin": "2.0.0", + "@stylistic/eslint-plugin-js": "1.6.3", + "@stylistic/stylelint-plugin": "2.1.0", "@vitejs/plugin-vue": "5.0.4", - "eslint": "8.56.0", + "eslint": "8.57.0", "eslint-plugin-array-func": "4.0.0", - "eslint-plugin-github": "4.10.1", + "eslint-plugin-github": "4.10.2", "eslint-plugin-i": "2.29.1", "eslint-plugin-jquery": "1.5.1", "eslint-plugin-no-jquery": "2.7.0", @@ -81,7 +81,7 @@ "eslint-plugin-unicorn": "51.0.1", "eslint-plugin-vitest": "0.3.22", "eslint-plugin-vitest-globals": "1.4.0", - "eslint-plugin-vue": "9.21.1", + "eslint-plugin-vue": "9.22.0", "eslint-plugin-vue-scoped-css": "2.7.2", "eslint-plugin-wc": "2.0.4", "jsdom": "24.0.0", @@ -93,7 +93,7 @@ "svgo": "3.2.0", "updates": "15.1.2", "vite-string-plugin": "1.1.5", - "vitest": "1.2.2" + "vitest": "1.3.1" }, "browserslist": [ "defaults" diff --git a/poetry.lock b/poetry.lock index 4cb58c6ef..46520fba3 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 1.7.1 and should not be changed by hand. +# This file is automatically @generated by Poetry 1.8.2 and should not be changed by hand. [[package]] name = "click" @@ -27,12 +27,12 @@ files = [ [[package]] name = "cssbeautifier" -version = "1.14.11" +version = "1.15.1" description = "CSS unobfuscator and beautifier." optional = false python-versions = "*" files = [ - {file = "cssbeautifier-1.14.11.tar.gz", hash = "sha256:40544c2b62bbcb64caa5e7f37a02df95654e5ce1bcacadac4ca1f3dc89c31513"}, + {file = "cssbeautifier-1.15.1.tar.gz", hash = "sha256:9f7064362aedd559c55eeecf6b6bed65e05f33488dcbe39044f0403c26e1c006"}, ] [package.dependencies] @@ -67,13 +67,12 @@ tqdm = ">=4.62.2,<5.0.0" [[package]] name = "editorconfig" -version = "0.12.3" +version = "0.12.4" description = "EditorConfig File Locator and Interpreter for Python" optional = false python-versions = "*" files = [ - {file = "EditorConfig-0.12.3-py3-none-any.whl", hash = "sha256:6b0851425aa875b08b16789ee0eeadbd4ab59666e9ebe728e526314c4a2e52c1"}, - {file = "EditorConfig-0.12.3.tar.gz", hash = "sha256:57f8ce78afcba15c8b18d46b5170848c88d56fd38f05c2ec60dbbfcb8996e89e"}, + {file = "EditorConfig-0.12.4.tar.gz", hash = "sha256:24857fa1793917dd9ccf0c7810a07e05404ce9b823521c7dce22a4fb5d125f80"}, ] [[package]] @@ -100,12 +99,12 @@ files = [ [[package]] name = "jsbeautifier" -version = "1.14.11" +version = "1.15.1" description = "JavaScript unobfuscator and beautifier." optional = false python-versions = "*" files = [ - {file = "jsbeautifier-1.14.11.tar.gz", hash = "sha256:6b632581ea60dd1c133cd25a48ad187b4b91f526623c4b0fb5443ef805250505"}, + {file = "jsbeautifier-1.15.1.tar.gz", hash = "sha256:ebd733b560704c602d744eafc839db60a1ee9326e30a2a80c4adb8718adc1b24"}, ] [package.dependencies] @@ -114,13 +113,13 @@ six = ">=1.13.0" [[package]] name = "json5" -version = "0.9.14" +version = "0.9.18" description = "A Python implementation of the JSON5 data format." optional = false -python-versions = "*" +python-versions = ">=3.8" files = [ - {file = "json5-0.9.14-py2.py3-none-any.whl", hash = "sha256:740c7f1b9e584a468dbb2939d8d458db3427f2c93ae2139d05f47e453eae964f"}, - {file = "json5-0.9.14.tar.gz", hash = "sha256:9ed66c3a6ca3510a976a9ef9b8c0787de24802724ab1860bc0153c7fdd589b02"}, + {file = "json5-0.9.18-py2.py3-none-any.whl", hash = "sha256:3f20193ff8dfdec6ab114b344e7ac5d76fac453c8bab9bdfe1460d1d528ec393"}, + {file = "json5-0.9.18.tar.gz", hash = "sha256:ecb8ac357004e3522fb989da1bf08b146011edbd14fdffae6caad3bd68493467"}, ] [package.extras] @@ -322,13 +321,13 @@ files = [ [[package]] name = "tqdm" -version = "4.66.1" +version = "4.66.2" description = "Fast, Extensible Progress Meter" optional = false python-versions = ">=3.7" files = [ - {file = "tqdm-4.66.1-py3-none-any.whl", hash = "sha256:d302b3c5b53d47bce91fea46679d9c3c6508cf6332229aa1e7d8653723793386"}, - {file = "tqdm-4.66.1.tar.gz", hash = "sha256:d88e651f9db8d8551a62556d3cff9e3034274ca5d66e93197cf2490e2dcb69c7"}, + {file = "tqdm-4.66.2-py3-none-any.whl", hash = "sha256:1ee4f8a893eb9bef51c6e35730cebf234d5d0b6bd112b0271e10ed7c24a02bd9"}, + {file = "tqdm-4.66.2.tar.gz", hash = "sha256:6cd52cdf0fef0e0f543299cfc96fec90d7b8a7e88745f411ec33eb44d5ed3531"}, ] [package.dependencies] @@ -342,13 +341,13 @@ telegram = ["requests"] [[package]] name = "yamllint" -version = "1.35.0" +version = "1.35.1" description = "A linter for YAML files." optional = false python-versions = ">=3.8" files = [ - {file = "yamllint-1.35.0-py3-none-any.whl", hash = "sha256:601b0adaaac6d9bacb16a2e612e7ee8d23caf941ceebf9bfe2cff0f196266004"}, - {file = "yamllint-1.35.0.tar.gz", hash = "sha256:9bc99c3e9fe89b4c6ee26e17aa817cf2d14390de6577cb6e2e6ed5f72120c835"}, + {file = "yamllint-1.35.1-py3-none-any.whl", hash = "sha256:2e16e504bb129ff515b37823b472750b36b6de07963bd74b307341ef5ad8bdc3"}, + {file = "yamllint-1.35.1.tar.gz", hash = "sha256:7a003809f88324fd2c877734f2d575ee7881dd9043360657cc8049c809eba6cd"}, ] [package.dependencies] @@ -360,5 +359,5 @@ dev = ["doc8", "flake8", "flake8-import-order", "rstcheck[sphinx]", "sphinx"] [metadata] lock-version = "2.0" -python-versions = "^3.8" -content-hash = "ba1c2c4235872f67354b5f52aa5bf0cd616354961530d9dc907f9fba28cc1ece" +python-versions = "^3.10" +content-hash = "cd2ff218e9f27a464dfbc8ec2387824a90f4360e04c3f2e58cc375796b7df33a" diff --git a/pyproject.toml b/pyproject.toml index ef763da24..323307c1d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -5,11 +5,11 @@ description = "" authors = [] [tool.poetry.dependencies] -python = "^3.8" +python = "^3.10" [tool.poetry.group.dev.dependencies] djlint = "1.34.1" -yamllint = "1.35.0" +yamllint = "1.35.1" [tool.djlint] profile="golang" diff --git a/routers/api/actions/artifact.pb.go b/routers/api/actions/artifact.pb.go new file mode 100644 index 000000000..590eda9fb --- /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 000000000..c68e5d030 --- /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.go b/routers/api/actions/artifacts.go index 9fbd3f045..d530e9cee 100644 --- a/routers/api/actions/artifacts.go +++ b/routers/api/actions/artifacts.go @@ -71,7 +71,6 @@ import ( "code.gitea.io/gitea/models/actions" "code.gitea.io/gitea/models/db" - "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/json" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/setting" @@ -80,6 +79,7 @@ import ( "code.gitea.io/gitea/modules/web" web_types "code.gitea.io/gitea/modules/web/types" actions_service "code.gitea.io/gitea/services/actions" + "code.gitea.io/gitea/services/context" ) const artifactRouteBase = "/_apis/pipelines/workflows/{run_id}/artifacts" diff --git a/routers/api/actions/artifacts_chunks.go b/routers/api/actions/artifacts_chunks.go index 0713c8bba..3a81724b3 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,6 +23,52 @@ import ( "code.gitea.io/gitea/modules/storage" ) +func saveUploadChunkBase(st storage.ObjectStorage, ctx *ArtifactContext, + artifact *actions.ActionArtifact, + contentSize, runID, start, end, length int64, checkMd5 bool, +) (int64, error) { + // build chunk store path + storagePath := fmt.Sprintf("tmp%d/%d-%d-%d-%d.chunk", runID, runID, artifact.ID, start, end) + 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) + } + 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, checkErr + } + log.Info("[artifact] save chunk %s, size: %d, artifact id: %d, start: %d, end: %d", + storagePath, contentSize, artifact.ID, start, end) + // return chunk total size + return length, nil +} + func saveUploadChunk(st storage.ObjectStorage, ctx *ArtifactContext, artifact *actions.ActionArtifact, contentSize, runID int64, @@ -29,33 +80,15 @@ func saveUploadChunk(st storage.ObjectStorage, ctx *ArtifactContext, 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) - // 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 { - if err := st.Delete(storagePath); err != nil { - log.Error("Error deleting chunk: %s, %v", storagePath, err) - } - return -1, fmt.Errorf("md5 not match") - } - log.Info("[artifact] save chunk %s, size: %d, artifact id: %d, start: %d, end: %d", - storagePath, contentSize, artifact.ID, start, end) - // return chunk total size - return length, nil + 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 { @@ -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 381e7eb16..aaf89ef40 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 000000000..8300989c7 --- /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/alpine/alpine.go b/routers/api/packages/alpine/alpine.go index 3701fc97c..cf0fe6c07 100644 --- a/routers/api/packages/alpine/alpine.go +++ b/routers/api/packages/alpine/alpine.go @@ -15,12 +15,12 @@ import ( packages_model "code.gitea.io/gitea/models/packages" alpine_model "code.gitea.io/gitea/models/packages/alpine" - "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/json" packages_module "code.gitea.io/gitea/modules/packages" alpine_module "code.gitea.io/gitea/modules/packages/alpine" "code.gitea.io/gitea/modules/util" "code.gitea.io/gitea/routers/api/packages/helper" + "code.gitea.io/gitea/services/context" packages_service "code.gitea.io/gitea/services/packages" alpine_service "code.gitea.io/gitea/services/packages/alpine" ) diff --git a/routers/api/packages/api.go b/routers/api/packages/api.go index d990ebb56..5e3cbac8f 100644 --- a/routers/api/packages/api.go +++ b/routers/api/packages/api.go @@ -10,7 +10,6 @@ import ( auth_model "code.gitea.io/gitea/models/auth" "code.gitea.io/gitea/models/perm" - "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/web" @@ -36,7 +35,7 @@ import ( "code.gitea.io/gitea/routers/api/packages/swift" "code.gitea.io/gitea/routers/api/packages/vagrant" "code.gitea.io/gitea/services/auth" - context_service "code.gitea.io/gitea/services/context" + "code.gitea.io/gitea/services/context" ) func reqPackageAccess(accessMode perm.AccessMode) func(ctx *context.Context) { @@ -642,7 +641,7 @@ func CommonRoutes() *web.Route { }) }) }, reqPackageAccess(perm.AccessModeRead)) - }, context_service.UserAssignmentWeb(), context.PackageAssignment()) + }, context.UserAssignmentWeb(), context.PackageAssignment()) return r } @@ -812,7 +811,7 @@ func ContainerRoutes() *web.Route { ctx.Status(http.StatusNotFound) }) - }, container.ReqContainerAccess, context_service.UserAssignmentWeb(), context.PackageAssignment(), reqPackageAccess(perm.AccessModeRead)) + }, container.ReqContainerAccess, context.UserAssignmentWeb(), context.PackageAssignment(), reqPackageAccess(perm.AccessModeRead)) return r } diff --git a/routers/api/packages/cargo/cargo.go b/routers/api/packages/cargo/cargo.go index 8f1e965c9..140e532ef 100644 --- a/routers/api/packages/cargo/cargo.go +++ b/routers/api/packages/cargo/cargo.go @@ -12,14 +12,15 @@ import ( "code.gitea.io/gitea/models/db" packages_model "code.gitea.io/gitea/models/packages" - "code.gitea.io/gitea/modules/context" "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" "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/util" "code.gitea.io/gitea/routers/api/packages/helper" + "code.gitea.io/gitea/services/context" "code.gitea.io/gitea/services/convert" packages_service "code.gitea.io/gitea/services/packages" cargo_service "code.gitea.io/gitea/services/packages/cargo" @@ -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 f1e9ae12d..b49f4e9d0 100644 --- a/routers/api/packages/chef/chef.go +++ b/routers/api/packages/chef/chef.go @@ -15,12 +15,13 @@ import ( "code.gitea.io/gitea/models/db" packages_model "code.gitea.io/gitea/models/packages" - "code.gitea.io/gitea/modules/context" + "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" "code.gitea.io/gitea/modules/util" "code.gitea.io/gitea/routers/api/packages/helper" + "code.gitea.io/gitea/services/context" packages_service "code.gitea.io/gitea/services/packages" ) @@ -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 0551093cd..a045da40d 100644 --- a/routers/api/packages/composer/composer.go +++ b/routers/api/packages/composer/composer.go @@ -14,12 +14,13 @@ import ( "code.gitea.io/gitea/models/db" packages_model "code.gitea.io/gitea/models/packages" - "code.gitea.io/gitea/modules/context" + "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" "code.gitea.io/gitea/modules/util" "code.gitea.io/gitea/routers/api/packages/helper" + "code.gitea.io/gitea/services/context" "code.gitea.io/gitea/services/convert" packages_service "code.gitea.io/gitea/services/packages" @@ -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/conan/conan.go b/routers/api/packages/conan/conan.go index 4bf13222d..c45e085a4 100644 --- a/routers/api/packages/conan/conan.go +++ b/routers/api/packages/conan/conan.go @@ -15,13 +15,13 @@ import ( packages_model "code.gitea.io/gitea/models/packages" conan_model "code.gitea.io/gitea/models/packages/conan" "code.gitea.io/gitea/modules/container" - "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/json" "code.gitea.io/gitea/modules/log" packages_module "code.gitea.io/gitea/modules/packages" conan_module "code.gitea.io/gitea/modules/packages/conan" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/routers/api/packages/helper" + "code.gitea.io/gitea/services/context" notify_service "code.gitea.io/gitea/services/notify" packages_service "code.gitea.io/gitea/services/packages" ) diff --git a/routers/api/packages/conan/search.go b/routers/api/packages/conan/search.go index 2bcf9df16..7370c702c 100644 --- a/routers/api/packages/conan/search.go +++ b/routers/api/packages/conan/search.go @@ -9,9 +9,9 @@ import ( conan_model "code.gitea.io/gitea/models/packages/conan" user_model "code.gitea.io/gitea/models/user" - "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/json" conan_module "code.gitea.io/gitea/modules/packages/conan" + "code.gitea.io/gitea/services/context" ) // SearchResult contains the found recipe names diff --git a/routers/api/packages/conda/conda.go b/routers/api/packages/conda/conda.go index 0bee7baa9..30c80fc15 100644 --- a/routers/api/packages/conda/conda.go +++ b/routers/api/packages/conda/conda.go @@ -12,13 +12,13 @@ import ( packages_model "code.gitea.io/gitea/models/packages" conda_model "code.gitea.io/gitea/models/packages/conda" - "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/json" "code.gitea.io/gitea/modules/log" packages_module "code.gitea.io/gitea/modules/packages" conda_module "code.gitea.io/gitea/modules/packages/conda" "code.gitea.io/gitea/modules/util" "code.gitea.io/gitea/routers/api/packages/helper" + "code.gitea.io/gitea/services/context" packages_service "code.gitea.io/gitea/services/packages" "github.com/dsnet/compress/bzip2" diff --git a/routers/api/packages/container/container.go b/routers/api/packages/container/container.go index 8621242da..e51976614 100644 --- a/routers/api/packages/container/container.go +++ b/routers/api/packages/container/container.go @@ -17,7 +17,6 @@ import ( packages_model "code.gitea.io/gitea/models/packages" container_model "code.gitea.io/gitea/models/packages/container" user_model "code.gitea.io/gitea/models/user" - "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/json" "code.gitea.io/gitea/modules/log" packages_module "code.gitea.io/gitea/modules/packages" @@ -25,6 +24,7 @@ import ( "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/util" "code.gitea.io/gitea/routers/api/packages/helper" + "code.gitea.io/gitea/services/context" packages_service "code.gitea.io/gitea/services/packages" container_service "code.gitea.io/gitea/services/packages/container" diff --git a/routers/api/packages/cran/cran.go b/routers/api/packages/cran/cran.go index ae43df7c9..2cec75294 100644 --- a/routers/api/packages/cran/cran.go +++ b/routers/api/packages/cran/cran.go @@ -13,11 +13,11 @@ import ( packages_model "code.gitea.io/gitea/models/packages" cran_model "code.gitea.io/gitea/models/packages/cran" - "code.gitea.io/gitea/modules/context" packages_module "code.gitea.io/gitea/modules/packages" cran_module "code.gitea.io/gitea/modules/packages/cran" "code.gitea.io/gitea/modules/util" "code.gitea.io/gitea/routers/api/packages/helper" + "code.gitea.io/gitea/services/context" packages_service "code.gitea.io/gitea/services/packages" ) diff --git a/routers/api/packages/debian/debian.go b/routers/api/packages/debian/debian.go index 379137e87..241de3ac5 100644 --- a/routers/api/packages/debian/debian.go +++ b/routers/api/packages/debian/debian.go @@ -13,11 +13,11 @@ import ( "code.gitea.io/gitea/models/db" packages_model "code.gitea.io/gitea/models/packages" - "code.gitea.io/gitea/modules/context" packages_module "code.gitea.io/gitea/modules/packages" debian_module "code.gitea.io/gitea/modules/packages/debian" "code.gitea.io/gitea/modules/util" "code.gitea.io/gitea/routers/api/packages/helper" + "code.gitea.io/gitea/services/context" notify_service "code.gitea.io/gitea/services/notify" packages_service "code.gitea.io/gitea/services/packages" debian_service "code.gitea.io/gitea/services/packages/debian" diff --git a/routers/api/packages/generic/generic.go b/routers/api/packages/generic/generic.go index 30854335c..b65870a8d 100644 --- a/routers/api/packages/generic/generic.go +++ b/routers/api/packages/generic/generic.go @@ -10,10 +10,10 @@ import ( "strings" packages_model "code.gitea.io/gitea/models/packages" - "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/log" packages_module "code.gitea.io/gitea/modules/packages" "code.gitea.io/gitea/routers/api/packages/helper" + "code.gitea.io/gitea/services/context" packages_service "code.gitea.io/gitea/services/packages" ) diff --git a/routers/api/packages/goproxy/goproxy.go b/routers/api/packages/goproxy/goproxy.go index 18e0074ab..d658066bb 100644 --- a/routers/api/packages/goproxy/goproxy.go +++ b/routers/api/packages/goproxy/goproxy.go @@ -12,11 +12,12 @@ import ( "time" packages_model "code.gitea.io/gitea/models/packages" - "code.gitea.io/gitea/modules/context" + "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" "code.gitea.io/gitea/routers/api/packages/helper" + "code.gitea.io/gitea/services/context" packages_service "code.gitea.io/gitea/services/packages" ) @@ -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 a8daa69dc..efdb83ec0 100644 --- a/routers/api/packages/helm/helm.go +++ b/routers/api/packages/helm/helm.go @@ -13,14 +13,15 @@ import ( "time" packages_model "code.gitea.io/gitea/models/packages" - "code.gitea.io/gitea/modules/context" "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" "code.gitea.io/gitea/modules/util" "code.gitea.io/gitea/routers/api/packages/helper" + "code.gitea.io/gitea/services/context" packages_service "code.gitea.io/gitea/services/packages" "gopkg.in/yaml.v3" @@ -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/helper/helper.go b/routers/api/packages/helper/helper.go index aadb10376..cdb64109a 100644 --- a/routers/api/packages/helper/helper.go +++ b/routers/api/packages/helper/helper.go @@ -10,9 +10,9 @@ import ( "net/url" packages_model "code.gitea.io/gitea/models/packages" - "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/services/context" ) // LogAndProcessError logs an error and calls a custom callback with the processed error message. diff --git a/routers/api/packages/maven/maven.go b/routers/api/packages/maven/maven.go index 5106395eb..27f0578db 100644 --- a/routers/api/packages/maven/maven.go +++ b/routers/api/packages/maven/maven.go @@ -20,12 +20,12 @@ import ( "strings" packages_model "code.gitea.io/gitea/models/packages" - "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/json" "code.gitea.io/gitea/modules/log" packages_module "code.gitea.io/gitea/modules/packages" maven_module "code.gitea.io/gitea/modules/packages/maven" "code.gitea.io/gitea/routers/api/packages/helper" + "code.gitea.io/gitea/services/context" packages_service "code.gitea.io/gitea/services/packages" ) diff --git a/routers/api/packages/npm/api.go b/routers/api/packages/npm/api.go index 847087488..f8e839c42 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 170edfbe1..84acfffae 100644 --- a/routers/api/packages/npm/npm.go +++ b/routers/api/packages/npm/npm.go @@ -17,12 +17,13 @@ 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/context" + "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" "code.gitea.io/gitea/modules/util" "code.gitea.io/gitea/routers/api/packages/helper" + "code.gitea.io/gitea/services/context" packages_service "code.gitea.io/gitea/services/packages" "github.com/hashicorp/go-version" @@ -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 a63df2a1f..0eb817c1a 100644 --- a/routers/api/packages/nuget/nuget.go +++ b/routers/api/packages/nuget/nuget.go @@ -17,13 +17,14 @@ import ( "code.gitea.io/gitea/models/db" packages_model "code.gitea.io/gitea/models/packages" nuget_model "code.gitea.io/gitea/models/packages/nuget" - "code.gitea.io/gitea/modules/context" "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" "code.gitea.io/gitea/modules/util" "code.gitea.io/gitea/routers/api/packages/helper" + "code.gitea.io/gitea/services/context" packages_service "code.gitea.io/gitea/services/packages" ) @@ -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/pub/pub.go b/routers/api/packages/pub/pub.go index 1f605c6c9..f87df52a2 100644 --- a/routers/api/packages/pub/pub.go +++ b/routers/api/packages/pub/pub.go @@ -14,7 +14,6 @@ import ( "time" packages_model "code.gitea.io/gitea/models/packages" - "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/json" "code.gitea.io/gitea/modules/log" packages_module "code.gitea.io/gitea/modules/packages" @@ -22,6 +21,7 @@ import ( "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/util" "code.gitea.io/gitea/routers/api/packages/helper" + "code.gitea.io/gitea/services/context" packages_service "code.gitea.io/gitea/services/packages" ) diff --git a/routers/api/packages/pypi/pypi.go b/routers/api/packages/pypi/pypi.go index 5718b1203..7824db182 100644 --- a/routers/api/packages/pypi/pypi.go +++ b/routers/api/packages/pypi/pypi.go @@ -12,12 +12,12 @@ import ( "strings" packages_model "code.gitea.io/gitea/models/packages" - "code.gitea.io/gitea/modules/context" packages_module "code.gitea.io/gitea/modules/packages" pypi_module "code.gitea.io/gitea/modules/packages/pypi" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/validation" "code.gitea.io/gitea/routers/api/packages/helper" + "code.gitea.io/gitea/services/context" packages_service "code.gitea.io/gitea/services/packages" ) diff --git a/routers/api/packages/rpm/rpm.go b/routers/api/packages/rpm/rpm.go index 5d0668055..4de361c21 100644 --- a/routers/api/packages/rpm/rpm.go +++ b/routers/api/packages/rpm/rpm.go @@ -13,13 +13,13 @@ import ( "code.gitea.io/gitea/models/db" packages_model "code.gitea.io/gitea/models/packages" - "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/json" packages_module "code.gitea.io/gitea/modules/packages" rpm_module "code.gitea.io/gitea/modules/packages/rpm" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/util" "code.gitea.io/gitea/routers/api/packages/helper" + "code.gitea.io/gitea/services/context" notify_service "code.gitea.io/gitea/services/notify" packages_service "code.gitea.io/gitea/services/packages" rpm_service "code.gitea.io/gitea/services/packages/rpm" diff --git a/routers/api/packages/rubygems/rubygems.go b/routers/api/packages/rubygems/rubygems.go index 01fd4dad6..d2fbcd01f 100644 --- a/routers/api/packages/rubygems/rubygems.go +++ b/routers/api/packages/rubygems/rubygems.go @@ -13,11 +13,12 @@ import ( "strings" packages_model "code.gitea.io/gitea/models/packages" - "code.gitea.io/gitea/modules/context" + "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" "code.gitea.io/gitea/routers/api/packages/helper" + "code.gitea.io/gitea/services/context" packages_service "code.gitea.io/gitea/services/packages" ) @@ -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 6ad289e51..a9da3ea9c 100644 --- a/routers/api/packages/swift/swift.go +++ b/routers/api/packages/swift/swift.go @@ -13,14 +13,15 @@ import ( "strings" packages_model "code.gitea.io/gitea/models/packages" - "code.gitea.io/gitea/modules/context" "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" "code.gitea.io/gitea/modules/util" "code.gitea.io/gitea/routers/api/packages/helper" + "code.gitea.io/gitea/services/context" packages_service "code.gitea.io/gitea/services/packages" "github.com/hashicorp/go-version" @@ -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/packages/vagrant/vagrant.go b/routers/api/packages/vagrant/vagrant.go index af9cd08a6..98a81da36 100644 --- a/routers/api/packages/vagrant/vagrant.go +++ b/routers/api/packages/vagrant/vagrant.go @@ -12,11 +12,11 @@ import ( "strings" packages_model "code.gitea.io/gitea/models/packages" - "code.gitea.io/gitea/modules/context" packages_module "code.gitea.io/gitea/modules/packages" vagrant_module "code.gitea.io/gitea/modules/packages/vagrant" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/routers/api/packages/helper" + "code.gitea.io/gitea/services/context" packages_service "code.gitea.io/gitea/services/packages" "github.com/hashicorp/go-version" diff --git a/routers/api/v1/activitypub/person.go b/routers/api/v1/activitypub/person.go index cad5032d1..995a148f0 100644 --- a/routers/api/v1/activitypub/person.go +++ b/routers/api/v1/activitypub/person.go @@ -9,9 +9,9 @@ import ( "strings" "code.gitea.io/gitea/modules/activitypub" - "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/services/context" ap "github.com/go-ap/activitypub" "github.com/go-ap/jsonld" diff --git a/routers/api/v1/activitypub/reqsignature.go b/routers/api/v1/activitypub/reqsignature.go index 3f60ed777..59ebc74b8 100644 --- a/routers/api/v1/activitypub/reqsignature.go +++ b/routers/api/v1/activitypub/reqsignature.go @@ -13,9 +13,9 @@ import ( "net/url" "code.gitea.io/gitea/modules/activitypub" - gitea_context "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/httplib" "code.gitea.io/gitea/modules/setting" + gitea_context "code.gitea.io/gitea/services/context" ap "github.com/go-ap/activitypub" "github.com/go-fed/httpsig" diff --git a/routers/api/v1/admin/adopt.go b/routers/api/v1/admin/adopt.go index bf030eb22..a4708fe03 100644 --- a/routers/api/v1/admin/adopt.go +++ b/routers/api/v1/admin/adopt.go @@ -8,9 +8,9 @@ import ( repo_model "code.gitea.io/gitea/models/repo" user_model "code.gitea.io/gitea/models/user" - "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/util" "code.gitea.io/gitea/routers/api/v1/utils" + "code.gitea.io/gitea/services/context" repo_service "code.gitea.io/gitea/services/repository" ) diff --git a/routers/api/v1/admin/cron.go b/routers/api/v1/admin/cron.go index cc8c6c9e2..e1ca6048c 100644 --- a/routers/api/v1/admin/cron.go +++ b/routers/api/v1/admin/cron.go @@ -6,11 +6,11 @@ package admin import ( "net/http" - "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/log" "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/cron" ) diff --git a/routers/api/v1/admin/email.go b/routers/api/v1/admin/email.go index 5914215bc..ba963e9f6 100644 --- a/routers/api/v1/admin/email.go +++ b/routers/api/v1/admin/email.go @@ -7,9 +7,9 @@ import ( "net/http" user_model "code.gitea.io/gitea/models/user" - "code.gitea.io/gitea/modules/context" api "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/routers/api/v1/utils" + "code.gitea.io/gitea/services/context" "code.gitea.io/gitea/services/convert" ) diff --git a/routers/api/v1/admin/hooks.go b/routers/api/v1/admin/hooks.go index 8a095a7de..4c168b55b 100644 --- a/routers/api/v1/admin/hooks.go +++ b/routers/api/v1/admin/hooks.go @@ -8,12 +8,13 @@ import ( "net/http" "code.gitea.io/gitea/models/webhook" - "code.gitea.io/gitea/modules/context" + "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" "code.gitea.io/gitea/modules/web" "code.gitea.io/gitea/routers/api/v1/utils" + "code.gitea.io/gitea/services/context" webhook_service "code.gitea.io/gitea/services/webhook" ) @@ -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/admin/org.go b/routers/api/v1/admin/org.go index bf68942a9..a5c299bbf 100644 --- a/routers/api/v1/admin/org.go +++ b/routers/api/v1/admin/org.go @@ -10,10 +10,10 @@ import ( "code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/organization" user_model "code.gitea.io/gitea/models/user" - "code.gitea.io/gitea/modules/context" api "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/web" "code.gitea.io/gitea/routers/api/v1/utils" + "code.gitea.io/gitea/services/context" "code.gitea.io/gitea/services/convert" ) diff --git a/routers/api/v1/admin/repo.go b/routers/api/v1/admin/repo.go index a4895f260..c119d5390 100644 --- a/routers/api/v1/admin/repo.go +++ b/routers/api/v1/admin/repo.go @@ -4,10 +4,10 @@ package admin import ( - "code.gitea.io/gitea/modules/context" api "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/web" "code.gitea.io/gitea/routers/api/v1/repo" + "code.gitea.io/gitea/services/context" ) // CreateRepo api for creating a repository diff --git a/routers/api/v1/admin/runners.go b/routers/api/v1/admin/runners.go index c0d936443..329242d9f 100644 --- a/routers/api/v1/admin/runners.go +++ b/routers/api/v1/admin/runners.go @@ -4,8 +4,8 @@ package admin import ( - "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/routers/api/v1/shared" + "code.gitea.io/gitea/services/context" ) // https://docs.github.com/en/rest/actions/self-hosted-runners?apiVersion=2022-11-28#create-a-registration-token-for-an-organization diff --git a/routers/api/v1/admin/user.go b/routers/api/v1/admin/user.go index 2ce7651a0..64315108b 100644 --- a/routers/api/v1/admin/user.go +++ b/routers/api/v1/admin/user.go @@ -15,7 +15,6 @@ import ( "code.gitea.io/gitea/models/db" user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/auth/password" - "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/optional" "code.gitea.io/gitea/modules/setting" @@ -25,6 +24,7 @@ import ( "code.gitea.io/gitea/routers/api/v1/user" "code.gitea.io/gitea/routers/api/v1/utils" asymkey_service "code.gitea.io/gitea/services/asymkey" + "code.gitea.io/gitea/services/context" "code.gitea.io/gitea/services/convert" "code.gitea.io/gitea/services/mailer" user_service "code.gitea.io/gitea/services/user" diff --git a/routers/api/v1/api.go b/routers/api/v1/api.go index 48ce49447..c296cac79 100644 --- a/routers/api/v1/api.go +++ b/routers/api/v1/api.go @@ -80,7 +80,6 @@ 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/context" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/setting" api "code.gitea.io/gitea/modules/structs" @@ -96,7 +95,7 @@ import ( "code.gitea.io/gitea/routers/api/v1/user" "code.gitea.io/gitea/routers/common" "code.gitea.io/gitea/services/auth" - context_service "code.gitea.io/gitea/services/context" + "code.gitea.io/gitea/services/context" "code.gitea.io/gitea/services/forms" _ "code.gitea.io/gitea/routers/api/v1/swagger" // for swagger generation @@ -889,11 +888,11 @@ func Routes() *web.Route { m.Group("/user/{username}", func() { m.Get("", activitypub.Person) m.Post("/inbox", activitypub.ReqHTTPSignature(), activitypub.PersonInbox) - }, context_service.UserAssignmentAPI()) + }, context.UserAssignmentAPI()) m.Group("/user-id/{user-id}", func() { m.Get("", activitypub.Person) m.Post("/inbox", activitypub.ReqHTTPSignature(), activitypub.PersonInbox) - }, context_service.UserIDAssignmentAPI()) + }, context.UserIDAssignmentAPI()) }, tokenRequiresScopes(auth_model.AccessTokenScopeCategoryActivityPub)) } @@ -949,7 +948,7 @@ func Routes() *web.Route { }, reqSelfOrAdmin(), reqBasicOrRevProxyAuth()) m.Get("/activities/feeds", user.ListUserActivityFeeds) - }, context_service.UserAssignmentAPI(), individualPermsChecker) + }, context.UserAssignmentAPI(), individualPermsChecker) }, tokenRequiresScopes(auth_model.AccessTokenScopeCategoryUser)) // Users (requires user scope) @@ -969,7 +968,7 @@ func Routes() *web.Route { } m.Get("/subscriptions", user.GetWatchedRepos) - }, context_service.UserAssignmentAPI()) + }, context.UserAssignmentAPI()) }, tokenRequiresScopes(auth_model.AccessTokenScopeCategoryUser), reqToken()) // Users (requires user scope) @@ -1004,7 +1003,7 @@ func Routes() *web.Route { m.Get("", user.CheckMyFollowing) m.Put("", user.Follow) m.Delete("", user.Unfollow) - }, context_service.UserAssignmentAPI()) + }, context.UserAssignmentAPI()) }) // (admin:public_key scope) @@ -1068,7 +1067,7 @@ func Routes() *web.Route { m.Group("", func() { m.Put("/block/{username}", user.BlockUser) m.Put("/unblock/{username}", user.UnblockUser) - }, context_service.UserAssignmentAPI()) + }, context.UserAssignmentAPI()) }) m.Group("/avatar", func() { @@ -1485,14 +1484,14 @@ func Routes() *web.Route { m.Get("/files", reqToken(), packages.ListPackageFiles) }) m.Get("/", reqToken(), packages.ListPackages) - }, tokenRequiresScopes(auth_model.AccessTokenScopeCategoryPackage), context_service.UserAssignmentAPI(), context.PackageAssignmentAPI(), reqPackageAccess(perm.AccessModeRead)) + }, tokenRequiresScopes(auth_model.AccessTokenScopeCategoryPackage), context.UserAssignmentAPI(), context.PackageAssignmentAPI(), reqPackageAccess(perm.AccessModeRead)) // Organizations m.Get("/user/orgs", reqToken(), tokenRequiresScopes(auth_model.AccessTokenScopeCategoryUser, auth_model.AccessTokenScopeCategoryOrganization), org.ListMyOrgs) m.Group("/users/{username}/orgs", func() { m.Get("", reqToken(), org.ListUserOrgs) m.Get("/{org}/permissions", reqToken(), org.GetUserOrgsPermissions) - }, tokenRequiresScopes(auth_model.AccessTokenScopeCategoryUser, auth_model.AccessTokenScopeCategoryOrganization), context_service.UserAssignmentAPI()) + }, tokenRequiresScopes(auth_model.AccessTokenScopeCategoryUser, auth_model.AccessTokenScopeCategoryOrganization), context.UserAssignmentAPI()) m.Post("/orgs", tokenRequiresScopes(auth_model.AccessTokenScopeCategoryOrganization), reqToken(), bind(api.CreateOrgOption{}), org.Create) m.Get("/orgs", org.GetAll, tokenRequiresScopes(auth_model.AccessTokenScopeCategoryOrganization)) m.Group("/orgs/{org}", func() { @@ -1554,7 +1553,7 @@ func Routes() *web.Route { m.Group("", func() { m.Put("/block/{username}", org.BlockUser) m.Put("/unblock/{username}", org.UnblockUser) - }, context_service.UserAssignmentAPI()) + }, context.UserAssignmentAPI()) }, reqToken(), reqOrgOwnership()) }, tokenRequiresScopes(auth_model.AccessTokenScopeCategoryOrganization), orgAssignment(true)) m.Group("/teams/{teamid}", func() { @@ -1598,7 +1597,7 @@ func Routes() *web.Route { m.Post("/orgs", bind(api.CreateOrgOption{}), admin.CreateOrg) m.Post("/repos", bind(api.CreateRepoOption{}), admin.CreateRepo) m.Post("/rename", bind(api.RenameUserOption{}), admin.RenameUser) - }, context_service.UserAssignmentAPI()) + }, context.UserAssignmentAPI()) }) m.Group("/emails", func() { m.Get("", admin.GetAllEmails) diff --git a/routers/api/v1/misc/gitignore.go b/routers/api/v1/misc/gitignore.go index 7c7fe4b12..dffd77175 100644 --- a/routers/api/v1/misc/gitignore.go +++ b/routers/api/v1/misc/gitignore.go @@ -6,11 +6,11 @@ package misc import ( "net/http" - "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/options" repo_module "code.gitea.io/gitea/modules/repository" "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/util" + "code.gitea.io/gitea/services/context" ) // Shows a list of all Gitignore templates diff --git a/routers/api/v1/misc/label_templates.go b/routers/api/v1/misc/label_templates.go index 0e0ca39fc..cc11f3762 100644 --- a/routers/api/v1/misc/label_templates.go +++ b/routers/api/v1/misc/label_templates.go @@ -6,9 +6,9 @@ package misc import ( "net/http" - "code.gitea.io/gitea/modules/context" repo_module "code.gitea.io/gitea/modules/repository" "code.gitea.io/gitea/modules/util" + "code.gitea.io/gitea/services/context" "code.gitea.io/gitea/services/convert" ) diff --git a/routers/api/v1/misc/licenses.go b/routers/api/v1/misc/licenses.go index 65f63468c..2a980f508 100644 --- a/routers/api/v1/misc/licenses.go +++ b/routers/api/v1/misc/licenses.go @@ -8,12 +8,12 @@ import ( "net/http" "net/url" - "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/options" repo_module "code.gitea.io/gitea/modules/repository" "code.gitea.io/gitea/modules/setting" api "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/util" + "code.gitea.io/gitea/services/context" ) // Returns a list of all License templates diff --git a/routers/api/v1/misc/markup.go b/routers/api/v1/misc/markup.go index 7b24b353b..9699c7936 100644 --- a/routers/api/v1/misc/markup.go +++ b/routers/api/v1/misc/markup.go @@ -6,12 +6,12 @@ package misc import ( "net/http" - "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/markup" "code.gitea.io/gitea/modules/markup/markdown" api "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/web" "code.gitea.io/gitea/routers/common" + "code.gitea.io/gitea/services/context" ) // Markup render markup document to HTML diff --git a/routers/api/v1/misc/markup_test.go b/routers/api/v1/misc/markup_test.go index ec8f8f47b..f499501c2 100644 --- a/routers/api/v1/misc/markup_test.go +++ b/routers/api/v1/misc/markup_test.go @@ -10,11 +10,11 @@ import ( "strings" "testing" - "code.gitea.io/gitea/modules/contexttest" "code.gitea.io/gitea/modules/markup" "code.gitea.io/gitea/modules/setting" api "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/web" + "code.gitea.io/gitea/services/contexttest" "github.com/stretchr/testify/assert" ) diff --git a/routers/api/v1/misc/nodeinfo.go b/routers/api/v1/misc/nodeinfo.go index 6045208f2..9c2a0db8d 100644 --- a/routers/api/v1/misc/nodeinfo.go +++ b/routers/api/v1/misc/nodeinfo.go @@ -9,9 +9,9 @@ import ( issues_model "code.gitea.io/gitea/models/issues" user_model "code.gitea.io/gitea/models/user" - "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/structs" + "code.gitea.io/gitea/services/context" ) const cacheKeyNodeInfoUsage = "API_NodeInfoUsage" diff --git a/routers/api/v1/misc/signing.go b/routers/api/v1/misc/signing.go index 2ca9813e1..24a46c1e7 100644 --- a/routers/api/v1/misc/signing.go +++ b/routers/api/v1/misc/signing.go @@ -7,8 +7,8 @@ import ( "fmt" "net/http" - "code.gitea.io/gitea/modules/context" asymkey_service "code.gitea.io/gitea/services/asymkey" + "code.gitea.io/gitea/services/context" ) // SigningKey returns the public key of the default signing key if it exists diff --git a/routers/api/v1/misc/version.go b/routers/api/v1/misc/version.go index 83fa35219..e3b43a0e6 100644 --- a/routers/api/v1/misc/version.go +++ b/routers/api/v1/misc/version.go @@ -6,9 +6,9 @@ package misc import ( "net/http" - "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/structs" + "code.gitea.io/gitea/services/context" ) // Version shows the version of the Gitea server diff --git a/routers/api/v1/notify/notifications.go b/routers/api/v1/notify/notifications.go index c87da9399..46b3c7f5e 100644 --- a/routers/api/v1/notify/notifications.go +++ b/routers/api/v1/notify/notifications.go @@ -9,9 +9,9 @@ import ( activities_model "code.gitea.io/gitea/models/activities" "code.gitea.io/gitea/models/db" - "code.gitea.io/gitea/modules/context" api "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/routers/api/v1/utils" + "code.gitea.io/gitea/services/context" ) // NewAvailable check if unread notifications exist diff --git a/routers/api/v1/notify/repo.go b/routers/api/v1/notify/repo.go index 55ca6ad1f..8d97e8a3f 100644 --- a/routers/api/v1/notify/repo.go +++ b/routers/api/v1/notify/repo.go @@ -10,9 +10,9 @@ import ( activities_model "code.gitea.io/gitea/models/activities" "code.gitea.io/gitea/models/db" - "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/structs" + "code.gitea.io/gitea/services/context" "code.gitea.io/gitea/services/convert" ) diff --git a/routers/api/v1/notify/threads.go b/routers/api/v1/notify/threads.go index 919e52952..8e12d359c 100644 --- a/routers/api/v1/notify/threads.go +++ b/routers/api/v1/notify/threads.go @@ -10,7 +10,7 @@ import ( activities_model "code.gitea.io/gitea/models/activities" "code.gitea.io/gitea/models/db" issues_model "code.gitea.io/gitea/models/issues" - "code.gitea.io/gitea/modules/context" + "code.gitea.io/gitea/services/context" "code.gitea.io/gitea/services/convert" ) diff --git a/routers/api/v1/notify/user.go b/routers/api/v1/notify/user.go index 4abdfb2e9..879f484cc 100644 --- a/routers/api/v1/notify/user.go +++ b/routers/api/v1/notify/user.go @@ -9,8 +9,8 @@ import ( activities_model "code.gitea.io/gitea/models/activities" "code.gitea.io/gitea/models/db" - "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/structs" + "code.gitea.io/gitea/services/context" "code.gitea.io/gitea/services/convert" ) diff --git a/routers/api/v1/org/avatar.go b/routers/api/v1/org/avatar.go index 7b621a50c..e34c68dfc 100644 --- a/routers/api/v1/org/avatar.go +++ b/routers/api/v1/org/avatar.go @@ -7,9 +7,9 @@ import ( "encoding/base64" "net/http" - "code.gitea.io/gitea/modules/context" api "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/web" + "code.gitea.io/gitea/services/context" user_service "code.gitea.io/gitea/services/user" ) diff --git a/routers/api/v1/org/hook.go b/routers/api/v1/org/hook.go index 3c3f058b5..c1dc0519e 100644 --- a/routers/api/v1/org/hook.go +++ b/routers/api/v1/org/hook.go @@ -6,10 +6,10 @@ package org import ( "net/http" - "code.gitea.io/gitea/modules/context" api "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/web" "code.gitea.io/gitea/routers/api/v1/utils" + "code.gitea.io/gitea/services/context" webhook_service "code.gitea.io/gitea/services/webhook" ) diff --git a/routers/api/v1/org/label.go b/routers/api/v1/org/label.go index 5a03059de..b5ec54ccf 100644 --- a/routers/api/v1/org/label.go +++ b/routers/api/v1/org/label.go @@ -9,11 +9,11 @@ import ( "strings" issues_model "code.gitea.io/gitea/models/issues" - "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/label" api "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/web" "code.gitea.io/gitea/routers/api/v1/utils" + "code.gitea.io/gitea/services/context" "code.gitea.io/gitea/services/convert" ) diff --git a/routers/api/v1/org/member.go b/routers/api/v1/org/member.go index 422b7cecf..fb66d4c3f 100644 --- a/routers/api/v1/org/member.go +++ b/routers/api/v1/org/member.go @@ -9,11 +9,11 @@ import ( "code.gitea.io/gitea/models" "code.gitea.io/gitea/models/organization" - "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/setting" api "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/routers/api/v1/user" "code.gitea.io/gitea/routers/api/v1/utils" + "code.gitea.io/gitea/services/context" "code.gitea.io/gitea/services/convert" ) diff --git a/routers/api/v1/org/org.go b/routers/api/v1/org/org.go index 2eefad6a9..9f9483d4f 100644 --- a/routers/api/v1/org/org.go +++ b/routers/api/v1/org/org.go @@ -13,12 +13,12 @@ import ( "code.gitea.io/gitea/models/organization" "code.gitea.io/gitea/models/perm" user_model "code.gitea.io/gitea/models/user" - "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/optional" api "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/web" "code.gitea.io/gitea/routers/api/v1/user" "code.gitea.io/gitea/routers/api/v1/utils" + "code.gitea.io/gitea/services/context" "code.gitea.io/gitea/services/convert" "code.gitea.io/gitea/services/org" user_service "code.gitea.io/gitea/services/user" diff --git a/routers/api/v1/org/runners.go b/routers/api/v1/org/runners.go index 05bce8dae..2a52bd877 100644 --- a/routers/api/v1/org/runners.go +++ b/routers/api/v1/org/runners.go @@ -4,8 +4,8 @@ package org import ( - "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/routers/api/v1/shared" + "code.gitea.io/gitea/services/context" ) // https://docs.github.com/en/rest/actions/self-hosted-runners?apiVersion=2022-11-28#create-a-registration-token-for-an-organization diff --git a/routers/api/v1/org/secrets.go b/routers/api/v1/org/secrets.go index ddc74d865..abb6bb26c 100644 --- a/routers/api/v1/org/secrets.go +++ b/routers/api/v1/org/secrets.go @@ -9,11 +9,11 @@ import ( "code.gitea.io/gitea/models/db" secret_model "code.gitea.io/gitea/models/secret" - "code.gitea.io/gitea/modules/context" 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" secret_service "code.gitea.io/gitea/services/secrets" ) diff --git a/routers/api/v1/org/team.go b/routers/api/v1/org/team.go index f129c6623..b62a386fd 100644 --- a/routers/api/v1/org/team.go +++ b/routers/api/v1/org/team.go @@ -15,12 +15,12 @@ import ( access_model "code.gitea.io/gitea/models/perm/access" repo_model "code.gitea.io/gitea/models/repo" unit_model "code.gitea.io/gitea/models/unit" - "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/log" api "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/web" "code.gitea.io/gitea/routers/api/v1/user" "code.gitea.io/gitea/routers/api/v1/utils" + "code.gitea.io/gitea/services/context" "code.gitea.io/gitea/services/convert" org_service "code.gitea.io/gitea/services/org" repo_service "code.gitea.io/gitea/services/repository" diff --git a/routers/api/v1/packages/package.go b/routers/api/v1/packages/package.go index a79ba315b..b38aa1316 100644 --- a/routers/api/v1/packages/package.go +++ b/routers/api/v1/packages/package.go @@ -7,10 +7,10 @@ import ( "net/http" "code.gitea.io/gitea/models/packages" - "code.gitea.io/gitea/modules/context" + "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" packages_service "code.gitea.io/gitea/services/packages" ) @@ -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/action.go b/routers/api/v1/repo/action.go index 039cdadac..e0af276c7 100644 --- a/routers/api/v1/repo/action.go +++ b/routers/api/v1/repo/action.go @@ -7,10 +7,10 @@ import ( "errors" "net/http" - "code.gitea.io/gitea/modules/context" api "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/util" "code.gitea.io/gitea/modules/web" + "code.gitea.io/gitea/services/context" secret_service "code.gitea.io/gitea/services/secrets" ) diff --git a/routers/api/v1/repo/avatar.go b/routers/api/v1/repo/avatar.go index 1b661955f..698337ffd 100644 --- a/routers/api/v1/repo/avatar.go +++ b/routers/api/v1/repo/avatar.go @@ -7,9 +7,9 @@ import ( "encoding/base64" "net/http" - "code.gitea.io/gitea/modules/context" api "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/web" + "code.gitea.io/gitea/services/context" repo_service "code.gitea.io/gitea/services/repository" ) diff --git a/routers/api/v1/repo/blob.go b/routers/api/v1/repo/blob.go index 26605bba0..3b116666e 100644 --- a/routers/api/v1/repo/blob.go +++ b/routers/api/v1/repo/blob.go @@ -6,7 +6,7 @@ package repo import ( "net/http" - "code.gitea.io/gitea/modules/context" + "code.gitea.io/gitea/services/context" files_service "code.gitea.io/gitea/services/repository/files" ) diff --git a/routers/api/v1/repo/branch.go b/routers/api/v1/repo/branch.go index 2cdbcd25a..5e6b6a865 100644 --- a/routers/api/v1/repo/branch.go +++ b/routers/api/v1/repo/branch.go @@ -14,7 +14,6 @@ import ( git_model "code.gitea.io/gitea/models/git" "code.gitea.io/gitea/models/organization" user_model "code.gitea.io/gitea/models/user" - "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/gitrepo" "code.gitea.io/gitea/modules/optional" @@ -22,6 +21,7 @@ import ( api "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/web" "code.gitea.io/gitea/routers/api/v1/utils" + "code.gitea.io/gitea/services/context" "code.gitea.io/gitea/services/convert" pull_service "code.gitea.io/gitea/services/pull" repo_service "code.gitea.io/gitea/services/repository" diff --git a/routers/api/v1/repo/collaborators.go b/routers/api/v1/repo/collaborators.go index 2c85657b9..a43a21a88 100644 --- a/routers/api/v1/repo/collaborators.go +++ b/routers/api/v1/repo/collaborators.go @@ -13,11 +13,11 @@ import ( access_model "code.gitea.io/gitea/models/perm/access" repo_model "code.gitea.io/gitea/models/repo" user_model "code.gitea.io/gitea/models/user" - "code.gitea.io/gitea/modules/context" repo_module "code.gitea.io/gitea/modules/repository" api "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/web" "code.gitea.io/gitea/routers/api/v1/utils" + "code.gitea.io/gitea/services/context" "code.gitea.io/gitea/services/convert" repo_service "code.gitea.io/gitea/services/repository" ) diff --git a/routers/api/v1/repo/commits.go b/routers/api/v1/repo/commits.go index d01cf6b8b..d06a3b4e4 100644 --- a/routers/api/v1/repo/commits.go +++ b/routers/api/v1/repo/commits.go @@ -12,11 +12,11 @@ import ( issues_model "code.gitea.io/gitea/models/issues" user_model "code.gitea.io/gitea/models/user" - "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/setting" api "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/routers/api/v1/utils" + "code.gitea.io/gitea/services/context" "code.gitea.io/gitea/services/convert" ) diff --git a/routers/api/v1/repo/file.go b/routers/api/v1/repo/file.go index 94a6381e2..72ada25ec 100644 --- a/routers/api/v1/repo/file.go +++ b/routers/api/v1/repo/file.go @@ -19,7 +19,6 @@ import ( git_model "code.gitea.io/gitea/models/git" repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/models/unit" - "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/gitrepo" "code.gitea.io/gitea/modules/httpcache" @@ -30,6 +29,7 @@ import ( api "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/web" "code.gitea.io/gitea/routers/common" + "code.gitea.io/gitea/services/context" archiver_service "code.gitea.io/gitea/services/repository/archiver" files_service "code.gitea.io/gitea/services/repository/files" ) @@ -672,6 +672,7 @@ func UpdateFile(ctx *context.APIContext) { apiOpts := web.GetForm(ctx).(*api.UpdateFileOptions) if ctx.Repo.Repository.IsEmpty { ctx.Error(http.StatusUnprocessableEntity, "RepoIsEmpty", fmt.Errorf("repo is empty")) + return } if apiOpts.BranchName == "" { diff --git a/routers/api/v1/repo/flags.go b/routers/api/v1/repo/flags.go index cbb2c9591..ac5cb2e6d 100644 --- a/routers/api/v1/repo/flags.go +++ b/routers/api/v1/repo/flags.go @@ -6,9 +6,9 @@ package repo import ( "net/http" - "code.gitea.io/gitea/modules/context" api "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/web" + "code.gitea.io/gitea/services/context" ) func ListFlags(ctx *context.APIContext) { diff --git a/routers/api/v1/repo/fork.go b/routers/api/v1/repo/fork.go index 69433bf4c..212cc7a93 100644 --- a/routers/api/v1/repo/fork.go +++ b/routers/api/v1/repo/fork.go @@ -14,11 +14,11 @@ import ( access_model "code.gitea.io/gitea/models/perm/access" repo_model "code.gitea.io/gitea/models/repo" user_model "code.gitea.io/gitea/models/user" - "code.gitea.io/gitea/modules/context" 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" "code.gitea.io/gitea/services/convert" repo_service "code.gitea.io/gitea/services/repository" ) diff --git a/routers/api/v1/repo/git_hook.go b/routers/api/v1/repo/git_hook.go index 7e471e263..26ae84d08 100644 --- a/routers/api/v1/repo/git_hook.go +++ b/routers/api/v1/repo/git_hook.go @@ -6,10 +6,10 @@ package repo import ( "net/http" - "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/git" api "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/web" + "code.gitea.io/gitea/services/context" "code.gitea.io/gitea/services/convert" ) diff --git a/routers/api/v1/repo/git_ref.go b/routers/api/v1/repo/git_ref.go index 34d2dcfcc..0fa58425b 100644 --- a/routers/api/v1/repo/git_ref.go +++ b/routers/api/v1/repo/git_ref.go @@ -7,10 +7,10 @@ import ( "net/http" "net/url" - "code.gitea.io/gitea/modules/context" 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" ) // GetGitAllRefs get ref or an list all the refs of a repository diff --git a/routers/api/v1/repo/hook.go b/routers/api/v1/repo/hook.go index 8859e3ae2..ffd231359 100644 --- a/routers/api/v1/repo/hook.go +++ b/routers/api/v1/repo/hook.go @@ -11,13 +11,13 @@ import ( "code.gitea.io/gitea/models/perm" access_model "code.gitea.io/gitea/models/perm/access" "code.gitea.io/gitea/models/webhook" - "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/setting" api "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/web" webhook_module "code.gitea.io/gitea/modules/webhook" "code.gitea.io/gitea/routers/api/v1/utils" + "code.gitea.io/gitea/services/context" "code.gitea.io/gitea/services/convert" webhook_service "code.gitea.io/gitea/services/webhook" ) diff --git a/routers/api/v1/repo/hook_test.go b/routers/api/v1/repo/hook_test.go index 94a71e20a..37cf61c1e 100644 --- a/routers/api/v1/repo/hook_test.go +++ b/routers/api/v1/repo/hook_test.go @@ -9,7 +9,7 @@ import ( "code.gitea.io/gitea/models/unittest" "code.gitea.io/gitea/models/webhook" - "code.gitea.io/gitea/modules/contexttest" + "code.gitea.io/gitea/services/contexttest" "github.com/stretchr/testify/assert" ) diff --git a/routers/api/v1/repo/issue.go b/routers/api/v1/repo/issue.go index ae35bf2ee..af3f890f8 100644 --- a/routers/api/v1/repo/issue.go +++ b/routers/api/v1/repo/issue.go @@ -19,14 +19,14 @@ 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/context" issue_indexer "code.gitea.io/gitea/modules/indexer/issues" + "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" "code.gitea.io/gitea/modules/web" "code.gitea.io/gitea/routers/api/v1/utils" + "code.gitea.io/gitea/services/context" "code.gitea.io/gitea/services/convert" issue_service "code.gitea.io/gitea/services/issue" notify_service "code.gitea.io/gitea/services/notify" @@ -123,14 +123,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 ( @@ -143,7 +143,7 @@ func SearchIssues(ctx *context.APIContext) { Private: false, AllPublic: true, TopicOnly: false, - Collaborate: util.OptionalBoolNone, + Collaborate: optional.None[bool](), // This needs to be a column that is not nil in fixtures or // MySQL will return different results when sorting by null in some cases OrderBy: db.SearchOrderByAlphabetically, @@ -166,7 +166,7 @@ func SearchIssues(ctx *context.APIContext) { opts.OwnerID = owner.ID opts.AllLimited = false opts.AllPublic = false - opts.Collaborate = util.OptionalBoolFalse + opts.Collaborate = optional.Some(false) } if ctx.FormString("team") != "" { if ctx.FormString("owner") == "" { @@ -205,14 +205,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 +397,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 +453,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_attachment.go b/routers/api/v1/repo/issue_attachment.go index eaaaeaa9f..fc9e88d63 100644 --- a/routers/api/v1/repo/issue_attachment.go +++ b/routers/api/v1/repo/issue_attachment.go @@ -9,12 +9,12 @@ import ( issues_model "code.gitea.io/gitea/models/issues" repo_model "code.gitea.io/gitea/models/repo" - "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/setting" api "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/web" "code.gitea.io/gitea/services/attachment" + "code.gitea.io/gitea/services/context" "code.gitea.io/gitea/services/convert" issue_service "code.gitea.io/gitea/services/issue" ) diff --git a/routers/api/v1/repo/issue_comment.go b/routers/api/v1/repo/issue_comment.go index 35d7658b6..c3005dee3 100644 --- a/routers/api/v1/repo/issue_comment.go +++ b/routers/api/v1/repo/issue_comment.go @@ -14,11 +14,11 @@ 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/context" + "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" "code.gitea.io/gitea/services/convert" issue_service "code.gitea.io/gitea/services/issue" ) @@ -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/issue_comment_attachment.go b/routers/api/v1/repo/issue_comment_attachment.go index 5622a9292..0f8fc96f0 100644 --- a/routers/api/v1/repo/issue_comment_attachment.go +++ b/routers/api/v1/repo/issue_comment_attachment.go @@ -9,12 +9,12 @@ import ( issues_model "code.gitea.io/gitea/models/issues" repo_model "code.gitea.io/gitea/models/repo" - "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/setting" api "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/web" "code.gitea.io/gitea/services/attachment" + "code.gitea.io/gitea/services/context" "code.gitea.io/gitea/services/convert" issue_service "code.gitea.io/gitea/services/issue" ) diff --git a/routers/api/v1/repo/issue_dependency.go b/routers/api/v1/repo/issue_dependency.go index 62d1057cd..a42920d4f 100644 --- a/routers/api/v1/repo/issue_dependency.go +++ b/routers/api/v1/repo/issue_dependency.go @@ -11,10 +11,10 @@ import ( issues_model "code.gitea.io/gitea/models/issues" access_model "code.gitea.io/gitea/models/perm/access" repo_model "code.gitea.io/gitea/models/repo" - "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/setting" api "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/web" + "code.gitea.io/gitea/services/context" "code.gitea.io/gitea/services/convert" ) diff --git a/routers/api/v1/repo/issue_label.go b/routers/api/v1/repo/issue_label.go index 008ff5c69..fd9625c0f 100644 --- a/routers/api/v1/repo/issue_label.go +++ b/routers/api/v1/repo/issue_label.go @@ -8,9 +8,9 @@ import ( "net/http" issues_model "code.gitea.io/gitea/models/issues" - "code.gitea.io/gitea/modules/context" api "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/web" + "code.gitea.io/gitea/services/context" "code.gitea.io/gitea/services/convert" issue_service "code.gitea.io/gitea/services/issue" ) diff --git a/routers/api/v1/repo/issue_pin.go b/routers/api/v1/repo/issue_pin.go index 61f88de34..ff1135862 100644 --- a/routers/api/v1/repo/issue_pin.go +++ b/routers/api/v1/repo/issue_pin.go @@ -7,8 +7,8 @@ import ( "net/http" issues_model "code.gitea.io/gitea/models/issues" - "code.gitea.io/gitea/modules/context" api "code.gitea.io/gitea/modules/structs" + "code.gitea.io/gitea/services/context" "code.gitea.io/gitea/services/convert" ) diff --git a/routers/api/v1/repo/issue_reaction.go b/routers/api/v1/repo/issue_reaction.go index 27edc1aba..c395255c1 100644 --- a/routers/api/v1/repo/issue_reaction.go +++ b/routers/api/v1/repo/issue_reaction.go @@ -9,10 +9,10 @@ import ( issues_model "code.gitea.io/gitea/models/issues" user_model "code.gitea.io/gitea/models/user" - "code.gitea.io/gitea/modules/context" api "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/web" "code.gitea.io/gitea/routers/api/v1/utils" + "code.gitea.io/gitea/services/context" "code.gitea.io/gitea/services/convert" issue_service "code.gitea.io/gitea/services/issue" ) diff --git a/routers/api/v1/repo/issue_stopwatch.go b/routers/api/v1/repo/issue_stopwatch.go index 52bf8b5c7..d9054e8f7 100644 --- a/routers/api/v1/repo/issue_stopwatch.go +++ b/routers/api/v1/repo/issue_stopwatch.go @@ -8,8 +8,8 @@ import ( "net/http" issues_model "code.gitea.io/gitea/models/issues" - "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/routers/api/v1/utils" + "code.gitea.io/gitea/services/context" "code.gitea.io/gitea/services/convert" ) diff --git a/routers/api/v1/repo/issue_subscription.go b/routers/api/v1/repo/issue_subscription.go index ece880c03..a53517246 100644 --- a/routers/api/v1/repo/issue_subscription.go +++ b/routers/api/v1/repo/issue_subscription.go @@ -9,9 +9,9 @@ import ( issues_model "code.gitea.io/gitea/models/issues" user_model "code.gitea.io/gitea/models/user" - "code.gitea.io/gitea/modules/context" api "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/routers/api/v1/utils" + "code.gitea.io/gitea/services/context" "code.gitea.io/gitea/services/convert" ) diff --git a/routers/api/v1/repo/issue_tracked_time.go b/routers/api/v1/repo/issue_tracked_time.go index cf03e72aa..c64051588 100644 --- a/routers/api/v1/repo/issue_tracked_time.go +++ b/routers/api/v1/repo/issue_tracked_time.go @@ -12,10 +12,10 @@ import ( issues_model "code.gitea.io/gitea/models/issues" "code.gitea.io/gitea/models/unit" user_model "code.gitea.io/gitea/models/user" - "code.gitea.io/gitea/modules/context" api "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/web" "code.gitea.io/gitea/routers/api/v1/utils" + "code.gitea.io/gitea/services/context" "code.gitea.io/gitea/services/convert" ) diff --git a/routers/api/v1/repo/key.go b/routers/api/v1/repo/key.go index af48c4088..88444a262 100644 --- a/routers/api/v1/repo/key.go +++ b/routers/api/v1/repo/key.go @@ -15,12 +15,12 @@ import ( "code.gitea.io/gitea/models/perm" access_model "code.gitea.io/gitea/models/perm/access" repo_model "code.gitea.io/gitea/models/repo" - "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/setting" api "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/web" "code.gitea.io/gitea/routers/api/v1/utils" asymkey_service "code.gitea.io/gitea/services/asymkey" + "code.gitea.io/gitea/services/context" "code.gitea.io/gitea/services/convert" ) diff --git a/routers/api/v1/repo/label.go b/routers/api/v1/repo/label.go index 420d3ab5b..b6eb51fd2 100644 --- a/routers/api/v1/repo/label.go +++ b/routers/api/v1/repo/label.go @@ -9,11 +9,11 @@ import ( "strconv" issues_model "code.gitea.io/gitea/models/issues" - "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/label" api "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/web" "code.gitea.io/gitea/routers/api/v1/utils" + "code.gitea.io/gitea/services/context" "code.gitea.io/gitea/services/convert" ) diff --git a/routers/api/v1/repo/language.go b/routers/api/v1/repo/language.go index 12f1761ad..f1d5bbe45 100644 --- a/routers/api/v1/repo/language.go +++ b/routers/api/v1/repo/language.go @@ -9,8 +9,8 @@ import ( "strconv" repo_model "code.gitea.io/gitea/models/repo" - "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/services/context" ) type languageResponse []*repo_model.LanguageStat diff --git a/routers/api/v1/repo/migrate.go b/routers/api/v1/repo/migrate.go index 839fbfe8a..2caaa130e 100644 --- a/routers/api/v1/repo/migrate.go +++ b/routers/api/v1/repo/migrate.go @@ -17,7 +17,6 @@ import ( access_model "code.gitea.io/gitea/models/perm/access" repo_model "code.gitea.io/gitea/models/repo" user_model "code.gitea.io/gitea/models/user" - "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/graceful" "code.gitea.io/gitea/modules/lfs" "code.gitea.io/gitea/modules/log" @@ -26,6 +25,7 @@ import ( api "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/util" "code.gitea.io/gitea/modules/web" + "code.gitea.io/gitea/services/context" "code.gitea.io/gitea/services/convert" "code.gitea.io/gitea/services/forms" "code.gitea.io/gitea/services/migrations" diff --git a/routers/api/v1/repo/milestone.go b/routers/api/v1/repo/milestone.go index 9c2ed16d9..b9534016e 100644 --- a/routers/api/v1/repo/milestone.go +++ b/routers/api/v1/repo/milestone.go @@ -11,12 +11,12 @@ import ( "code.gitea.io/gitea/models/db" issues_model "code.gitea.io/gitea/models/issues" - "code.gitea.io/gitea/modules/context" + "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" "code.gitea.io/gitea/services/convert" ) @@ -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/mirror.go b/routers/api/v1/repo/mirror.go index 26e0be301..864644e1e 100644 --- a/routers/api/v1/repo/mirror.go +++ b/routers/api/v1/repo/mirror.go @@ -13,12 +13,12 @@ import ( "code.gitea.io/gitea/models/db" repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/models/unit" - "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/setting" 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" "code.gitea.io/gitea/services/convert" "code.gitea.io/gitea/services/forms" "code.gitea.io/gitea/services/migrations" diff --git a/routers/api/v1/repo/notes.go b/routers/api/v1/repo/notes.go index e7e00dae4..a4a1d4eab 100644 --- a/routers/api/v1/repo/notes.go +++ b/routers/api/v1/repo/notes.go @@ -7,9 +7,9 @@ import ( "fmt" "net/http" - "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/git" api "code.gitea.io/gitea/modules/structs" + "code.gitea.io/gitea/services/context" "code.gitea.io/gitea/services/convert" ) diff --git a/routers/api/v1/repo/patch.go b/routers/api/v1/repo/patch.go index 9b5635d24..0e0601b7d 100644 --- a/routers/api/v1/repo/patch.go +++ b/routers/api/v1/repo/patch.go @@ -10,10 +10,10 @@ import ( "code.gitea.io/gitea/models" git_model "code.gitea.io/gitea/models/git" repo_model "code.gitea.io/gitea/models/repo" - "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/git" api "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/web" + "code.gitea.io/gitea/services/context" "code.gitea.io/gitea/services/repository/files" ) diff --git a/routers/api/v1/repo/pull.go b/routers/api/v1/repo/pull.go index ef9b4893f..f78e34d7b 100644 --- a/routers/api/v1/repo/pull.go +++ b/routers/api/v1/repo/pull.go @@ -21,7 +21,6 @@ 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/context" "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/gitrepo" "code.gitea.io/gitea/modules/log" @@ -32,6 +31,7 @@ import ( "code.gitea.io/gitea/routers/api/v1/utils" asymkey_service "code.gitea.io/gitea/services/asymkey" "code.gitea.io/gitea/services/automerge" + "code.gitea.io/gitea/services/context" "code.gitea.io/gitea/services/convert" "code.gitea.io/gitea/services/forms" "code.gitea.io/gitea/services/gitdiff" diff --git a/routers/api/v1/repo/pull_review.go b/routers/api/v1/repo/pull_review.go index e39a096ad..6860d6e77 100644 --- a/routers/api/v1/repo/pull_review.go +++ b/routers/api/v1/repo/pull_review.go @@ -12,11 +12,11 @@ import ( "code.gitea.io/gitea/models/organization" access_model "code.gitea.io/gitea/models/perm/access" user_model "code.gitea.io/gitea/models/user" - "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/gitrepo" api "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/web" "code.gitea.io/gitea/routers/api/v1/utils" + "code.gitea.io/gitea/services/context" "code.gitea.io/gitea/services/convert" issue_service "code.gitea.io/gitea/services/issue" pull_service "code.gitea.io/gitea/services/pull" diff --git a/routers/api/v1/repo/release.go b/routers/api/v1/repo/release.go index a41c5ba7d..f0f3c0bbc 100644 --- a/routers/api/v1/repo/release.go +++ b/routers/api/v1/repo/release.go @@ -4,6 +4,7 @@ package repo import ( + "fmt" "net/http" "code.gitea.io/gitea/models" @@ -11,10 +12,10 @@ import ( "code.gitea.io/gitea/models/perm" repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/models/unit" - "code.gitea.io/gitea/modules/context" api "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/web" "code.gitea.io/gitea/routers/api/v1/utils" + "code.gitea.io/gitea/services/context" "code.gitea.io/gitea/services/convert" release_service "code.gitea.io/gitea/services/release" ) @@ -215,6 +216,10 @@ func CreateRelease(ctx *context.APIContext) { // "409": // "$ref": "#/responses/error" form := web.GetForm(ctx).(*api.CreateReleaseOption) + if ctx.Repo.Repository.IsEmpty { + ctx.Error(http.StatusUnprocessableEntity, "RepoIsEmpty", fmt.Errorf("repo is empty")) + return + } rel, err := repo_model.GetRelease(ctx, ctx.Repo.Repository.ID, form.TagName) if err != nil { if !repo_model.IsErrReleaseNotExist(err) { diff --git a/routers/api/v1/repo/release_attachment.go b/routers/api/v1/repo/release_attachment.go index c36bf12e6..59fd83e3a 100644 --- a/routers/api/v1/repo/release_attachment.go +++ b/routers/api/v1/repo/release_attachment.go @@ -4,16 +4,18 @@ package repo import ( + "io" "net/http" + "strings" repo_model "code.gitea.io/gitea/models/repo" - "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/setting" api "code.gitea.io/gitea/modules/structs" - "code.gitea.io/gitea/modules/upload" "code.gitea.io/gitea/modules/web" "code.gitea.io/gitea/services/attachment" + "code.gitea.io/gitea/services/context" + "code.gitea.io/gitea/services/context/upload" "code.gitea.io/gitea/services/convert" ) @@ -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 - } - defer file.Close() + var content io.ReadCloser + var filename string + var size int64 = -1 - filename := header.Filename - if query := ctx.FormString("name"); query != "" { - filename = query + 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") + } + + 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/api/v1/repo/release_tags.go b/routers/api/v1/repo/release_tags.go index 9f2098df0..fec91164a 100644 --- a/routers/api/v1/repo/release_tags.go +++ b/routers/api/v1/repo/release_tags.go @@ -8,7 +8,7 @@ import ( "code.gitea.io/gitea/models" repo_model "code.gitea.io/gitea/models/repo" - "code.gitea.io/gitea/modules/context" + "code.gitea.io/gitea/services/context" "code.gitea.io/gitea/services/convert" releaseservice "code.gitea.io/gitea/services/release" ) diff --git a/routers/api/v1/repo/repo.go b/routers/api/v1/repo/repo.go index de105f474..40960144c 100644 --- a/routers/api/v1/repo/repo.go +++ b/routers/api/v1/repo/repo.go @@ -19,18 +19,18 @@ import ( repo_model "code.gitea.io/gitea/models/repo" unit_model "code.gitea.io/gitea/models/unit" user_model "code.gitea.io/gitea/models/user" - "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/gitrepo" "code.gitea.io/gitea/modules/label" "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" api "code.gitea.io/gitea/modules/structs" - "code.gitea.io/gitea/modules/util" "code.gitea.io/gitea/modules/validation" "code.gitea.io/gitea/modules/web" "code.gitea.io/gitea/routers/api/v1/utils" + "code.gitea.io/gitea/services/context" "code.gitea.io/gitea/services/convert" "code.gitea.io/gitea/services/issue" repo_service "code.gitea.io/gitea/services/repository" @@ -135,33 +135,33 @@ func Search(ctx *context.APIContext) { PriorityOwnerID: ctx.FormInt64("priority_owner_id"), TeamID: ctx.FormInt64("team_id"), TopicOnly: ctx.FormBool("topic"), - Collaborate: util.OptionalBoolNone, + Collaborate: optional.None[bool](), Private: ctx.IsSigned && (ctx.FormString("private") == "" || ctx.FormBool("private")), - Template: util.OptionalBoolNone, + Template: optional.None[bool](), StarredByID: ctx.FormInt64("starredBy"), IncludeDescription: ctx.FormBool("includeDesc"), } if ctx.FormString("template") != "" { - opts.Template = util.OptionalBoolOf(ctx.FormBool("template")) + opts.Template = optional.Some(ctx.FormBool("template")) } if ctx.FormBool("exclusive") { - opts.Collaborate = util.OptionalBoolFalse + opts.Collaborate = optional.Some(false) } mode := ctx.FormString("mode") switch mode { case "source": - opts.Fork = util.OptionalBoolFalse - opts.Mirror = util.OptionalBoolFalse + opts.Fork = optional.Some(false) + opts.Mirror = optional.Some(false) case "fork": - opts.Fork = util.OptionalBoolTrue + opts.Fork = optional.Some(true) case "mirror": - opts.Mirror = util.OptionalBoolTrue + opts.Mirror = optional.Some(true) case "collaborative": - opts.Mirror = util.OptionalBoolFalse - opts.Collaborate = util.OptionalBoolTrue + opts.Mirror = optional.Some(false) + opts.Collaborate = optional.Some(true) case "": default: ctx.Error(http.StatusUnprocessableEntity, "", fmt.Errorf("Invalid search mode: \"%s\"", mode)) @@ -169,11 +169,11 @@ func Search(ctx *context.APIContext) { } if ctx.FormString("archived") != "" { - opts.Archived = util.OptionalBoolOf(ctx.FormBool("archived")) + opts.Archived = optional.Some(ctx.FormBool("archived")) } if ctx.FormString("is_private") != "" { - opts.IsPrivate = util.OptionalBoolOf(ctx.FormBool("is_private")) + opts.IsPrivate = optional.Some(ctx.FormBool("is_private")) } sortMode := ctx.FormString("sort") @@ -358,7 +358,7 @@ func Generate(ctx *context.APIContext) { return } - opts := repo_module.GenerateRepoOptions{ + opts := repo_service.GenerateRepoOptions{ Name: form.Name, DefaultBranch: form.DefaultBranch, Description: form.Description, diff --git a/routers/api/v1/repo/repo_test.go b/routers/api/v1/repo/repo_test.go index 08ba7faba..8d6ca9e3b 100644 --- a/routers/api/v1/repo/repo_test.go +++ b/routers/api/v1/repo/repo_test.go @@ -9,9 +9,9 @@ import ( repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/models/unittest" - "code.gitea.io/gitea/modules/contexttest" api "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/web" + "code.gitea.io/gitea/services/contexttest" "github.com/stretchr/testify/assert" ) diff --git a/routers/api/v1/repo/runners.go b/routers/api/v1/repo/runners.go index 0a2bbf811..fe133b311 100644 --- a/routers/api/v1/repo/runners.go +++ b/routers/api/v1/repo/runners.go @@ -4,8 +4,8 @@ package repo import ( - "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/routers/api/v1/shared" + "code.gitea.io/gitea/services/context" ) // GetRegistrationToken returns the token to register repo runners diff --git a/routers/api/v1/repo/star.go b/routers/api/v1/repo/star.go index 05227e33a..99676de11 100644 --- a/routers/api/v1/repo/star.go +++ b/routers/api/v1/repo/star.go @@ -7,9 +7,9 @@ import ( "net/http" repo_model "code.gitea.io/gitea/models/repo" - "code.gitea.io/gitea/modules/context" api "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/routers/api/v1/utils" + "code.gitea.io/gitea/services/context" "code.gitea.io/gitea/services/convert" ) diff --git a/routers/api/v1/repo/status.go b/routers/api/v1/repo/status.go index b4edf0608..53711bede 100644 --- a/routers/api/v1/repo/status.go +++ b/routers/api/v1/repo/status.go @@ -9,10 +9,10 @@ import ( "code.gitea.io/gitea/models/db" git_model "code.gitea.io/gitea/models/git" - "code.gitea.io/gitea/modules/context" api "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/web" "code.gitea.io/gitea/routers/api/v1/utils" + "code.gitea.io/gitea/services/context" "code.gitea.io/gitea/services/convert" files_service "code.gitea.io/gitea/services/repository/files" ) diff --git a/routers/api/v1/repo/subscriber.go b/routers/api/v1/repo/subscriber.go index 05509fc44..858418285 100644 --- a/routers/api/v1/repo/subscriber.go +++ b/routers/api/v1/repo/subscriber.go @@ -7,9 +7,9 @@ import ( "net/http" repo_model "code.gitea.io/gitea/models/repo" - "code.gitea.io/gitea/modules/context" api "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/routers/api/v1/utils" + "code.gitea.io/gitea/services/context" "code.gitea.io/gitea/services/convert" ) diff --git a/routers/api/v1/repo/tag.go b/routers/api/v1/repo/tag.go index ad812ace5..84ec3dd91 100644 --- a/routers/api/v1/repo/tag.go +++ b/routers/api/v1/repo/tag.go @@ -10,10 +10,10 @@ import ( "code.gitea.io/gitea/models" repo_model "code.gitea.io/gitea/models/repo" - "code.gitea.io/gitea/modules/context" api "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/web" "code.gitea.io/gitea/routers/api/v1/utils" + "code.gitea.io/gitea/services/context" "code.gitea.io/gitea/services/convert" releaseservice "code.gitea.io/gitea/services/release" ) diff --git a/routers/api/v1/repo/teams.go b/routers/api/v1/repo/teams.go index 1bacc7121..0ecf3a39d 100644 --- a/routers/api/v1/repo/teams.go +++ b/routers/api/v1/repo/teams.go @@ -8,7 +8,7 @@ import ( "net/http" "code.gitea.io/gitea/models/organization" - "code.gitea.io/gitea/modules/context" + "code.gitea.io/gitea/services/context" "code.gitea.io/gitea/services/convert" org_service "code.gitea.io/gitea/services/org" repo_service "code.gitea.io/gitea/services/repository" diff --git a/routers/api/v1/repo/topic.go b/routers/api/v1/repo/topic.go index d662b9b58..1d8e675bd 100644 --- a/routers/api/v1/repo/topic.go +++ b/routers/api/v1/repo/topic.go @@ -8,11 +8,11 @@ import ( "strings" repo_model "code.gitea.io/gitea/models/repo" - "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/log" api "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/web" "code.gitea.io/gitea/routers/api/v1/utils" + "code.gitea.io/gitea/services/context" "code.gitea.io/gitea/services/convert" ) diff --git a/routers/api/v1/repo/transfer.go b/routers/api/v1/repo/transfer.go index a00bbcc17..94c6bc6de 100644 --- a/routers/api/v1/repo/transfer.go +++ b/routers/api/v1/repo/transfer.go @@ -14,10 +14,10 @@ import ( access_model "code.gitea.io/gitea/models/perm/access" repo_model "code.gitea.io/gitea/models/repo" user_model "code.gitea.io/gitea/models/user" - "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/log" api "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/web" + "code.gitea.io/gitea/services/context" "code.gitea.io/gitea/services/convert" repo_service "code.gitea.io/gitea/services/repository" ) diff --git a/routers/api/v1/repo/tree.go b/routers/api/v1/repo/tree.go index f63100b6e..353a996d5 100644 --- a/routers/api/v1/repo/tree.go +++ b/routers/api/v1/repo/tree.go @@ -6,7 +6,7 @@ package repo import ( "net/http" - "code.gitea.io/gitea/modules/context" + "code.gitea.io/gitea/services/context" files_service "code.gitea.io/gitea/services/repository/files" ) diff --git a/routers/api/v1/repo/wiki.go b/routers/api/v1/repo/wiki.go index ba3e978a8..347b7539b 100644 --- a/routers/api/v1/repo/wiki.go +++ b/routers/api/v1/repo/wiki.go @@ -10,13 +10,13 @@ import ( "net/url" repo_model "code.gitea.io/gitea/models/repo" - "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/gitrepo" "code.gitea.io/gitea/modules/setting" api "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/util" "code.gitea.io/gitea/modules/web" + "code.gitea.io/gitea/services/context" "code.gitea.io/gitea/services/convert" notify_service "code.gitea.io/gitea/services/notify" wiki_service "code.gitea.io/gitea/services/wiki" diff --git a/routers/api/v1/settings/settings.go b/routers/api/v1/settings/settings.go index 957b839e6..c422315b2 100644 --- a/routers/api/v1/settings/settings.go +++ b/routers/api/v1/settings/settings.go @@ -6,9 +6,9 @@ package settings import ( "net/http" - "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/setting" api "code.gitea.io/gitea/modules/structs" + "code.gitea.io/gitea/services/context" ) // GetGeneralUISettings returns instance's global settings for ui diff --git a/routers/api/v1/shared/runners.go b/routers/api/v1/shared/runners.go index fe1584d2e..f184786d7 100644 --- a/routers/api/v1/shared/runners.go +++ b/routers/api/v1/shared/runners.go @@ -8,8 +8,8 @@ import ( "net/http" actions_model "code.gitea.io/gitea/models/actions" - "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/util" + "code.gitea.io/gitea/services/context" ) // RegistrationToken is a string used to register a runner with a server diff --git a/routers/api/v1/user/action.go b/routers/api/v1/user/action.go index cbe332a77..babb8c0cf 100644 --- a/routers/api/v1/user/action.go +++ b/routers/api/v1/user/action.go @@ -7,10 +7,10 @@ import ( "errors" "net/http" - "code.gitea.io/gitea/modules/context" api "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/util" "code.gitea.io/gitea/modules/web" + "code.gitea.io/gitea/services/context" secret_service "code.gitea.io/gitea/services/secrets" ) diff --git a/routers/api/v1/user/app.go b/routers/api/v1/user/app.go index eb35d8031..b61ebac7d 100644 --- a/routers/api/v1/user/app.go +++ b/routers/api/v1/user/app.go @@ -13,10 +13,10 @@ import ( auth_model "code.gitea.io/gitea/models/auth" "code.gitea.io/gitea/models/db" - "code.gitea.io/gitea/modules/context" api "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/web" "code.gitea.io/gitea/routers/api/v1/utils" + "code.gitea.io/gitea/services/context" "code.gitea.io/gitea/services/convert" ) diff --git a/routers/api/v1/user/avatar.go b/routers/api/v1/user/avatar.go index 1c1bb6181..f91229622 100644 --- a/routers/api/v1/user/avatar.go +++ b/routers/api/v1/user/avatar.go @@ -7,9 +7,9 @@ import ( "encoding/base64" "net/http" - "code.gitea.io/gitea/modules/context" api "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/web" + "code.gitea.io/gitea/services/context" user_service "code.gitea.io/gitea/services/user" ) diff --git a/routers/api/v1/user/email.go b/routers/api/v1/user/email.go index 3dcea9083..33aa851a8 100644 --- a/routers/api/v1/user/email.go +++ b/routers/api/v1/user/email.go @@ -8,9 +8,9 @@ import ( "net/http" user_model "code.gitea.io/gitea/models/user" - "code.gitea.io/gitea/modules/context" api "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/web" + "code.gitea.io/gitea/services/context" "code.gitea.io/gitea/services/convert" user_service "code.gitea.io/gitea/services/user" ) diff --git a/routers/api/v1/user/follower.go b/routers/api/v1/user/follower.go index 783cee858..1ba7346b8 100644 --- a/routers/api/v1/user/follower.go +++ b/routers/api/v1/user/follower.go @@ -9,9 +9,9 @@ import ( "net/http" user_model "code.gitea.io/gitea/models/user" - "code.gitea.io/gitea/modules/context" api "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/routers/api/v1/utils" + "code.gitea.io/gitea/services/context" "code.gitea.io/gitea/services/convert" ) diff --git a/routers/api/v1/user/gpg_key.go b/routers/api/v1/user/gpg_key.go index 234da5dfd..dcf5da0b2 100644 --- a/routers/api/v1/user/gpg_key.go +++ b/routers/api/v1/user/gpg_key.go @@ -10,10 +10,11 @@ import ( asymkey_model "code.gitea.io/gitea/models/asymkey" "code.gitea.io/gitea/models/db" - "code.gitea.io/gitea/modules/context" + "code.gitea.io/gitea/modules/setting" api "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/web" "code.gitea.io/gitea/routers/api/v1/utils" + "code.gitea.io/gitea/services/context" "code.gitea.io/gitea/services/convert" ) @@ -132,6 +133,11 @@ func GetGPGKey(ctx *context.APIContext) { // CreateUserGPGKey creates new GPG key to given user by ID. func CreateUserGPGKey(ctx *context.APIContext, form api.CreateGPGKeyOption, uid int64) { + if setting.Admin.UserDisabledFeatures.Contains(setting.UserFeatureManageGPGKeys) { + ctx.NotFound("Not Found", fmt.Errorf("gpg keys setting is not allowed to be visited")) + return + } + token := asymkey_model.VerificationToken(ctx.Doer, 1) lastToken := asymkey_model.VerificationToken(ctx.Doer, 0) @@ -268,6 +274,11 @@ func DeleteGPGKey(ctx *context.APIContext) { // "404": // "$ref": "#/responses/notFound" + if setting.Admin.UserDisabledFeatures.Contains(setting.UserFeatureManageGPGKeys) { + ctx.NotFound("Not Found", fmt.Errorf("gpg keys setting is not allowed to be visited")) + return + } + if err := asymkey_model.DeleteGPGKey(ctx, ctx.Doer, ctx.ParamsInt64(":id")); err != nil { if asymkey_model.IsErrGPGKeyAccessDenied(err) { ctx.Error(http.StatusForbidden, "", "You do not have access to this key") diff --git a/routers/api/v1/user/helper.go b/routers/api/v1/user/helper.go index 392b266eb..8b5c64e29 100644 --- a/routers/api/v1/user/helper.go +++ b/routers/api/v1/user/helper.go @@ -7,7 +7,7 @@ import ( "net/http" user_model "code.gitea.io/gitea/models/user" - "code.gitea.io/gitea/modules/context" + "code.gitea.io/gitea/services/context" ) // GetUserByParamsName get user by name diff --git a/routers/api/v1/user/hook.go b/routers/api/v1/user/hook.go index e87385e4a..9d9ca5bf0 100644 --- a/routers/api/v1/user/hook.go +++ b/routers/api/v1/user/hook.go @@ -6,10 +6,10 @@ package user import ( "net/http" - "code.gitea.io/gitea/modules/context" api "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/web" "code.gitea.io/gitea/routers/api/v1/utils" + "code.gitea.io/gitea/services/context" webhook_service "code.gitea.io/gitea/services/webhook" ) diff --git a/routers/api/v1/user/key.go b/routers/api/v1/user/key.go index dd185aa7d..ada6759f8 100644 --- a/routers/api/v1/user/key.go +++ b/routers/api/v1/user/key.go @@ -11,13 +11,13 @@ import ( "code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/perm" user_model "code.gitea.io/gitea/models/user" - "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/setting" api "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/web" "code.gitea.io/gitea/routers/api/v1/repo" "code.gitea.io/gitea/routers/api/v1/utils" asymkey_service "code.gitea.io/gitea/services/asymkey" + "code.gitea.io/gitea/services/context" "code.gitea.io/gitea/services/convert" ) diff --git a/routers/api/v1/user/repo.go b/routers/api/v1/user/repo.go index b8b2d265b..81f8e0f3f 100644 --- a/routers/api/v1/user/repo.go +++ b/routers/api/v1/user/repo.go @@ -11,9 +11,9 @@ import ( repo_model "code.gitea.io/gitea/models/repo" unit_model "code.gitea.io/gitea/models/unit" user_model "code.gitea.io/gitea/models/user" - "code.gitea.io/gitea/modules/context" api "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/routers/api/v1/utils" + "code.gitea.io/gitea/services/context" "code.gitea.io/gitea/services/convert" ) diff --git a/routers/api/v1/user/runners.go b/routers/api/v1/user/runners.go index 51556ae0f..899218473 100644 --- a/routers/api/v1/user/runners.go +++ b/routers/api/v1/user/runners.go @@ -4,8 +4,8 @@ package user import ( - "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/routers/api/v1/shared" + "code.gitea.io/gitea/services/context" ) // https://docs.github.com/en/rest/actions/self-hosted-runners?apiVersion=2022-11-28#create-a-registration-token-for-an-organization diff --git a/routers/api/v1/user/settings.go b/routers/api/v1/user/settings.go index 062df1ca4..d0a8daaa8 100644 --- a/routers/api/v1/user/settings.go +++ b/routers/api/v1/user/settings.go @@ -6,10 +6,10 @@ package user import ( "net/http" - "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/optional" api "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/web" + "code.gitea.io/gitea/services/context" "code.gitea.io/gitea/services/convert" user_service "code.gitea.io/gitea/services/user" ) diff --git a/routers/api/v1/user/star.go b/routers/api/v1/user/star.go index 2659789dd..e624884db 100644 --- a/routers/api/v1/user/star.go +++ b/routers/api/v1/user/star.go @@ -12,9 +12,9 @@ import ( access_model "code.gitea.io/gitea/models/perm/access" repo_model "code.gitea.io/gitea/models/repo" user_model "code.gitea.io/gitea/models/user" - "code.gitea.io/gitea/modules/context" api "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/routers/api/v1/utils" + "code.gitea.io/gitea/services/context" "code.gitea.io/gitea/services/convert" ) diff --git a/routers/api/v1/user/user.go b/routers/api/v1/user/user.go index 67651062c..831c1436d 100644 --- a/routers/api/v1/user/user.go +++ b/routers/api/v1/user/user.go @@ -10,8 +10,8 @@ import ( activities_model "code.gitea.io/gitea/models/activities" user_model "code.gitea.io/gitea/models/user" - "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/routers/api/v1/utils" + "code.gitea.io/gitea/services/context" "code.gitea.io/gitea/services/convert" ) diff --git a/routers/api/v1/user/watch.go b/routers/api/v1/user/watch.go index 7f531eafa..706f4cc66 100644 --- a/routers/api/v1/user/watch.go +++ b/routers/api/v1/user/watch.go @@ -11,9 +11,9 @@ import ( access_model "code.gitea.io/gitea/models/perm/access" repo_model "code.gitea.io/gitea/models/repo" user_model "code.gitea.io/gitea/models/user" - "code.gitea.io/gitea/modules/context" api "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/routers/api/v1/utils" + "code.gitea.io/gitea/services/context" "code.gitea.io/gitea/services/convert" ) diff --git a/routers/api/v1/utils/block.go b/routers/api/v1/utils/block.go index 187d69044..34fad9603 100644 --- a/routers/api/v1/utils/block.go +++ b/routers/api/v1/utils/block.go @@ -7,8 +7,8 @@ import ( "net/http" user_model "code.gitea.io/gitea/models/user" - "code.gitea.io/gitea/modules/context" api "code.gitea.io/gitea/modules/structs" + "code.gitea.io/gitea/services/context" user_service "code.gitea.io/gitea/services/user" ) diff --git a/routers/api/v1/utils/git.go b/routers/api/v1/utils/git.go index 5e8019001..4e2513781 100644 --- a/routers/api/v1/utils/git.go +++ b/routers/api/v1/utils/git.go @@ -8,10 +8,10 @@ import ( "fmt" "net/http" - "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/gitrepo" "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/services/context" ) // ResolveRefOrSha resolve ref to sha if exist diff --git a/routers/api/v1/utils/hook.go b/routers/api/v1/utils/hook.go index 28b21ab8d..f1abd49a7 100644 --- a/routers/api/v1/utils/hook.go +++ b/routers/api/v1/utils/hook.go @@ -12,12 +12,12 @@ import ( "code.gitea.io/gitea/models/db" user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/models/webhook" - "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/json" "code.gitea.io/gitea/modules/setting" api "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/util" webhook_module "code.gitea.io/gitea/modules/webhook" + "code.gitea.io/gitea/services/context" webhook_service "code.gitea.io/gitea/services/webhook" ) diff --git a/routers/api/v1/utils/page.go b/routers/api/v1/utils/page.go index 6910b8293..024ba7b8d 100644 --- a/routers/api/v1/utils/page.go +++ b/routers/api/v1/utils/page.go @@ -5,7 +5,7 @@ package utils import ( "code.gitea.io/gitea/models/db" - "code.gitea.io/gitea/modules/context" + "code.gitea.io/gitea/services/context" "code.gitea.io/gitea/services/convert" ) diff --git a/routers/common/auth.go b/routers/common/auth.go index 8904785d5..115d65ed1 100644 --- a/routers/common/auth.go +++ b/routers/common/auth.go @@ -5,9 +5,9 @@ package common import ( user_model "code.gitea.io/gitea/models/user" - "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/web/middleware" auth_service "code.gitea.io/gitea/services/auth" + "code.gitea.io/gitea/services/context" ) type AuthResult struct { diff --git a/routers/common/errpage.go b/routers/common/errpage.go index 923421a29..402ca44c1 100644 --- a/routers/common/errpage.go +++ b/routers/common/errpage.go @@ -9,13 +9,13 @@ import ( user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/base" - "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/httpcache" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/templates" "code.gitea.io/gitea/modules/web/middleware" "code.gitea.io/gitea/modules/web/routing" + "code.gitea.io/gitea/services/context" ) const tplStatus500 base.TplName = "status/500" diff --git a/routers/common/markup.go b/routers/common/markup.go index a1c2c37ac..7819ee722 100644 --- a/routers/common/markup.go +++ b/routers/common/markup.go @@ -9,11 +9,11 @@ import ( "net/http" "strings" - "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/markup" "code.gitea.io/gitea/modules/markup/markdown" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/util" + "code.gitea.io/gitea/services/context" "mvdan.cc/xurls/v2" ) diff --git a/routers/common/middleware.go b/routers/common/middleware.go index 8a39dda17..c7c75fb09 100644 --- a/routers/common/middleware.go +++ b/routers/common/middleware.go @@ -9,11 +9,11 @@ import ( "strings" "code.gitea.io/gitea/modules/cache" - "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/process" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/web/middleware" "code.gitea.io/gitea/modules/web/routing" + "code.gitea.io/gitea/services/context" "gitea.com/go-chi/session" "github.com/chi-middleware/proxy" @@ -38,6 +38,7 @@ func ProtocolMiddlewares() (handlers []any) { }) }) + // wrap the request and response, use the process context and add it to the process manager handlers = append(handlers, func(next http.Handler) http.Handler { return http.HandlerFunc(func(resp http.ResponseWriter, req *http.Request) { ctx, _, finished := process.GetManager().AddTypedContext(req.Context(), fmt.Sprintf("%s: %s", req.Method, req.RequestURI), process.RequestProcessType, true) diff --git a/routers/common/serve.go b/routers/common/serve.go index 8a7f8b333..446908db7 100644 --- a/routers/common/serve.go +++ b/routers/common/serve.go @@ -7,11 +7,11 @@ import ( "io" "time" - "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/httpcache" "code.gitea.io/gitea/modules/httplib" "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/services/context" ) // ServeBlob download a git.Blob diff --git a/routers/init.go b/routers/init.go index 5ae6a551f..28e1c4980 100644 --- a/routers/init.go +++ b/routers/init.go @@ -200,6 +200,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/install/install.go b/routers/install/install.go index 13504953c..5030306d8 100644 --- a/routers/install/install.go +++ b/routers/install/install.go @@ -22,7 +22,6 @@ import ( user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/auth/password/hash" "code.gitea.io/gitea/modules/base" - "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/generate" "code.gitea.io/gitea/modules/graceful" "code.gitea.io/gitea/modules/log" @@ -34,6 +33,7 @@ import ( "code.gitea.io/gitea/modules/web" "code.gitea.io/gitea/modules/web/middleware" "code.gitea.io/gitea/routers/common" + "code.gitea.io/gitea/services/context" "code.gitea.io/gitea/services/forms" "gitea.com/go-chi/session" diff --git a/routers/private/actions.go b/routers/private/actions.go index 1325913e1..397f20a09 100644 --- a/routers/private/actions.go +++ b/routers/private/actions.go @@ -13,11 +13,11 @@ import ( actions_model "code.gitea.io/gitea/models/actions" repo_model "code.gitea.io/gitea/models/repo" user_model "code.gitea.io/gitea/models/user" - "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/json" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/private" "code.gitea.io/gitea/modules/util" + "code.gitea.io/gitea/services/context" ) // GenerateActionsRunnerToken generates a new runner token for a given scope diff --git a/routers/private/default_branch.go b/routers/private/default_branch.go index a23e101e9..2e323129e 100644 --- a/routers/private/default_branch.go +++ b/routers/private/default_branch.go @@ -8,9 +8,9 @@ import ( "net/http" repo_model "code.gitea.io/gitea/models/repo" - gitea_context "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/private" + gitea_context "code.gitea.io/gitea/services/context" ) // SetDefaultBranch updates the default branch diff --git a/routers/private/hook_post_receive.go b/routers/private/hook_post_receive.go index 1b274ae15..f4c698d3e 100644 --- a/routers/private/hook_post_receive.go +++ b/routers/private/hook_post_receive.go @@ -10,7 +10,6 @@ import ( issues_model "code.gitea.io/gitea/models/issues" repo_model "code.gitea.io/gitea/models/repo" - gitea_context "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/private" @@ -18,6 +17,7 @@ import ( "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/util" "code.gitea.io/gitea/modules/web" + gitea_context "code.gitea.io/gitea/services/context" repo_service "code.gitea.io/gitea/services/repository" ) @@ -159,7 +159,7 @@ func HookPostReceive(ctx *gitea_context.PrivateContext) { } // If we've pushed a branch (and not deleted it) - if git.IsEmptyCommitID(newCommitID) && refFullName.IsBranch() { + if !git.IsEmptyCommitID(newCommitID) && refFullName.IsBranch() { // First ensure we have the repository loaded, we're allowed pulls requests and we can get the base repo if repo == nil { repo = loadRepository(ctx, ownerName, repoName) diff --git a/routers/private/hook_pre_receive.go b/routers/private/hook_pre_receive.go index f28ae4c0e..f45e57b9e 100644 --- a/routers/private/hook_pre_receive.go +++ b/routers/private/hook_pre_receive.go @@ -16,11 +16,11 @@ import ( access_model "code.gitea.io/gitea/models/perm/access" "code.gitea.io/gitea/models/unit" user_model "code.gitea.io/gitea/models/user" - gitea_context "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/private" "code.gitea.io/gitea/modules/web" + gitea_context "code.gitea.io/gitea/services/context" pull_service "code.gitea.io/gitea/services/pull" ) diff --git a/routers/private/hook_proc_receive.go b/routers/private/hook_proc_receive.go index 557712077..e4aabd858 100644 --- a/routers/private/hook_proc_receive.go +++ b/routers/private/hook_proc_receive.go @@ -7,12 +7,12 @@ import ( "net/http" repo_model "code.gitea.io/gitea/models/repo" - gitea_context "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/private" "code.gitea.io/gitea/modules/web" "code.gitea.io/gitea/services/agit" + gitea_context "code.gitea.io/gitea/services/context" ) // HookProcReceive proc-receive hook - only handles agit Proc-Receive requests at present diff --git a/routers/private/internal.go b/routers/private/internal.go index 407edebee..ede310113 100644 --- a/routers/private/internal.go +++ b/routers/private/internal.go @@ -8,11 +8,11 @@ import ( "net/http" "strings" - "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/private" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/web" + "code.gitea.io/gitea/services/context" "gitea.com/go-chi/binding" chi_middleware "github.com/go-chi/chi/v5/middleware" diff --git a/routers/private/internal_repo.go b/routers/private/internal_repo.go index 615239d47..e8ee8ba8a 100644 --- a/routers/private/internal_repo.go +++ b/routers/private/internal_repo.go @@ -9,10 +9,10 @@ import ( "net/http" repo_model "code.gitea.io/gitea/models/repo" - gitea_context "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/gitrepo" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/private" + gitea_context "code.gitea.io/gitea/services/context" ) // This file contains common functions relating to setting the Repository for the internal routes diff --git a/routers/private/key.go b/routers/private/key.go index 0096480d6..5b8f238a8 100644 --- a/routers/private/key.go +++ b/routers/private/key.go @@ -7,9 +7,9 @@ import ( "net/http" asymkey_model "code.gitea.io/gitea/models/asymkey" - "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/private" "code.gitea.io/gitea/modules/timeutil" + "code.gitea.io/gitea/services/context" ) // UpdatePublicKeyInRepo update public key and deploy key updates diff --git a/routers/private/mail.go b/routers/private/mail.go index e5e162c88..c19ee6789 100644 --- a/routers/private/mail.go +++ b/routers/private/mail.go @@ -11,11 +11,11 @@ import ( "code.gitea.io/gitea/models/db" user_model "code.gitea.io/gitea/models/user" - "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/json" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/private" "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/services/context" "code.gitea.io/gitea/services/mailer" ) diff --git a/routers/private/manager.go b/routers/private/manager.go index 397e6fac7..a6aa03e4e 100644 --- a/routers/private/manager.go +++ b/routers/private/manager.go @@ -8,7 +8,6 @@ import ( "net/http" "code.gitea.io/gitea/models/db" - "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/graceful" "code.gitea.io/gitea/modules/graceful/releasereopen" "code.gitea.io/gitea/modules/log" @@ -17,6 +16,7 @@ import ( "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/templates" "code.gitea.io/gitea/modules/web" + "code.gitea.io/gitea/services/context" ) // ReloadTemplates reloads all the templates diff --git a/routers/private/manager_process.go b/routers/private/manager_process.go index 68e4a2180..9a0298a37 100644 --- a/routers/private/manager_process.go +++ b/routers/private/manager_process.go @@ -11,10 +11,10 @@ import ( "runtime" "time" - "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/private" process_module "code.gitea.io/gitea/modules/process" + "code.gitea.io/gitea/services/context" ) // Processes prints out the processes diff --git a/routers/private/manager_unix.go b/routers/private/manager_unix.go index 09ced33b8..0c63ebc91 100644 --- a/routers/private/manager_unix.go +++ b/routers/private/manager_unix.go @@ -8,8 +8,8 @@ package private import ( "net/http" - "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/graceful" + "code.gitea.io/gitea/services/context" ) // Restart causes the server to perform a graceful restart diff --git a/routers/private/manager_windows.go b/routers/private/manager_windows.go index bd3c3c30d..f1b9365f5 100644 --- a/routers/private/manager_windows.go +++ b/routers/private/manager_windows.go @@ -8,9 +8,9 @@ package private import ( "net/http" - "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/graceful" "code.gitea.io/gitea/modules/private" + "code.gitea.io/gitea/services/context" ) // Restart is not implemented for Windows based servers as they can't fork diff --git a/routers/private/restore_repo.go b/routers/private/restore_repo.go index 7efc22a3d..4e95d3071 100644 --- a/routers/private/restore_repo.go +++ b/routers/private/restore_repo.go @@ -7,9 +7,9 @@ import ( "io" "net/http" - myCtx "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/json" "code.gitea.io/gitea/modules/private" + myCtx "code.gitea.io/gitea/services/context" "code.gitea.io/gitea/services/migrations" ) diff --git a/routers/private/serv.go b/routers/private/serv.go index 00731947a..ef3920d35 100644 --- a/routers/private/serv.go +++ b/routers/private/serv.go @@ -14,11 +14,11 @@ 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/context" "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/private" "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/services/context" repo_service "code.gitea.io/gitea/services/repository" wiki_service "code.gitea.io/gitea/services/wiki" ) diff --git a/routers/private/ssh_log.go b/routers/private/ssh_log.go index eacfa18f0..5bec632ea 100644 --- a/routers/private/ssh_log.go +++ b/routers/private/ssh_log.go @@ -6,11 +6,11 @@ package private import ( "net/http" - "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/private" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/web" + "code.gitea.io/gitea/services/context" ) // SSHLog hook to response ssh log diff --git a/routers/web/admin/admin.go b/routers/web/admin/admin.go index 58bb28173..fe98178ac 100644 --- a/routers/web/admin/admin.go +++ b/routers/web/admin/admin.go @@ -14,12 +14,12 @@ import ( activities_model "code.gitea.io/gitea/models/activities" "code.gitea.io/gitea/models/db" "code.gitea.io/gitea/modules/base" - "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/graceful" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/updatechecker" "code.gitea.io/gitea/modules/web" + "code.gitea.io/gitea/services/context" "code.gitea.io/gitea/services/cron" "code.gitea.io/gitea/services/forms" release_service "code.gitea.io/gitea/services/release" diff --git a/routers/web/admin/admin_test.go b/routers/web/admin/admin_test.go index 452291e17..c73780d60 100644 --- a/routers/web/admin/admin_test.go +++ b/routers/web/admin/admin_test.go @@ -8,9 +8,9 @@ import ( activities_model "code.gitea.io/gitea/models/activities" "code.gitea.io/gitea/models/unittest" - "code.gitea.io/gitea/modules/contexttest" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/test" + "code.gitea.io/gitea/services/contexttest" "github.com/stretchr/testify/assert" ) diff --git a/routers/web/admin/applications.go b/routers/web/admin/applications.go index b6f7bcd2a..858339807 100644 --- a/routers/web/admin/applications.go +++ b/routers/web/admin/applications.go @@ -10,9 +10,9 @@ import ( "code.gitea.io/gitea/models/auth" "code.gitea.io/gitea/models/db" "code.gitea.io/gitea/modules/base" - "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/setting" user_setting "code.gitea.io/gitea/routers/web/user/setting" + "code.gitea.io/gitea/services/context" ) var ( diff --git a/routers/web/admin/auths.go b/routers/web/admin/auths.go index 7fdd18dfa..ba487d104 100644 --- a/routers/web/admin/auths.go +++ b/routers/web/admin/auths.go @@ -16,7 +16,6 @@ import ( "code.gitea.io/gitea/models/db" "code.gitea.io/gitea/modules/auth/pam" "code.gitea.io/gitea/modules/base" - "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/util" @@ -27,6 +26,7 @@ import ( pam_service "code.gitea.io/gitea/services/auth/source/pam" "code.gitea.io/gitea/services/auth/source/smtp" "code.gitea.io/gitea/services/auth/source/sspi" + "code.gitea.io/gitea/services/context" "code.gitea.io/gitea/services/forms" "xorm.io/xorm/convert" diff --git a/routers/web/admin/config.go b/routers/web/admin/config.go index c827f2a4f..d9b197333 100644 --- a/routers/web/admin/config.go +++ b/routers/web/admin/config.go @@ -12,13 +12,13 @@ import ( system_model "code.gitea.io/gitea/models/system" "code.gitea.io/gitea/modules/base" "code.gitea.io/gitea/modules/container" - "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/json" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/setting/config" "code.gitea.io/gitea/modules/util" + "code.gitea.io/gitea/services/context" "code.gitea.io/gitea/services/mailer" "gitea.com/go-chi/session" diff --git a/routers/web/admin/diagnosis.go b/routers/web/admin/diagnosis.go index 2d550125d..020554a35 100644 --- a/routers/web/admin/diagnosis.go +++ b/routers/web/admin/diagnosis.go @@ -9,8 +9,8 @@ import ( "runtime/pprof" "time" - "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/httplib" + "code.gitea.io/gitea/services/context" ) func MonitorDiagnosis(ctx *context.Context) { diff --git a/routers/web/admin/emails.go b/routers/web/admin/emails.go index 59f80035d..2cf4035c6 100644 --- a/routers/web/admin/emails.go +++ b/routers/web/admin/emails.go @@ -11,10 +11,10 @@ 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/context" "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" ) const ( @@ -68,10 +68,10 @@ func Emails(ctx *context.Context) { opts.Keyword = ctx.FormTrim("q") opts.SortType = orderBy if len(ctx.FormString("is_activated")) != 0 { - opts.IsActivated = util.OptionalBoolOf(ctx.FormBool("activated")) + opts.IsActivated = optional.Some(ctx.FormBool("activated")) } if len(ctx.FormString("is_primary")) != 0 { - opts.IsPrimary = util.OptionalBoolOf(ctx.FormBool("primary")) + opts.IsPrimary = optional.Some(ctx.FormBool("primary")) } if len(opts.Keyword) == 0 || isKeywordValid(opts.Keyword) { diff --git a/routers/web/admin/hooks.go b/routers/web/admin/hooks.go index cd8cc29cd..8d59fbb85 100644 --- a/routers/web/admin/hooks.go +++ b/routers/web/admin/hooks.go @@ -8,9 +8,9 @@ import ( "code.gitea.io/gitea/models/webhook" "code.gitea.io/gitea/modules/base" - "code.gitea.io/gitea/modules/context" + "code.gitea.io/gitea/modules/optional" "code.gitea.io/gitea/modules/setting" - "code.gitea.io/gitea/modules/util" + "code.gitea.io/gitea/services/context" ) const ( @@ -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/notice.go b/routers/web/admin/notice.go index e1cb578d0..36303cbc0 100644 --- a/routers/web/admin/notice.go +++ b/routers/web/admin/notice.go @@ -11,9 +11,9 @@ import ( "code.gitea.io/gitea/models/db" system_model "code.gitea.io/gitea/models/system" "code.gitea.io/gitea/modules/base" - "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/services/context" ) const ( diff --git a/routers/web/admin/orgs.go b/routers/web/admin/orgs.go index 00131c9e2..c5454db71 100644 --- a/routers/web/admin/orgs.go +++ b/routers/web/admin/orgs.go @@ -8,10 +8,10 @@ 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/context" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/routers/web/explore" + "code.gitea.io/gitea/services/context" ) const ( diff --git a/routers/web/admin/packages.go b/routers/web/admin/packages.go index 35ce215be..39f064a1b 100644 --- a/routers/web/admin/packages.go +++ b/routers/web/admin/packages.go @@ -11,9 +11,9 @@ 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/context" + "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/queue.go b/routers/web/admin/queue.go index 18a8d7d3e..d8c50730b 100644 --- a/routers/web/admin/queue.go +++ b/routers/web/admin/queue.go @@ -7,9 +7,9 @@ import ( "net/http" "strconv" - "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/queue" "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/services/context" ) func Queues(ctx *context.Context) { diff --git a/routers/web/admin/repos.go b/routers/web/admin/repos.go index 45c280ef7..ddf444016 100644 --- a/routers/web/admin/repos.go +++ b/routers/web/admin/repos.go @@ -12,11 +12,11 @@ import ( repo_model "code.gitea.io/gitea/models/repo" user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/base" - "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/util" "code.gitea.io/gitea/routers/web/explore" + "code.gitea.io/gitea/services/context" repo_service "code.gitea.io/gitea/services/repository" ) diff --git a/routers/web/admin/runners.go b/routers/web/admin/runners.go index eaa268b4f..d73290a8d 100644 --- a/routers/web/admin/runners.go +++ b/routers/web/admin/runners.go @@ -4,8 +4,8 @@ package admin import ( - "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/services/context" ) func RedirectToDefaultSetting(ctx *context.Context) { diff --git a/routers/web/admin/stacktrace.go b/routers/web/admin/stacktrace.go index b603fb59a..d6def94bb 100644 --- a/routers/web/admin/stacktrace.go +++ b/routers/web/admin/stacktrace.go @@ -7,9 +7,9 @@ import ( "net/http" "runtime" - "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/process" "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/services/context" ) // Stacktrace show admin monitor goroutines page diff --git a/routers/web/admin/users.go b/routers/web/admin/users.go index adb9799c0..a34e0d0f0 100644 --- a/routers/web/admin/users.go +++ b/routers/web/admin/users.go @@ -19,7 +19,6 @@ import ( user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/auth/password" "code.gitea.io/gitea/modules/base" - "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/optional" "code.gitea.io/gitea/modules/setting" @@ -27,6 +26,7 @@ import ( "code.gitea.io/gitea/modules/web" "code.gitea.io/gitea/routers/web/explore" user_setting "code.gitea.io/gitea/routers/web/user/setting" + "code.gitea.io/gitea/services/context" "code.gitea.io/gitea/services/forms" "code.gitea.io/gitea/services/mailer" user_service "code.gitea.io/gitea/services/user" @@ -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) @@ -276,7 +276,7 @@ func ViewUser(ctx *context.Context) { OwnerID: u.ID, OrderBy: db.SearchOrderByAlphabetically, Private: true, - Collaborate: util.OptionalBoolFalse, + Collaborate: optional.Some(false), }) if err != nil { ctx.ServerError("SearchRepository", 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/admin/users_test.go b/routers/web/admin/users_test.go index 560ee70ea..f6f923785 100644 --- a/routers/web/admin/users_test.go +++ b/routers/web/admin/users_test.go @@ -8,10 +8,10 @@ import ( "code.gitea.io/gitea/models/unittest" user_model "code.gitea.io/gitea/models/user" - "code.gitea.io/gitea/modules/contexttest" "code.gitea.io/gitea/modules/setting" api "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/web" + "code.gitea.io/gitea/services/contexttest" "code.gitea.io/gitea/services/forms" "github.com/stretchr/testify/assert" diff --git a/routers/web/auth/2fa.go b/routers/web/auth/2fa.go index dc0062eba..f93177bf9 100644 --- a/routers/web/auth/2fa.go +++ b/routers/web/auth/2fa.go @@ -10,9 +10,9 @@ import ( "code.gitea.io/gitea/models/auth" user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/base" - "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/web" + "code.gitea.io/gitea/services/context" "code.gitea.io/gitea/services/externalaccount" "code.gitea.io/gitea/services/forms" ) diff --git a/routers/web/auth/auth.go b/routers/web/auth/auth.go index 91f631aca..1adb89184 100644 --- a/routers/web/auth/auth.go +++ b/routers/web/auth/auth.go @@ -17,7 +17,6 @@ import ( user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/auth/password" "code.gitea.io/gitea/modules/base" - "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/eventsource" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/optional" @@ -30,6 +29,7 @@ import ( "code.gitea.io/gitea/routers/utils" auth_service "code.gitea.io/gitea/services/auth" "code.gitea.io/gitea/services/auth/source/oauth2" + "code.gitea.io/gitea/services/context" "code.gitea.io/gitea/services/externalaccount" "code.gitea.io/gitea/services/forms" "code.gitea.io/gitea/services/mailer" @@ -171,7 +171,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 @@ -194,7 +194,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 @@ -414,7 +414,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 @@ -443,7 +443,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/auth/linkaccount.go b/routers/web/auth/linkaccount.go index 1d94e52fe..f744a57a4 100644 --- a/routers/web/auth/linkaccount.go +++ b/routers/web/auth/linkaccount.go @@ -12,13 +12,13 @@ import ( "code.gitea.io/gitea/models/auth" user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/base" - "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/util" "code.gitea.io/gitea/modules/web" auth_service "code.gitea.io/gitea/services/auth" "code.gitea.io/gitea/services/auth/source/oauth2" + "code.gitea.io/gitea/services/context" "code.gitea.io/gitea/services/externalaccount" "code.gitea.io/gitea/services/forms" diff --git a/routers/web/auth/oauth.go b/routers/web/auth/oauth.go index 4e4079d8f..f5ca0bda5 100644 --- a/routers/web/auth/oauth.go +++ b/routers/web/auth/oauth.go @@ -21,7 +21,6 @@ import ( auth_module "code.gitea.io/gitea/modules/auth" "code.gitea.io/gitea/modules/base" "code.gitea.io/gitea/modules/container" - "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/json" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/optional" @@ -33,6 +32,7 @@ import ( auth_service "code.gitea.io/gitea/services/auth" source_service "code.gitea.io/gitea/services/auth/source" "code.gitea.io/gitea/services/auth/source/oauth2" + "code.gitea.io/gitea/services/context" "code.gitea.io/gitea/services/externalaccount" "code.gitea.io/gitea/services/forms" user_service "code.gitea.io/gitea/services/user" diff --git a/routers/web/auth/openid.go b/routers/web/auth/openid.go index 29ef772b1..2143b8096 100644 --- a/routers/web/auth/openid.go +++ b/routers/web/auth/openid.go @@ -11,12 +11,12 @@ import ( user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/auth/openid" "code.gitea.io/gitea/modules/base" - "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/util" "code.gitea.io/gitea/modules/web" "code.gitea.io/gitea/services/auth" + "code.gitea.io/gitea/services/context" "code.gitea.io/gitea/services/forms" ) diff --git a/routers/web/auth/password.go b/routers/web/auth/password.go index 1f2d13328..c9e038604 100644 --- a/routers/web/auth/password.go +++ b/routers/web/auth/password.go @@ -12,7 +12,6 @@ import ( user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/auth/password" "code.gitea.io/gitea/modules/base" - "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/optional" "code.gitea.io/gitea/modules/setting" @@ -20,6 +19,7 @@ import ( "code.gitea.io/gitea/modules/web" "code.gitea.io/gitea/modules/web/middleware" "code.gitea.io/gitea/routers/utils" + "code.gitea.io/gitea/services/context" "code.gitea.io/gitea/services/forms" "code.gitea.io/gitea/services/mailer" user_service "code.gitea.io/gitea/services/user" diff --git a/routers/web/auth/webauthn.go b/routers/web/auth/webauthn.go index 95c8d262a..1079f44a0 100644 --- a/routers/web/auth/webauthn.go +++ b/routers/web/auth/webauthn.go @@ -11,9 +11,9 @@ import ( user_model "code.gitea.io/gitea/models/user" wa "code.gitea.io/gitea/modules/auth/webauthn" "code.gitea.io/gitea/modules/base" - "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/services/context" "code.gitea.io/gitea/services/externalaccount" "github.com/go-webauthn/webauthn/protocol" diff --git a/routers/web/devtest/devtest.go b/routers/web/devtest/devtest.go index 525ca9be5..dd20663f9 100644 --- a/routers/web/devtest/devtest.go +++ b/routers/web/devtest/devtest.go @@ -10,8 +10,8 @@ import ( "time" "code.gitea.io/gitea/modules/base" - "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/templates" + "code.gitea.io/gitea/services/context" ) // List all devtest templates, they will be used for e2e tests for the UI components diff --git a/routers/web/events/events.go b/routers/web/events/events.go index 1a5a162c1..52f20e07d 100644 --- a/routers/web/events/events.go +++ b/routers/web/events/events.go @@ -7,11 +7,11 @@ import ( "net/http" "time" - "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/eventsource" "code.gitea.io/gitea/modules/graceful" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/routers/web/auth" + "code.gitea.io/gitea/services/context" ) // Events listens for events diff --git a/routers/web/explore/code.go b/routers/web/explore/code.go index d81884ec6..2cde8b655 100644 --- a/routers/web/explore/code.go +++ b/routers/web/explore/code.go @@ -8,9 +8,9 @@ import ( repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/modules/base" - "code.gitea.io/gitea/modules/context" code_indexer "code.gitea.io/gitea/modules/indexer/code" "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/services/context" ) const ( diff --git a/routers/web/explore/org.go b/routers/web/explore/org.go index dc1318bee..f8fd6ec38 100644 --- a/routers/web/explore/org.go +++ b/routers/web/explore/org.go @@ -6,9 +6,10 @@ package explore import ( "code.gitea.io/gitea/models/db" user_model "code.gitea.io/gitea/models/user" - "code.gitea.io/gitea/modules/context" + "code.gitea.io/gitea/modules/container" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/structs" + "code.gitea.io/gitea/services/context" ) // Organizations render explore organizations page @@ -24,8 +25,16 @@ func Organizations(ctx *context.Context) { visibleTypes = append(visibleTypes, structs.VisibleTypeLimited, structs.VisibleTypePrivate) } - if ctx.FormString("sort") == "" { - ctx.SetFormString("sort", setting.UI.ExploreDefaultSort) + supportedSortOrders := container.SetOf( + "newest", + "oldest", + "alphabetically", + "reversealphabetically", + ) + sortOrder := ctx.FormString("sort") + if sortOrder == "" { + sortOrder = "newest" + ctx.SetFormString("sort", sortOrder) } RenderUserSearch(ctx, &user_model.SearchUserOptions{ @@ -33,5 +42,7 @@ func Organizations(ctx *context.Context) { Type: user_model.UserTypeOrganization, ListOptions: db.ListOptions{PageSize: setting.UI.ExplorePagingNum}, Visible: visibleTypes, + + SupportedSortOrders: supportedSortOrders, }, tplExploreUsers) } diff --git a/routers/web/explore/repo.go b/routers/web/explore/repo.go index 0446edebe..cf7381512 100644 --- a/routers/web/explore/repo.go +++ b/routers/web/explore/repo.go @@ -10,10 +10,10 @@ import ( "code.gitea.io/gitea/models/db" repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/modules/base" - "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/sitemap" + "code.gitea.io/gitea/services/context" ) const ( @@ -109,6 +109,21 @@ func RenderRepoSearch(ctx *context.Context, opts *RepoSearchOptions) { language := ctx.FormTrim("language") ctx.Data["Language"] = language + archived := ctx.FormOptionalBool("archived") + ctx.Data["IsArchived"] = archived + + fork := ctx.FormOptionalBool("fork") + ctx.Data["IsFork"] = fork + + mirror := ctx.FormOptionalBool("mirror") + ctx.Data["IsMirror"] = mirror + + template := ctx.FormOptionalBool("template") + ctx.Data["IsTemplate"] = template + + private := ctx.FormOptionalBool("private") + ctx.Data["IsPrivate"] = private + repos, count, err = repo_model.SearchRepository(ctx, &repo_model.SearchRepoOptions{ ListOptions: db.ListOptions{ Page: page, @@ -125,6 +140,11 @@ func RenderRepoSearch(ctx *context.Context, opts *RepoSearchOptions) { Language: language, IncludeDescription: setting.UI.SearchRepoDescription, OnlyShowRelevant: opts.OnlyShowRelevant, + Archived: archived, + Fork: fork, + Mirror: mirror, + Template: template, + IsPrivate: private, }) if err != nil { ctx.ServerError("SearchRepository", err) diff --git a/routers/web/explore/topic.go b/routers/web/explore/topic.go index bb1be310d..95fecfe2b 100644 --- a/routers/web/explore/topic.go +++ b/routers/web/explore/topic.go @@ -8,8 +8,8 @@ import ( "code.gitea.io/gitea/models/db" repo_model "code.gitea.io/gitea/models/repo" - "code.gitea.io/gitea/modules/context" api "code.gitea.io/gitea/modules/structs" + "code.gitea.io/gitea/services/context" "code.gitea.io/gitea/services/convert" ) diff --git a/routers/web/explore/user.go b/routers/web/explore/user.go index 09d31f95e..b79a79fb2 100644 --- a/routers/web/explore/user.go +++ b/routers/web/explore/user.go @@ -10,12 +10,13 @@ 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/context" + "code.gitea.io/gitea/modules/container" "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/optional" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/sitemap" "code.gitea.io/gitea/modules/structs" - "code.gitea.io/gitea/modules/util" + "code.gitea.io/gitea/services/context" ) const ( @@ -79,10 +80,16 @@ func RenderUserSearch(ctx *context.Context, opts *user_model.SearchUserOptions, fallthrough default: // in case the sortType is not valid, we set it to recentupdate + sortOrder = "recentupdate" ctx.Data["SortType"] = "recentupdate" orderBy = "`user`.updated_unix DESC" } + if opts.SupportedSortOrders != nil && !opts.SupportedSortOrders.Contains(sortOrder) { + ctx.NotFound("unsupported sort order", nil) + return + } + opts.Keyword = ctx.FormTrim("q") opts.OrderBy = orderBy if len(opts.Keyword) == 0 || isKeywordValid(opts.Keyword) { @@ -132,15 +139,25 @@ func Users(ctx *context.Context) { ctx.Data["PageIsExploreUsers"] = true ctx.Data["IsRepoIndexerEnabled"] = setting.Indexer.RepoIndexerEnabled - if ctx.FormString("sort") == "" { - ctx.SetFormString("sort", setting.UI.ExploreDefaultSort) + supportedSortOrders := container.SetOf( + "newest", + "oldest", + "alphabetically", + "reversealphabetically", + ) + sortOrder := ctx.FormString("sort") + if sortOrder == "" { + sortOrder = "newest" + ctx.SetFormString("sort", sortOrder) } RenderUserSearch(ctx, &user_model.SearchUserOptions{ Actor: ctx.Doer, Type: user_model.UserTypeIndividual, ListOptions: db.ListOptions{PageSize: setting.UI.ExplorePagingNum}, - IsActive: util.OptionalBoolTrue, + IsActive: optional.Some(true), Visible: []structs.VisibleType{structs.VisibleTypePublic, structs.VisibleTypeLimited, structs.VisibleTypePrivate}, + + SupportedSortOrders: supportedSortOrders, }, tplExploreUsers) } diff --git a/routers/web/feed/branch.go b/routers/web/feed/branch.go index f13038ff9..80ce2ad19 100644 --- a/routers/web/feed/branch.go +++ b/routers/web/feed/branch.go @@ -9,7 +9,7 @@ import ( "time" "code.gitea.io/gitea/models/repo" - "code.gitea.io/gitea/modules/context" + "code.gitea.io/gitea/services/context" "github.com/gorilla/feeds" ) diff --git a/routers/web/feed/convert.go b/routers/web/feed/convert.go index 5186d1a52..743465082 100644 --- a/routers/web/feed/convert.go +++ b/routers/web/feed/convert.go @@ -14,12 +14,12 @@ import ( activities_model "code.gitea.io/gitea/models/activities" repo_model "code.gitea.io/gitea/models/repo" - "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/markup" "code.gitea.io/gitea/modules/markup/markdown" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/templates" "code.gitea.io/gitea/modules/util" + "code.gitea.io/gitea/services/context" "github.com/gorilla/feeds" "github.com/jaytaylor/html2text" @@ -51,7 +51,7 @@ func toReleaseLink(ctx *context.Context, act *activities_model.Action) string { // renderMarkdown creates a minimal markdown render context from an action. // If rendering fails, the original markdown text is returned -func renderMarkdown(ctx *context.Context, act *activities_model.Action, content string) string { +func renderMarkdown(ctx *context.Context, act *activities_model.Action, content string) template.HTML { markdownCtx := &markup.RenderContext{ Ctx: ctx, Links: markup.Links{ @@ -65,7 +65,7 @@ func renderMarkdown(ctx *context.Context, act *activities_model.Action, content } markdown, err := markdown.RenderString(markdownCtx, content) if err != nil { - return content + return templates.SanitizeHTML(content) // old code did so: use SanitizeHTML to render in tmpl } return markdown } @@ -75,7 +75,11 @@ func feedActionsToFeedItems(ctx *context.Context, actions activities_model.Actio for _, act := range actions { act.LoadActUser(ctx) - var content, desc, title string + // TODO: the code seems quite strange (maybe not right) + // sometimes it uses text content but sometimes it uses HTML content + // it should clearly defines which kind of content it should use for the feed items: plan text or rich HTML + var title, desc string + var content template.HTML link := &feeds.Link{Href: act.GetCommentHTMLURL(ctx)} @@ -229,7 +233,7 @@ func feedActionsToFeedItems(ctx *context.Context, actions activities_model.Actio desc = act.GetIssueTitle(ctx) comment := act.GetIssueInfos()[1] if len(comment) != 0 { - desc += "\n\n" + renderMarkdown(ctx, act, comment) + desc += "\n\n" + string(renderMarkdown(ctx, act, comment)) } case activities_model.ActionMergePullRequest, activities_model.ActionAutoMergePullRequest: desc = act.GetIssueInfos()[1] @@ -240,7 +244,7 @@ func feedActionsToFeedItems(ctx *context.Context, actions activities_model.Actio } } if len(content) == 0 { - content = desc + content = templates.SanitizeHTML(desc) } // It's a common practice for feed generators to use plain text titles. @@ -261,7 +265,7 @@ func feedActionsToFeedItems(ctx *context.Context, actions activities_model.Actio }, Id: fmt.Sprintf("%v: %v", strconv.FormatInt(act.ID, 10), link.Href), Created: act.CreatedUnix.AsTime(), - Content: content, + Content: string(content), }) } return items, err @@ -290,7 +294,8 @@ func releasesToFeedItems(ctx *context.Context, releases []*repo_model.Release, i return nil, err } - var title, content string + var title string + var content template.HTML if rel.IsTag { title = rel.TagName @@ -319,7 +324,7 @@ func releasesToFeedItems(ctx *context.Context, releases []*repo_model.Release, i Email: rel.Publisher.GetEmail(), }, Id: fmt.Sprintf("%v: %v", strconv.FormatInt(rel.ID, 10), link.Href), - Content: content, + Content: string(content), }) } diff --git a/routers/web/feed/file.go b/routers/web/feed/file.go index 56a9c54dd..1ab768ff2 100644 --- a/routers/web/feed/file.go +++ b/routers/web/feed/file.go @@ -9,9 +9,9 @@ import ( "time" "code.gitea.io/gitea/models/repo" - "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/util" + "code.gitea.io/gitea/services/context" "github.com/gorilla/feeds" ) diff --git a/routers/web/feed/profile.go b/routers/web/feed/profile.go index 3feca68d6..08cbcd9e1 100644 --- a/routers/web/feed/profile.go +++ b/routers/web/feed/profile.go @@ -7,9 +7,9 @@ import ( "time" activities_model "code.gitea.io/gitea/models/activities" - "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/markup" "code.gitea.io/gitea/modules/markup/markdown" + "code.gitea.io/gitea/services/context" "github.com/gorilla/feeds" ) @@ -58,7 +58,7 @@ func showUserFeed(ctx *context.Context, formatType string) { feed := &feeds.Feed{ Title: ctx.Locale.TrString("home.feed_of", ctx.ContextUser.DisplayName()), Link: &feeds.Link{Href: ctx.ContextUser.HTMLURL()}, - Description: ctxUserDescription, + Description: string(ctxUserDescription), Created: time.Now(), } diff --git a/routers/web/feed/release.go b/routers/web/feed/release.go index 558c03dba..273f47e3b 100644 --- a/routers/web/feed/release.go +++ b/routers/web/feed/release.go @@ -8,7 +8,7 @@ import ( "code.gitea.io/gitea/models/db" repo_model "code.gitea.io/gitea/models/repo" - "code.gitea.io/gitea/modules/context" + "code.gitea.io/gitea/services/context" "github.com/gorilla/feeds" ) diff --git a/routers/web/feed/render.go b/routers/web/feed/render.go index 41f9af1c8..dc99fb49e 100644 --- a/routers/web/feed/render.go +++ b/routers/web/feed/render.go @@ -4,7 +4,7 @@ package feed import ( - "code.gitea.io/gitea/modules/context" + "code.gitea.io/gitea/services/context" ) // RenderBranchFeed render format for branch or file diff --git a/routers/web/feed/repo.go b/routers/web/feed/repo.go index 51c24510c..bfcc3a37d 100644 --- a/routers/web/feed/repo.go +++ b/routers/web/feed/repo.go @@ -8,7 +8,7 @@ import ( activities_model "code.gitea.io/gitea/models/activities" repo_model "code.gitea.io/gitea/models/repo" - "code.gitea.io/gitea/modules/context" + "code.gitea.io/gitea/services/context" "github.com/gorilla/feeds" ) diff --git a/routers/web/githttp.go b/routers/web/githttp.go index ab74e9a33..5f1dedce7 100644 --- a/routers/web/githttp.go +++ b/routers/web/githttp.go @@ -6,11 +6,10 @@ package web import ( "net/http" - "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/web" "code.gitea.io/gitea/routers/web/repo" - context_service "code.gitea.io/gitea/services/context" + "code.gitea.io/gitea/services/context" ) func requireSignIn(ctx *context.Context) { @@ -39,5 +38,5 @@ func gitHTTPRouters(m *web.Route) { m.Methods("GET,OPTIONS", "/objects/{head:[0-9a-f]{2}}/{hash:[0-9a-f]{38,62}}", repo.GetLooseObject) m.Methods("GET,OPTIONS", "/objects/pack/pack-{file:[0-9a-f]{40,64}}.pack", repo.GetPackFile) m.Methods("GET,OPTIONS", "/objects/pack/pack-{file:[0-9a-f]{40,64}}.idx", repo.GetIdxFile) - }, ignSignInAndCsrf, requireSignIn, repo.HTTPGitEnabledHandler, repo.CorsHandler(), context_service.UserAssignmentWeb()) + }, ignSignInAndCsrf, requireSignIn, repo.HTTPGitEnabledHandler, repo.CorsHandler(), context.UserAssignmentWeb()) } diff --git a/routers/web/goget.go b/routers/web/goget.go index c5b8b6cbc..8d5612ebf 100644 --- a/routers/web/goget.go +++ b/routers/web/goget.go @@ -12,9 +12,9 @@ import ( "strings" repo_model "code.gitea.io/gitea/models/repo" - "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/util" + "code.gitea.io/gitea/services/context" ) func goGet(ctx *context.Context) { diff --git a/routers/web/home.go b/routers/web/home.go index 2321b00ef..d4be0931e 100644 --- a/routers/web/home.go +++ b/routers/web/home.go @@ -12,15 +12,15 @@ import ( repo_model "code.gitea.io/gitea/models/repo" user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/base" - "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/optional" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/sitemap" "code.gitea.io/gitea/modules/structs" - "code.gitea.io/gitea/modules/util" "code.gitea.io/gitea/modules/web/middleware" "code.gitea.io/gitea/routers/web/auth" "code.gitea.io/gitea/routers/web/user" + "code.gitea.io/gitea/services/context" ) const ( @@ -71,7 +71,7 @@ func HomeSitemap(ctx *context.Context) { _, cnt, err := user_model.SearchUsers(ctx, &user_model.SearchUserOptions{ Type: user_model.UserTypeIndividual, ListOptions: db.ListOptions{PageSize: 1}, - IsActive: util.OptionalBoolTrue, + IsActive: optional.Some(true), Visible: []structs.VisibleType{structs.VisibleTypePublic}, }) if err != nil { diff --git a/routers/web/misc/markup.go b/routers/web/misc/markup.go index c91da9a7f..2dbbd6fc0 100644 --- a/routers/web/misc/markup.go +++ b/routers/web/misc/markup.go @@ -5,10 +5,10 @@ package misc import ( - "code.gitea.io/gitea/modules/context" api "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/web" "code.gitea.io/gitea/routers/common" + "code.gitea.io/gitea/services/context" ) // Markup render markup document to HTML diff --git a/routers/web/misc/swagger-forgejo.go b/routers/web/misc/swagger-forgejo.go index 2f539e955..e3aff02c5 100644 --- a/routers/web/misc/swagger-forgejo.go +++ b/routers/web/misc/swagger-forgejo.go @@ -7,7 +7,7 @@ import ( "net/http" "code.gitea.io/gitea/modules/base" - "code.gitea.io/gitea/modules/context" + "code.gitea.io/gitea/services/context" ) // tplSwagger swagger page template diff --git a/routers/web/misc/swagger.go b/routers/web/misc/swagger.go index 72c09a378..5fddfa888 100644 --- a/routers/web/misc/swagger.go +++ b/routers/web/misc/swagger.go @@ -7,7 +7,7 @@ import ( "net/http" "code.gitea.io/gitea/modules/base" - "code.gitea.io/gitea/modules/context" + "code.gitea.io/gitea/services/context" ) // tplSwagger swagger page template diff --git a/routers/web/nodeinfo.go b/routers/web/nodeinfo.go index 01b71e708..f1cc7bf53 100644 --- a/routers/web/nodeinfo.go +++ b/routers/web/nodeinfo.go @@ -7,8 +7,8 @@ import ( "fmt" "net/http" - "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/services/context" ) type nodeInfoLinks struct { diff --git a/routers/web/org/home.go b/routers/web/org/home.go index 36f543dc4..71d10f3a4 100644 --- a/routers/web/org/home.go +++ b/routers/web/org/home.go @@ -12,7 +12,6 @@ import ( "code.gitea.io/gitea/models/organization" repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/modules/base" - "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/markup" @@ -20,6 +19,7 @@ import ( "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/util" shared_user "code.gitea.io/gitea/routers/web/shared/user" + "code.gitea.io/gitea/services/context" ) const ( @@ -85,6 +85,21 @@ func Home(ctx *context.Context) { page = 1 } + archived := ctx.FormOptionalBool("archived") + ctx.Data["IsArchived"] = archived + + fork := ctx.FormOptionalBool("fork") + ctx.Data["IsFork"] = fork + + mirror := ctx.FormOptionalBool("mirror") + ctx.Data["IsMirror"] = mirror + + template := ctx.FormOptionalBool("template") + ctx.Data["IsTemplate"] = template + + private := ctx.FormOptionalBool("private") + ctx.Data["IsPrivate"] = private + var ( repos []*repo_model.Repository count int64 @@ -102,6 +117,11 @@ func Home(ctx *context.Context) { Actor: ctx.Doer, Language: language, IncludeDescription: setting.UI.SearchRepoDescription, + Archived: archived, + Fork: fork, + Mirror: mirror, + Template: template, + IsPrivate: private, }) if err != nil { ctx.ServerError("SearchRepository", err) diff --git a/routers/web/org/members.go b/routers/web/org/members.go index 15a615c70..9a3d60e12 100644 --- a/routers/web/org/members.go +++ b/routers/web/org/members.go @@ -10,10 +10,10 @@ import ( "code.gitea.io/gitea/models" "code.gitea.io/gitea/models/organization" "code.gitea.io/gitea/modules/base" - "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/setting" shared_user "code.gitea.io/gitea/routers/web/shared/user" + "code.gitea.io/gitea/services/context" ) const ( diff --git a/routers/web/org/org.go b/routers/web/org/org.go index 1e4544730..f94dd16ea 100644 --- a/routers/web/org/org.go +++ b/routers/web/org/org.go @@ -12,10 +12,10 @@ import ( "code.gitea.io/gitea/models/organization" user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/base" - "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/web" + "code.gitea.io/gitea/services/context" "code.gitea.io/gitea/services/forms" ) diff --git a/routers/web/org/org_labels.go b/routers/web/org/org_labels.go index f78bd0027..02eae8052 100644 --- a/routers/web/org/org_labels.go +++ b/routers/web/org/org_labels.go @@ -8,10 +8,10 @@ import ( "code.gitea.io/gitea/models/db" issues_model "code.gitea.io/gitea/models/issues" - "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/label" repo_module "code.gitea.io/gitea/modules/repository" "code.gitea.io/gitea/modules/web" + "code.gitea.io/gitea/services/context" "code.gitea.io/gitea/services/forms" ) diff --git a/routers/web/org/projects.go b/routers/web/org/projects.go index f062127d2..ad8bb90d9 100644 --- a/routers/web/org/projects.go +++ b/routers/web/org/projects.go @@ -17,12 +17,13 @@ import ( attachment_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/models/unit" "code.gitea.io/gitea/modules/base" - "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/json" + "code.gitea.io/gitea/modules/optional" "code.gitea.io/gitea/modules/setting" - "code.gitea.io/gitea/modules/util" + "code.gitea.io/gitea/modules/templates" "code.gitea.io/gitea/modules/web" shared_user "code.gitea.io/gitea/routers/web/shared/user" + "code.gitea.io/gitea/services/context" "code.gitea.io/gitea/services/forms" ) @@ -66,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, @@ -78,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 { @@ -104,7 +105,7 @@ func Projects(ctx *context.Context) { } for _, project := range projects { - project.RenderedContent = project.Description + project.RenderedContent = templates.SanitizeHTML(project.Description) // FIXME: is it right? why not render? } err = shared_user.LoadHeaderCount(ctx) @@ -387,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 } @@ -395,7 +396,7 @@ func ViewProject(ctx *context.Context) { } } - project.RenderedContent = project.Description + project.RenderedContent = templates.SanitizeHTML(project.Description) // FIXME: is it right? why not render? ctx.Data["LinkedPRs"] = linkedPrsMap ctx.Data["PageIsViewProjects"] = true ctx.Data["CanWriteProjects"] = canWriteProjects(ctx) diff --git a/routers/web/org/projects_test.go b/routers/web/org/projects_test.go index 8053ab4cf..f4ccfe1c0 100644 --- a/routers/web/org/projects_test.go +++ b/routers/web/org/projects_test.go @@ -7,8 +7,8 @@ import ( "testing" "code.gitea.io/gitea/models/unittest" - "code.gitea.io/gitea/modules/contexttest" "code.gitea.io/gitea/routers/web/org" + "code.gitea.io/gitea/services/contexttest" "github.com/stretchr/testify/assert" ) diff --git a/routers/web/org/setting.go b/routers/web/org/setting.go index 47d0063f7..494ada432 100644 --- a/routers/web/org/setting.go +++ b/routers/web/org/setting.go @@ -14,7 +14,6 @@ import ( user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/models/webhook" "code.gitea.io/gitea/modules/base" - "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/optional" repo_module "code.gitea.io/gitea/modules/repository" @@ -22,6 +21,7 @@ import ( "code.gitea.io/gitea/modules/web" shared_user "code.gitea.io/gitea/routers/web/shared/user" user_setting "code.gitea.io/gitea/routers/web/user/setting" + "code.gitea.io/gitea/services/context" "code.gitea.io/gitea/services/forms" org_service "code.gitea.io/gitea/services/org" repo_service "code.gitea.io/gitea/services/repository" diff --git a/routers/web/org/setting/blocked_users.go b/routers/web/org/setting/blocked_users.go index d872dabd8..b23f5ba59 100644 --- a/routers/web/org/setting/blocked_users.go +++ b/routers/web/org/setting/blocked_users.go @@ -10,7 +10,7 @@ import ( "code.gitea.io/gitea/models/db" user_model "code.gitea.io/gitea/models/user" - "code.gitea.io/gitea/modules/context" + "code.gitea.io/gitea/services/context" user_service "code.gitea.io/gitea/services/user" ) diff --git a/routers/web/org/setting/runners.go b/routers/web/org/setting/runners.go index c3c771036..fe0570923 100644 --- a/routers/web/org/setting/runners.go +++ b/routers/web/org/setting/runners.go @@ -4,7 +4,7 @@ package setting import ( - "code.gitea.io/gitea/modules/context" + "code.gitea.io/gitea/services/context" ) func RedirectToDefaultSetting(ctx *context.Context) { diff --git a/routers/web/org/setting_oauth2.go b/routers/web/org/setting_oauth2.go index ca4fe09f3..7f855795d 100644 --- a/routers/web/org/setting_oauth2.go +++ b/routers/web/org/setting_oauth2.go @@ -10,10 +10,10 @@ import ( "code.gitea.io/gitea/models/auth" "code.gitea.io/gitea/models/db" "code.gitea.io/gitea/modules/base" - "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/setting" shared_user "code.gitea.io/gitea/routers/web/shared/user" user_setting "code.gitea.io/gitea/routers/web/user/setting" + "code.gitea.io/gitea/services/context" ) const ( diff --git a/routers/web/org/setting_packages.go b/routers/web/org/setting_packages.go index 796829d34..af9836e42 100644 --- a/routers/web/org/setting_packages.go +++ b/routers/web/org/setting_packages.go @@ -8,10 +8,10 @@ import ( "net/http" "code.gitea.io/gitea/modules/base" - "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/setting" shared "code.gitea.io/gitea/routers/web/shared/packages" shared_user "code.gitea.io/gitea/routers/web/shared/user" + "code.gitea.io/gitea/services/context" ) const ( diff --git a/routers/web/org/teams.go b/routers/web/org/teams.go index 71fe99c97..fd7486cac 100644 --- a/routers/web/org/teams.go +++ b/routers/web/org/teams.go @@ -20,11 +20,11 @@ import ( unit_model "code.gitea.io/gitea/models/unit" user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/base" - "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/web" shared_user "code.gitea.io/gitea/routers/web/shared/user" + "code.gitea.io/gitea/services/context" "code.gitea.io/gitea/services/convert" "code.gitea.io/gitea/services/forms" org_service "code.gitea.io/gitea/services/org" diff --git a/routers/web/repo/actions/actions.go b/routers/web/repo/actions/actions.go index 19aca2671..f27329aa0 100644 --- a/routers/web/repo/actions/actions.go +++ b/routers/web/repo/actions/actions.go @@ -15,11 +15,11 @@ import ( "code.gitea.io/gitea/modules/actions" "code.gitea.io/gitea/modules/base" "code.gitea.io/gitea/modules/container" - "code.gitea.io/gitea/modules/context" "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" "github.com/nektos/act/pkg/model" @@ -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 05675d73c..23ce70a15 100644 --- a/routers/web/repo/actions/view.go +++ b/routers/web/repo/actions/view.go @@ -13,6 +13,7 @@ import ( "io" "net/http" "net/url" + "strconv" "strings" "time" @@ -22,12 +23,13 @@ import ( "code.gitea.io/gitea/models/unit" "code.gitea.io/gitea/modules/actions" "code.gitea.io/gitea/modules/base" - context_module "code.gitea.io/gitea/modules/context" + "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/storage" "code.gitea.io/gitea/modules/timeutil" "code.gitea.io/gitea/modules/util" "code.gitea.io/gitea/modules/web" actions_service "code.gitea.io/gitea/services/actions" + context_module "code.gitea.io/gitea/services/context" "xorm.io/builder" ) @@ -312,10 +314,14 @@ func ViewPost(ctx *context_module.Context) { } // Rerun will rerun jobs in the given run -// jobIndex = 0 means rerun all jobs +// If jobIndexStr is a blank string, it means rerun all jobs func Rerun(ctx *context_module.Context) { runIndex := ctx.ParamsInt64("run") - jobIndex := ctx.ParamsInt64("job") + jobIndexStr := ctx.Params("job") + var jobIndex int64 + if jobIndexStr != "" { + jobIndex, _ = strconv.ParseInt(jobIndexStr, 10, 64) + } run, err := actions_model.GetRunByIndex(ctx, ctx.Repo.Repository.ID, runIndex) if err != nil { @@ -347,7 +353,7 @@ func Rerun(ctx *context_module.Context) { return } - if jobIndex != 0 { + if jobIndexStr != "" { jobs = []*actions_model.ActionRunJob{job} } @@ -642,6 +648,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/activity.go b/routers/web/repo/activity.go index af99c4ed9..6f6641cc6 100644 --- a/routers/web/repo/activity.go +++ b/routers/web/repo/activity.go @@ -10,7 +10,7 @@ import ( activities_model "code.gitea.io/gitea/models/activities" "code.gitea.io/gitea/models/unit" "code.gitea.io/gitea/modules/base" - "code.gitea.io/gitea/modules/context" + "code.gitea.io/gitea/services/context" ) const ( diff --git a/routers/web/repo/attachment.go b/routers/web/repo/attachment.go index 8c322b45e..f0c5622ae 100644 --- a/routers/web/repo/attachment.go +++ b/routers/web/repo/attachment.go @@ -9,15 +9,15 @@ import ( access_model "code.gitea.io/gitea/models/perm/access" repo_model "code.gitea.io/gitea/models/repo" - "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/httpcache" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/storage" - "code.gitea.io/gitea/modules/upload" "code.gitea.io/gitea/modules/util" "code.gitea.io/gitea/routers/common" "code.gitea.io/gitea/services/attachment" + "code.gitea.io/gitea/services/context" + "code.gitea.io/gitea/services/context/upload" repo_service "code.gitea.io/gitea/services/repository" ) diff --git a/routers/web/repo/badges/badges.go b/routers/web/repo/badges/badges.go index 8fe99c7fc..7f4549d60 100644 --- a/routers/web/repo/badges/badges.go +++ b/routers/web/repo/badges/badges.go @@ -11,8 +11,8 @@ import ( actions_model "code.gitea.io/gitea/models/actions" repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/models/unit" - context_module "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/setting" + context_module "code.gitea.io/gitea/services/context" ) func getBadgeURL(ctx *context_module.Context, label, text, color string) string { diff --git a/routers/web/repo/blame.go b/routers/web/repo/blame.go index 2c938dc96..0f464ad07 100644 --- a/routers/web/repo/blame.go +++ b/routers/web/repo/blame.go @@ -12,7 +12,6 @@ import ( user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/charset" - "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/highlight" "code.gitea.io/gitea/modules/log" @@ -20,6 +19,7 @@ import ( "code.gitea.io/gitea/modules/templates" "code.gitea.io/gitea/modules/timeutil" "code.gitea.io/gitea/modules/util" + "code.gitea.io/gitea/services/context" files_service "code.gitea.io/gitea/services/repository/files" ) diff --git a/routers/web/repo/branch.go b/routers/web/repo/branch.go index c543160f4..ae51f0596 100644 --- a/routers/web/repo/branch.go +++ b/routers/web/repo/branch.go @@ -16,14 +16,15 @@ import ( repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/models/unit" "code.gitea.io/gitea/modules/base" - "code.gitea.io/gitea/modules/context" "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" "code.gitea.io/gitea/modules/web" "code.gitea.io/gitea/routers/utils" + "code.gitea.io/gitea/services/context" "code.gitea.io/gitea/services/forms" release_service "code.gitea.io/gitea/services/release" repo_service "code.gitea.io/gitea/services/repository" @@ -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/cherry_pick.go b/routers/web/repo/cherry_pick.go index 63516bb4d..90dae704f 100644 --- a/routers/web/repo/cherry_pick.go +++ b/routers/web/repo/cherry_pick.go @@ -12,11 +12,11 @@ import ( git_model "code.gitea.io/gitea/models/git" "code.gitea.io/gitea/models/unit" "code.gitea.io/gitea/modules/base" - "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/git" "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" "code.gitea.io/gitea/services/repository/files" ) diff --git a/routers/web/repo/code_frequency.go b/routers/web/repo/code_frequency.go index 48ade655b..c76f492da 100644 --- a/routers/web/repo/code_frequency.go +++ b/routers/web/repo/code_frequency.go @@ -8,7 +8,7 @@ import ( "net/http" "code.gitea.io/gitea/modules/base" - "code.gitea.io/gitea/modules/context" + "code.gitea.io/gitea/services/context" contributors_service "code.gitea.io/gitea/services/repository" ) diff --git a/routers/web/repo/commit.go b/routers/web/repo/commit.go index 3b6e48228..7c89ce5a3 100644 --- a/routers/web/repo/commit.go +++ b/routers/web/repo/commit.go @@ -19,7 +19,6 @@ import ( user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/base" "code.gitea.io/gitea/modules/charset" - "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/gitgraph" "code.gitea.io/gitea/modules/gitrepo" @@ -27,6 +26,7 @@ import ( "code.gitea.io/gitea/modules/markup" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/util" + "code.gitea.io/gitea/services/context" "code.gitea.io/gitea/services/gitdiff" git_service "code.gitea.io/gitea/services/repository" ) diff --git a/routers/web/repo/compare.go b/routers/web/repo/compare.go index 535487d5f..b0570f97c 100644 --- a/routers/web/repo/compare.go +++ b/routers/web/repo/compare.go @@ -25,7 +25,6 @@ import ( user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/base" "code.gitea.io/gitea/modules/charset" - "code.gitea.io/gitea/modules/context" csv_module "code.gitea.io/gitea/modules/csv" "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/gitrepo" @@ -35,8 +34,9 @@ import ( "code.gitea.io/gitea/modules/setting" api "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/typesniffer" - "code.gitea.io/gitea/modules/upload" "code.gitea.io/gitea/modules/util" + "code.gitea.io/gitea/services/context" + "code.gitea.io/gitea/services/context/upload" "code.gitea.io/gitea/services/gitdiff" ) diff --git a/routers/web/repo/contributors.go b/routers/web/repo/contributors.go index bcfef7580..5fda17469 100644 --- a/routers/web/repo/contributors.go +++ b/routers/web/repo/contributors.go @@ -8,7 +8,7 @@ import ( "net/http" "code.gitea.io/gitea/modules/base" - "code.gitea.io/gitea/modules/context" + "code.gitea.io/gitea/services/context" contributors_service "code.gitea.io/gitea/services/repository" ) diff --git a/routers/web/repo/download.go b/routers/web/repo/download.go index a9e2e2b2f..c4a8baecc 100644 --- a/routers/web/repo/download.go +++ b/routers/web/repo/download.go @@ -9,7 +9,6 @@ import ( "time" git_model "code.gitea.io/gitea/models/git" - "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/httpcache" "code.gitea.io/gitea/modules/lfs" @@ -17,6 +16,7 @@ import ( "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/storage" "code.gitea.io/gitea/routers/common" + "code.gitea.io/gitea/services/context" ) // ServeBlobOrLFS download a git.Blob redirecting to LFS if necessary diff --git a/routers/web/repo/editor.go b/routers/web/repo/editor.go index 075477e5f..4f26c0c52 100644 --- a/routers/web/repo/editor.go +++ b/routers/web/repo/editor.go @@ -17,17 +17,17 @@ import ( user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/base" "code.gitea.io/gitea/modules/charset" - "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/json" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/markup" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/typesniffer" - "code.gitea.io/gitea/modules/upload" "code.gitea.io/gitea/modules/util" "code.gitea.io/gitea/modules/web" "code.gitea.io/gitea/routers/utils" + "code.gitea.io/gitea/services/context" + "code.gitea.io/gitea/services/context/upload" "code.gitea.io/gitea/services/forms" files_service "code.gitea.io/gitea/services/repository/files" ) @@ -382,7 +382,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), @@ -394,7 +394,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()), @@ -590,7 +590,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), @@ -797,7 +797,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/editor_test.go b/routers/web/repo/editor_test.go index c28c3ef1d..313fcfe33 100644 --- a/routers/web/repo/editor_test.go +++ b/routers/web/repo/editor_test.go @@ -7,9 +7,9 @@ import ( "testing" "code.gitea.io/gitea/models/unittest" - "code.gitea.io/gitea/modules/contexttest" "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/gitrepo" + "code.gitea.io/gitea/services/contexttest" "github.com/stretchr/testify/assert" ) diff --git a/routers/web/repo/find.go b/routers/web/repo/find.go index daefe59c8..07b372279 100644 --- a/routers/web/repo/find.go +++ b/routers/web/repo/find.go @@ -7,7 +7,7 @@ import ( "net/http" "code.gitea.io/gitea/modules/base" - "code.gitea.io/gitea/modules/context" + "code.gitea.io/gitea/services/context" ) const ( diff --git a/routers/web/repo/flags/manage.go b/routers/web/repo/flags/manage.go index 840f6c377..377a5c20f 100644 --- a/routers/web/repo/flags/manage.go +++ b/routers/web/repo/flags/manage.go @@ -7,9 +7,9 @@ import ( "net/http" "code.gitea.io/gitea/modules/base" - "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/services/context" ) const ( diff --git a/routers/web/repo/githttp.go b/routers/web/repo/githttp.go index f52abbfb0..9f3b63698 100644 --- a/routers/web/repo/githttp.go +++ b/routers/web/repo/githttp.go @@ -24,13 +24,13 @@ 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/context" "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/log" repo_module "code.gitea.io/gitea/modules/repository" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/util" + "code.gitea.io/gitea/services/context" repo_service "code.gitea.io/gitea/services/repository" "github.com/go-chi/cors" diff --git a/routers/web/repo/helper.go b/routers/web/repo/helper.go index a98abe566..5e1e11601 100644 --- a/routers/web/repo/helper.go +++ b/routers/web/repo/helper.go @@ -8,8 +8,8 @@ import ( "sort" "code.gitea.io/gitea/models/user" - "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/git" + "code.gitea.io/gitea/services/context" ) func MakeSelfOnTop(doer *user.User, users []*user.User) []*user.User { diff --git a/routers/web/repo/issue.go b/routers/web/repo/issue.go index 963c6289b..2e2d12672 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" @@ -31,7 +32,6 @@ import ( user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/base" "code.gitea.io/gitea/modules/container" - "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/emoji" "code.gitea.io/gitea/modules/git" issue_indexer "code.gitea.io/gitea/modules/indexer/issues" @@ -39,16 +39,19 @@ import ( "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/markup" "code.gitea.io/gitea/modules/markup/markdown" + "code.gitea.io/gitea/modules/optional" repo_module "code.gitea.io/gitea/modules/repository" "code.gitea.io/gitea/modules/setting" api "code.gitea.io/gitea/modules/structs" + "code.gitea.io/gitea/modules/templates" "code.gitea.io/gitea/modules/templates/vars" "code.gitea.io/gitea/modules/timeutil" - "code.gitea.io/gitea/modules/upload" "code.gitea.io/gitea/modules/util" "code.gitea.io/gitea/modules/web" "code.gitea.io/gitea/routers/utils" asymkey_service "code.gitea.io/gitea/services/asymkey" + "code.gitea.io/gitea/services/context" + "code.gitea.io/gitea/services/context/upload" "code.gitea.io/gitea/services/convert" "code.gitea.io/gitea/services/forms" issue_service "code.gitea.io/gitea/services/issue" @@ -143,7 +146,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") @@ -244,18 +247,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) { @@ -275,10 +278,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) @@ -434,7 +437,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 @@ -464,10 +467,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" @@ -516,7 +519,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 } @@ -558,7 +561,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) @@ -566,7 +569,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) @@ -594,7 +597,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 { @@ -604,7 +607,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 { @@ -617,7 +620,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 { @@ -627,7 +630,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 { @@ -1020,7 +1023,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) @@ -1032,14 +1035,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 } @@ -1768,7 +1771,7 @@ func ViewIssue(ctx *context.Context) { // so "|" is used as delimeter to mark the new format if comment.Content[0] != '|' { // handle old time comments that have formatted text stored - comment.RenderedContent = comment.Content + comment.RenderedContent = templates.SanitizeHTML(comment.Content) comment.Content = "" } else { // else it's just a duration in seconds to pass on to the frontend @@ -2509,14 +2512,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 ( @@ -2529,7 +2532,7 @@ func SearchIssues(ctx *context.Context) { Private: false, AllPublic: true, TopicOnly: false, - Collaborate: util.OptionalBoolNone, + Collaborate: optional.None[bool](), // This needs to be a column that is not nil in fixtures or // MySQL will return different results when sorting by null in some cases OrderBy: db.SearchOrderByAlphabetically, @@ -2553,7 +2556,7 @@ func SearchIssues(ctx *context.Context) { opts.OwnerID = owner.ID opts.AllLimited = false opts.AllPublic = false - opts.Collaborate = util.OptionalBoolFalse + opts.Collaborate = optional.Some(false) } if ctx.FormString("team") != "" { if ctx.FormString("owner") == "" { @@ -2594,14 +2597,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 @@ -2740,14 +2741,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") @@ -2799,14 +2800,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 @@ -3322,7 +3321,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(), @@ -3429,7 +3428,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(), @@ -3572,8 +3571,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/issue_content_history.go b/routers/web/repo/issue_content_history.go index 4dc537a06..dfee2863b 100644 --- a/routers/web/repo/issue_content_history.go +++ b/routers/web/repo/issue_content_history.go @@ -11,11 +11,11 @@ import ( "code.gitea.io/gitea/models/avatars" issues_model "code.gitea.io/gitea/models/issues" - "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/templates" "code.gitea.io/gitea/modules/timeutil" + "code.gitea.io/gitea/services/context" "github.com/sergi/go-diff/diffmatchpatch" ) diff --git a/routers/web/repo/issue_dependency.go b/routers/web/repo/issue_dependency.go index 022ec3ae3..e3b85ee63 100644 --- a/routers/web/repo/issue_dependency.go +++ b/routers/web/repo/issue_dependency.go @@ -8,8 +8,8 @@ import ( issues_model "code.gitea.io/gitea/models/issues" access_model "code.gitea.io/gitea/models/perm/access" - "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/services/context" ) // AddDependency adds new dependencies diff --git a/routers/web/repo/issue_label.go b/routers/web/repo/issue_label.go index dd3e2803b..9dedaefa4 100644 --- a/routers/web/repo/issue_label.go +++ b/routers/web/repo/issue_label.go @@ -10,12 +10,12 @@ import ( issues_model "code.gitea.io/gitea/models/issues" "code.gitea.io/gitea/models/organization" "code.gitea.io/gitea/modules/base" - "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/label" "code.gitea.io/gitea/modules/log" repo_module "code.gitea.io/gitea/modules/repository" "code.gitea.io/gitea/modules/timeutil" "code.gitea.io/gitea/modules/web" + "code.gitea.io/gitea/services/context" "code.gitea.io/gitea/services/forms" issue_service "code.gitea.io/gitea/services/issue" ) diff --git a/routers/web/repo/issue_label_test.go b/routers/web/repo/issue_label_test.go index 742f12114..93fc72300 100644 --- a/routers/web/repo/issue_label_test.go +++ b/routers/web/repo/issue_label_test.go @@ -10,10 +10,10 @@ import ( issues_model "code.gitea.io/gitea/models/issues" "code.gitea.io/gitea/models/unittest" - "code.gitea.io/gitea/modules/contexttest" "code.gitea.io/gitea/modules/repository" "code.gitea.io/gitea/modules/test" "code.gitea.io/gitea/modules/web" + "code.gitea.io/gitea/services/contexttest" "code.gitea.io/gitea/services/forms" "github.com/stretchr/testify/assert" diff --git a/routers/web/repo/issue_lock.go b/routers/web/repo/issue_lock.go index f83109d9b..1d5fc8a5f 100644 --- a/routers/web/repo/issue_lock.go +++ b/routers/web/repo/issue_lock.go @@ -5,8 +5,8 @@ package repo import ( issues_model "code.gitea.io/gitea/models/issues" - "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/web" + "code.gitea.io/gitea/services/context" "code.gitea.io/gitea/services/forms" ) diff --git a/routers/web/repo/issue_pin.go b/routers/web/repo/issue_pin.go index 9f334129f..365c81268 100644 --- a/routers/web/repo/issue_pin.go +++ b/routers/web/repo/issue_pin.go @@ -7,9 +7,9 @@ import ( "net/http" issues_model "code.gitea.io/gitea/models/issues" - "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/json" "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/services/context" ) // IssuePinOrUnpin pin or unpin a Issue diff --git a/routers/web/repo/issue_stopwatch.go b/routers/web/repo/issue_stopwatch.go index ab9fe3e69..70d42b27c 100644 --- a/routers/web/repo/issue_stopwatch.go +++ b/routers/web/repo/issue_stopwatch.go @@ -9,8 +9,8 @@ import ( "code.gitea.io/gitea/models/db" issues_model "code.gitea.io/gitea/models/issues" - "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/eventsource" + "code.gitea.io/gitea/services/context" ) // IssueStopwatch creates or stops a stopwatch for the given issue. diff --git a/routers/web/repo/issue_timetrack.go b/routers/web/repo/issue_timetrack.go index c9bf861b8..241e43404 100644 --- a/routers/web/repo/issue_timetrack.go +++ b/routers/web/repo/issue_timetrack.go @@ -9,9 +9,9 @@ import ( "code.gitea.io/gitea/models/db" issues_model "code.gitea.io/gitea/models/issues" - "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/util" "code.gitea.io/gitea/modules/web" + "code.gitea.io/gitea/services/context" "code.gitea.io/gitea/services/forms" ) diff --git a/routers/web/repo/issue_watch.go b/routers/web/repo/issue_watch.go index 1f51ceba5..8b033f3b1 100644 --- a/routers/web/repo/issue_watch.go +++ b/routers/web/repo/issue_watch.go @@ -9,8 +9,8 @@ import ( issues_model "code.gitea.io/gitea/models/issues" "code.gitea.io/gitea/modules/base" - "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/services/context" ) const ( diff --git a/routers/web/repo/middlewares.go b/routers/web/repo/middlewares.go index ee4964965..ddda9f3ff 100644 --- a/routers/web/repo/middlewares.go +++ b/routers/web/repo/middlewares.go @@ -9,9 +9,9 @@ import ( system_model "code.gitea.io/gitea/models/system" user_model "code.gitea.io/gitea/models/user" - "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/optional" + "code.gitea.io/gitea/services/context" user_service "code.gitea.io/gitea/services/user" ) diff --git a/routers/web/repo/migrate.go b/routers/web/repo/migrate.go index b70901d5f..97b0c425e 100644 --- a/routers/web/repo/migrate.go +++ b/routers/web/repo/migrate.go @@ -15,13 +15,13 @@ import ( repo_model "code.gitea.io/gitea/models/repo" user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/base" - "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/lfs" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/util" "code.gitea.io/gitea/modules/web" + "code.gitea.io/gitea/services/context" "code.gitea.io/gitea/services/forms" "code.gitea.io/gitea/services/migrations" "code.gitea.io/gitea/services/task" diff --git a/routers/web/repo/milestone.go b/routers/web/repo/milestone.go index 19db2abd6..1c53f73fd 100644 --- a/routers/web/repo/milestone.go +++ b/routers/web/repo/milestone.go @@ -12,13 +12,13 @@ import ( "code.gitea.io/gitea/models/db" issues_model "code.gitea.io/gitea/models/issues" "code.gitea.io/gitea/modules/base" - "code.gitea.io/gitea/modules/context" "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" "code.gitea.io/gitea/services/issue" @@ -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.GetTemplatesFromDefaultBranch(ctx.Repo.Repository, ctx.Repo.GitRepo) ctx.Data["NewIssueChooseTemplate"] = len(ret) > 0 diff --git a/routers/web/repo/packages.go b/routers/web/repo/packages.go index ac9e64d77..11874ab0d 100644 --- a/routers/web/repo/packages.go +++ b/routers/web/repo/packages.go @@ -10,9 +10,9 @@ import ( "code.gitea.io/gitea/models/packages" "code.gitea.io/gitea/models/unit" "code.gitea.io/gitea/modules/base" - "code.gitea.io/gitea/modules/context" + "code.gitea.io/gitea/modules/optional" "code.gitea.io/gitea/modules/setting" - "code.gitea.io/gitea/modules/util" + "code.gitea.io/gitea/services/context" ) const ( @@ -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/patch.go b/routers/web/repo/patch.go index 03ea03467..d234f6c96 100644 --- a/routers/web/repo/patch.go +++ b/routers/web/repo/patch.go @@ -10,10 +10,10 @@ import ( git_model "code.gitea.io/gitea/models/git" "code.gitea.io/gitea/models/unit" "code.gitea.io/gitea/modules/base" - "code.gitea.io/gitea/modules/context" "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" "code.gitea.io/gitea/services/repository/files" ) diff --git a/routers/web/repo/projects.go b/routers/web/repo/projects.go index cc0127e7e..4c171defb 100644 --- a/routers/web/repo/projects.go +++ b/routers/web/repo/projects.go @@ -17,13 +17,13 @@ import ( attachment_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/models/unit" "code.gitea.io/gitea/modules/base" - "code.gitea.io/gitea/modules/context" "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/projects_test.go b/routers/web/repo/projects_test.go index 6698d4702..479f8c55a 100644 --- a/routers/web/repo/projects_test.go +++ b/routers/web/repo/projects_test.go @@ -7,7 +7,7 @@ import ( "testing" "code.gitea.io/gitea/models/unittest" - "code.gitea.io/gitea/modules/contexttest" + "code.gitea.io/gitea/services/contexttest" "github.com/stretchr/testify/assert" ) diff --git a/routers/web/repo/pull.go b/routers/web/repo/pull.go index 561039c41..c93d342e6 100644 --- a/routers/web/repo/pull.go +++ b/routers/web/repo/pull.go @@ -28,7 +28,6 @@ import ( "code.gitea.io/gitea/models/unit" user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/base" - "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/emoji" "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/gitrepo" @@ -37,12 +36,13 @@ import ( "code.gitea.io/gitea/modules/optional" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/structs" - "code.gitea.io/gitea/modules/upload" "code.gitea.io/gitea/modules/util" "code.gitea.io/gitea/modules/web" "code.gitea.io/gitea/routers/utils" asymkey_service "code.gitea.io/gitea/services/asymkey" "code.gitea.io/gitea/services/automerge" + "code.gitea.io/gitea/services/context" + "code.gitea.io/gitea/services/context/upload" "code.gitea.io/gitea/services/forms" "code.gitea.io/gitea/services/gitdiff" notify_service "code.gitea.io/gitea/services/notify" @@ -1159,7 +1159,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), @@ -1173,7 +1173,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), @@ -1305,7 +1305,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), @@ -1318,7 +1318,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), @@ -1348,7 +1348,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), @@ -1525,7 +1525,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), @@ -1534,8 +1534,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/pull_review.go b/routers/web/repo/pull_review.go index 798d3d545..ead7592fd 100644 --- a/routers/web/repo/pull_review.go +++ b/routers/web/repo/pull_review.go @@ -11,12 +11,12 @@ import ( issues_model "code.gitea.io/gitea/models/issues" pull_model "code.gitea.io/gitea/models/pull" "code.gitea.io/gitea/modules/base" - "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/json" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/setting" - "code.gitea.io/gitea/modules/upload" "code.gitea.io/gitea/modules/web" + "code.gitea.io/gitea/services/context" + "code.gitea.io/gitea/services/context/upload" "code.gitea.io/gitea/services/forms" pull_service "code.gitea.io/gitea/services/pull" ) diff --git a/routers/web/repo/pull_review_test.go b/routers/web/repo/pull_review_test.go index 68f68d7bb..d87656f79 100644 --- a/routers/web/repo/pull_review_test.go +++ b/routers/web/repo/pull_review_test.go @@ -10,9 +10,9 @@ import ( "code.gitea.io/gitea/models/db" issues_model "code.gitea.io/gitea/models/issues" "code.gitea.io/gitea/models/unittest" - "code.gitea.io/gitea/modules/context" - "code.gitea.io/gitea/modules/contexttest" "code.gitea.io/gitea/modules/templates" + "code.gitea.io/gitea/services/context" + "code.gitea.io/gitea/services/contexttest" "code.gitea.io/gitea/services/pull" "github.com/stretchr/testify/assert" diff --git a/routers/web/repo/recent_commits.go b/routers/web/repo/recent_commits.go index 3507cb875..c158fb30b 100644 --- a/routers/web/repo/recent_commits.go +++ b/routers/web/repo/recent_commits.go @@ -8,7 +8,7 @@ import ( "net/http" "code.gitea.io/gitea/modules/base" - "code.gitea.io/gitea/modules/context" + "code.gitea.io/gitea/services/context" contributors_service "code.gitea.io/gitea/services/repository" ) diff --git a/routers/web/repo/release.go b/routers/web/repo/release.go index 79f3181ba..95447a8f5 100644 --- a/routers/web/repo/release.go +++ b/routers/web/repo/release.go @@ -17,16 +17,17 @@ import ( "code.gitea.io/gitea/models/unit" user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/base" - "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/log" "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/upload" "code.gitea.io/gitea/modules/util" "code.gitea.io/gitea/modules/web" "code.gitea.io/gitea/routers/web/feed" + "code.gitea.io/gitea/services/context" + "code.gitea.io/gitea/services/context/upload" "code.gitea.io/gitea/services/forms" releaseservice "code.gitea.io/gitea/services/release" ) @@ -112,7 +113,7 @@ func getReleaseInfos(ctx *context.Context, opts *repo_model.FindReleasesOptions) cacheUsers[r.PublisherID] = r.Publisher } - r.Note, err = markdown.RenderString(&markup.RenderContext{ + r.RenderedNote, err = markdown.RenderString(&markup.RenderContext{ Links: markup.Links{ Base: ctx.Repo.RepoLink, }, @@ -228,7 +229,7 @@ func TagsList(ctx *context.Context) { // the drafts should also be included because a real tag might be used as a draft. IncludeDrafts: true, IncludeTags: true, - HasSha1: util.OptionalBoolTrue, + HasSha1: optional.Some(true), RepoID: ctx.Repo.Repository.ID, } diff --git a/routers/web/repo/release_test.go b/routers/web/repo/release_test.go index c4a2c1904..7ebea4c3f 100644 --- a/routers/web/repo/release_test.go +++ b/routers/web/repo/release_test.go @@ -10,8 +10,8 @@ import ( repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/models/unit" "code.gitea.io/gitea/models/unittest" - "code.gitea.io/gitea/modules/contexttest" "code.gitea.io/gitea/modules/web" + "code.gitea.io/gitea/services/contexttest" "code.gitea.io/gitea/services/forms" "github.com/stretchr/testify/assert" diff --git a/routers/web/repo/render.go b/routers/web/repo/render.go index 7eb5a42aa..10fa21c60 100644 --- a/routers/web/repo/render.go +++ b/routers/web/repo/render.go @@ -10,11 +10,11 @@ import ( "path" "code.gitea.io/gitea/modules/charset" - "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/markup" "code.gitea.io/gitea/modules/typesniffer" "code.gitea.io/gitea/modules/util" + "code.gitea.io/gitea/services/context" ) // RenderFile renders a file by repos path diff --git a/routers/web/repo/repo.go b/routers/web/repo/repo.go index 17e5d9b58..77aab8354 100644 --- a/routers/web/repo/repo.go +++ b/routers/web/repo/repo.go @@ -21,7 +21,6 @@ import ( user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/base" "code.gitea.io/gitea/modules/cache" - "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/optional" @@ -31,6 +30,7 @@ import ( api "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/util" "code.gitea.io/gitea/modules/web" + "code.gitea.io/gitea/services/context" "code.gitea.io/gitea/services/convert" "code.gitea.io/gitea/services/forms" repo_service "code.gitea.io/gitea/services/repository" @@ -244,7 +244,7 @@ func CreatePost(ctx *context.Context) { var repo *repo_model.Repository var err error if form.RepoTemplate > 0 { - opts := repo_module.GenerateRepoOptions{ + opts := repo_service.GenerateRepoOptions{ Name: form.RepoName, Description: form.Description, Private: form.Private, @@ -553,33 +553,33 @@ func SearchRepo(ctx *context.Context) { PriorityOwnerID: ctx.FormInt64("priority_owner_id"), TeamID: ctx.FormInt64("team_id"), TopicOnly: ctx.FormBool("topic"), - Collaborate: util.OptionalBoolNone, + Collaborate: optional.None[bool](), Private: ctx.IsSigned && (ctx.FormString("private") == "" || ctx.FormBool("private")), - Template: util.OptionalBoolNone, + Template: optional.None[bool](), StarredByID: ctx.FormInt64("starredBy"), IncludeDescription: ctx.FormBool("includeDesc"), } if ctx.FormString("template") != "" { - opts.Template = util.OptionalBoolOf(ctx.FormBool("template")) + opts.Template = optional.Some(ctx.FormBool("template")) } if ctx.FormBool("exclusive") { - opts.Collaborate = util.OptionalBoolFalse + opts.Collaborate = optional.Some(false) } mode := ctx.FormString("mode") switch mode { case "source": - opts.Fork = util.OptionalBoolFalse - opts.Mirror = util.OptionalBoolFalse + opts.Fork = optional.Some(false) + opts.Mirror = optional.Some(false) case "fork": - opts.Fork = util.OptionalBoolTrue + opts.Fork = optional.Some(true) case "mirror": - opts.Mirror = util.OptionalBoolTrue + opts.Mirror = optional.Some(true) case "collaborative": - opts.Mirror = util.OptionalBoolFalse - opts.Collaborate = util.OptionalBoolTrue + opts.Mirror = optional.Some(false) + opts.Collaborate = optional.Some(true) case "": default: ctx.Error(http.StatusUnprocessableEntity, fmt.Sprintf("Invalid search mode: \"%s\"", mode)) @@ -587,11 +587,11 @@ func SearchRepo(ctx *context.Context) { } if ctx.FormString("archived") != "" { - opts.Archived = util.OptionalBoolOf(ctx.FormBool("archived")) + opts.Archived = optional.Some(ctx.FormBool("archived")) } if ctx.FormString("is_private") != "" { - opts.IsPrivate = util.OptionalBoolOf(ctx.FormBool("is_private")) + opts.IsPrivate = optional.Some(ctx.FormBool("is_private")) } sortMode := ctx.FormString("sort") diff --git a/routers/web/repo/search.go b/routers/web/repo/search.go index 29b3b7b47..74970c02c 100644 --- a/routers/web/repo/search.go +++ b/routers/web/repo/search.go @@ -7,9 +7,9 @@ import ( "net/http" "code.gitea.io/gitea/modules/base" - "code.gitea.io/gitea/modules/context" code_indexer "code.gitea.io/gitea/modules/indexer/code" "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/services/context" "code.gitea.io/gitea/services/repository/files" ) diff --git a/routers/web/repo/setting/avatar.go b/routers/web/repo/setting/avatar.go index 44468d266..504f57cfc 100644 --- a/routers/web/repo/setting/avatar.go +++ b/routers/web/repo/setting/avatar.go @@ -8,11 +8,11 @@ import ( "fmt" "io" - "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/typesniffer" "code.gitea.io/gitea/modules/web" + "code.gitea.io/gitea/services/context" "code.gitea.io/gitea/services/forms" repo_service "code.gitea.io/gitea/services/repository" ) diff --git a/routers/web/repo/setting/collaboration.go b/routers/web/repo/setting/collaboration.go index a73a7e5a8..75b55151e 100644 --- a/routers/web/repo/setting/collaboration.go +++ b/routers/web/repo/setting/collaboration.go @@ -14,10 +14,10 @@ import ( repo_model "code.gitea.io/gitea/models/repo" unit_model "code.gitea.io/gitea/models/unit" user_model "code.gitea.io/gitea/models/user" - "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/log" repo_module "code.gitea.io/gitea/modules/repository" "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/services/context" "code.gitea.io/gitea/services/mailer" org_service "code.gitea.io/gitea/services/org" repo_service "code.gitea.io/gitea/services/repository" diff --git a/routers/web/repo/setting/default_branch.go b/routers/web/repo/setting/default_branch.go index 9bf54e706..610fc5bcd 100644 --- a/routers/web/repo/setting/default_branch.go +++ b/routers/web/repo/setting/default_branch.go @@ -7,11 +7,11 @@ import ( "net/http" repo_model "code.gitea.io/gitea/models/repo" - "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/routers/web/repo" + "code.gitea.io/gitea/services/context" notify_service "code.gitea.io/gitea/services/notify" ) diff --git a/routers/web/repo/setting/deploy_key.go b/routers/web/repo/setting/deploy_key.go index 3d4420006..abc3eb4af 100644 --- a/routers/web/repo/setting/deploy_key.go +++ b/routers/web/repo/setting/deploy_key.go @@ -8,11 +8,11 @@ import ( asymkey_model "code.gitea.io/gitea/models/asymkey" "code.gitea.io/gitea/models/db" - "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/web" asymkey_service "code.gitea.io/gitea/services/asymkey" + "code.gitea.io/gitea/services/context" "code.gitea.io/gitea/services/forms" ) diff --git a/routers/web/repo/setting/git_hooks.go b/routers/web/repo/setting/git_hooks.go index 551327d44..217a01c90 100644 --- a/routers/web/repo/setting/git_hooks.go +++ b/routers/web/repo/setting/git_hooks.go @@ -6,8 +6,8 @@ package setting import ( "net/http" - "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/git" + "code.gitea.io/gitea/services/context" ) // GitHooks hooks of a repository diff --git a/routers/web/repo/setting/lfs.go b/routers/web/repo/setting/lfs.go index 53e7b22d1..9b66af37b 100644 --- a/routers/web/repo/setting/lfs.go +++ b/routers/web/repo/setting/lfs.go @@ -18,7 +18,6 @@ import ( "code.gitea.io/gitea/modules/base" "code.gitea.io/gitea/modules/charset" "code.gitea.io/gitea/modules/container" - "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/git/pipeline" "code.gitea.io/gitea/modules/lfs" @@ -28,6 +27,7 @@ import ( "code.gitea.io/gitea/modules/storage" "code.gitea.io/gitea/modules/typesniffer" "code.gitea.io/gitea/modules/util" + "code.gitea.io/gitea/services/context" ) const ( diff --git a/routers/web/repo/setting/protected_branch.go b/routers/web/repo/setting/protected_branch.go index 827ebea7f..b37520a39 100644 --- a/routers/web/repo/setting/protected_branch.go +++ b/routers/web/repo/setting/protected_branch.go @@ -15,9 +15,9 @@ import ( "code.gitea.io/gitea/models/perm" access_model "code.gitea.io/gitea/models/perm/access" "code.gitea.io/gitea/modules/base" - "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/web" "code.gitea.io/gitea/routers/web/repo" + "code.gitea.io/gitea/services/context" "code.gitea.io/gitea/services/forms" pull_service "code.gitea.io/gitea/services/pull" "code.gitea.io/gitea/services/repository" diff --git a/routers/web/repo/setting/protected_tag.go b/routers/web/repo/setting/protected_tag.go index 46addb3f0..2c25b650b 100644 --- a/routers/web/repo/setting/protected_tag.go +++ b/routers/web/repo/setting/protected_tag.go @@ -13,9 +13,9 @@ import ( "code.gitea.io/gitea/models/perm" access_model "code.gitea.io/gitea/models/perm/access" "code.gitea.io/gitea/modules/base" - "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/web" + "code.gitea.io/gitea/services/context" "code.gitea.io/gitea/services/forms" ) diff --git a/routers/web/repo/setting/runners.go b/routers/web/repo/setting/runners.go index 8d4112c15..a47d3b45e 100644 --- a/routers/web/repo/setting/runners.go +++ b/routers/web/repo/setting/runners.go @@ -11,10 +11,10 @@ import ( actions_model "code.gitea.io/gitea/models/actions" "code.gitea.io/gitea/models/db" "code.gitea.io/gitea/modules/base" - "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/setting" actions_shared "code.gitea.io/gitea/routers/web/shared/actions" shared_user "code.gitea.io/gitea/routers/web/shared/user" + "code.gitea.io/gitea/services/context" ) const ( diff --git a/routers/web/repo/setting/secrets.go b/routers/web/repo/setting/secrets.go index cf427b2c4..d4d56bfc5 100644 --- a/routers/web/repo/setting/secrets.go +++ b/routers/web/repo/setting/secrets.go @@ -8,10 +8,10 @@ import ( "net/http" "code.gitea.io/gitea/modules/base" - "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/setting" shared "code.gitea.io/gitea/routers/web/shared/secrets" shared_user "code.gitea.io/gitea/routers/web/shared/user" + "code.gitea.io/gitea/services/context" ) const ( diff --git a/routers/web/repo/setting/setting.go b/routers/web/repo/setting/setting.go index 0fdae7ec5..99c15b74f 100644 --- a/routers/web/repo/setting/setting.go +++ b/routers/web/repo/setting/setting.go @@ -19,7 +19,6 @@ import ( unit_model "code.gitea.io/gitea/models/unit" user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/base" - "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/indexer/code" "code.gitea.io/gitea/modules/indexer/stats" @@ -31,6 +30,7 @@ import ( "code.gitea.io/gitea/modules/validation" "code.gitea.io/gitea/modules/web" asymkey_service "code.gitea.io/gitea/services/asymkey" + "code.gitea.io/gitea/services/context" "code.gitea.io/gitea/services/forms" "code.gitea.io/gitea/services/migrations" mirror_service "code.gitea.io/gitea/services/mirror" diff --git a/routers/web/repo/setting/settings_test.go b/routers/web/repo/setting/settings_test.go index 1ed6858b9..b77111384 100644 --- a/routers/web/repo/setting/settings_test.go +++ b/routers/web/repo/setting/settings_test.go @@ -14,10 +14,10 @@ import ( repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/models/unittest" user_model "code.gitea.io/gitea/models/user" - "code.gitea.io/gitea/modules/context" - "code.gitea.io/gitea/modules/contexttest" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/web" + "code.gitea.io/gitea/services/context" + "code.gitea.io/gitea/services/contexttest" "code.gitea.io/gitea/services/forms" repo_service "code.gitea.io/gitea/services/repository" diff --git a/routers/web/repo/setting/variables.go b/routers/web/repo/setting/variables.go index 428aa0bd5..45b6c0f39 100644 --- a/routers/web/repo/setting/variables.go +++ b/routers/web/repo/setting/variables.go @@ -8,10 +8,10 @@ import ( "net/http" "code.gitea.io/gitea/modules/base" - "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/setting" shared "code.gitea.io/gitea/routers/web/shared/actions" shared_user "code.gitea.io/gitea/routers/web/shared/user" + "code.gitea.io/gitea/services/context" ) const ( diff --git a/routers/web/repo/setting/webhook.go b/routers/web/repo/setting/webhook.go index 7bbe4d81a..4e967c86d 100644 --- a/routers/web/repo/setting/webhook.go +++ b/routers/web/repo/setting/webhook.go @@ -18,7 +18,6 @@ import ( user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/models/webhook" "code.gitea.io/gitea/modules/base" - "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/json" "code.gitea.io/gitea/modules/setting" @@ -26,6 +25,7 @@ import ( "code.gitea.io/gitea/modules/util" "code.gitea.io/gitea/modules/web" webhook_module "code.gitea.io/gitea/modules/webhook" + "code.gitea.io/gitea/services/context" "code.gitea.io/gitea/services/convert" "code.gitea.io/gitea/services/forms" webhook_service "code.gitea.io/gitea/services/webhook" diff --git a/routers/web/repo/topic.go b/routers/web/repo/topic.go index d0e706c5b..d81a695df 100644 --- a/routers/web/repo/topic.go +++ b/routers/web/repo/topic.go @@ -8,8 +8,8 @@ import ( "strings" repo_model "code.gitea.io/gitea/models/repo" - "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/services/context" ) // TopicsPost response for creating repository diff --git a/routers/web/repo/treelist.go b/routers/web/repo/treelist.go index c364e7090..d11af4669 100644 --- a/routers/web/repo/treelist.go +++ b/routers/web/repo/treelist.go @@ -7,8 +7,8 @@ import ( "net/http" "code.gitea.io/gitea/modules/base" - "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/git" + "code.gitea.io/gitea/services/context" "github.com/go-enry/go-enry/v2" ) diff --git a/routers/web/repo/view.go b/routers/web/repo/view.go index 32c09bb5f..27984e762 100644 --- a/routers/web/repo/view.go +++ b/routers/web/repo/view.go @@ -35,8 +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/context" "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/highlight" "code.gitea.io/gitea/modules/lfs" @@ -48,6 +46,7 @@ import ( "code.gitea.io/gitea/modules/typesniffer" "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" files_service "code.gitea.io/gitea/services/repository/files" @@ -881,25 +880,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/repo/wiki.go b/routers/web/repo/wiki.go index 157ebd4d5..f0743cc89 100644 --- a/routers/web/repo/wiki.go +++ b/routers/web/repo/wiki.go @@ -18,7 +18,6 @@ import ( "code.gitea.io/gitea/models/unit" "code.gitea.io/gitea/modules/base" "code.gitea.io/gitea/modules/charset" - "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/gitrepo" "code.gitea.io/gitea/modules/log" @@ -29,6 +28,7 @@ import ( "code.gitea.io/gitea/modules/util" "code.gitea.io/gitea/modules/web" "code.gitea.io/gitea/routers/common" + "code.gitea.io/gitea/services/context" "code.gitea.io/gitea/services/forms" notify_service "code.gitea.io/gitea/services/notify" wiki_service "code.gitea.io/gitea/services/wiki" diff --git a/routers/web/repo/wiki_test.go b/routers/web/repo/wiki_test.go index d3decdae2..49c83cfef 100644 --- a/routers/web/repo/wiki_test.go +++ b/routers/web/repo/wiki_test.go @@ -11,10 +11,10 @@ import ( repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/models/unittest" - "code.gitea.io/gitea/modules/contexttest" "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/gitrepo" "code.gitea.io/gitea/modules/web" + "code.gitea.io/gitea/services/contexttest" "code.gitea.io/gitea/services/forms" wiki_service "code.gitea.io/gitea/services/wiki" diff --git a/routers/web/shared/actions/runners.go b/routers/web/shared/actions/runners.go index ae9a37672..34b796944 100644 --- a/routers/web/shared/actions/runners.go +++ b/routers/web/shared/actions/runners.go @@ -8,10 +8,10 @@ import ( actions_model "code.gitea.io/gitea/models/actions" "code.gitea.io/gitea/models/db" - "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/util" "code.gitea.io/gitea/modules/web" + "code.gitea.io/gitea/services/context" "code.gitea.io/gitea/services/forms" ) diff --git a/routers/web/shared/actions/variables.go b/routers/web/shared/actions/variables.go index 07a057520..0f705399c 100644 --- a/routers/web/shared/actions/variables.go +++ b/routers/web/shared/actions/variables.go @@ -10,9 +10,9 @@ import ( actions_model "code.gitea.io/gitea/models/actions" "code.gitea.io/gitea/models/db" - "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/web" + "code.gitea.io/gitea/services/context" "code.gitea.io/gitea/services/forms" secret_service "code.gitea.io/gitea/services/secrets" ) diff --git a/routers/web/shared/packages/packages.go b/routers/web/shared/packages/packages.go index 30c25374d..57671ad8f 100644 --- a/routers/web/shared/packages/packages.go +++ b/routers/web/shared/packages/packages.go @@ -12,10 +12,10 @@ import ( packages_model "code.gitea.io/gitea/models/packages" user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/base" - "code.gitea.io/gitea/modules/context" "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" cargo_service "code.gitea.io/gitea/services/packages/cargo" container_service "code.gitea.io/gitea/services/packages/container" @@ -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/secrets/secrets.go b/routers/web/shared/secrets/secrets.go index c805da734..73505ec37 100644 --- a/routers/web/shared/secrets/secrets.go +++ b/routers/web/shared/secrets/secrets.go @@ -6,10 +6,10 @@ package secrets import ( "code.gitea.io/gitea/models/db" secret_model "code.gitea.io/gitea/models/secret" - "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/web" "code.gitea.io/gitea/routers/web/shared/actions" + "code.gitea.io/gitea/services/context" "code.gitea.io/gitea/services/forms" secret_service "code.gitea.io/gitea/services/secrets" ) diff --git a/routers/web/shared/user/header.go b/routers/web/shared/user/header.go index 07026e484..f007772d6 100644 --- a/routers/web/shared/user/header.go +++ b/routers/web/shared/user/header.go @@ -13,12 +13,12 @@ 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/context" "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" + "code.gitea.io/gitea/services/context" ) // prepareContextForCommonProfile store some common data into context data for user's profile related pages (including the nav menu) @@ -36,8 +36,9 @@ func PrepareContextForProfileBigAvatar(ctx *context.Context) { ctx.Data["IsBlocked"] = ctx.Doer != nil && user_model.IsBlocked(ctx, ctx.Doer.ID, ctx.ContextUser.ID) ctx.Data["ShowUserEmail"] = setting.UI.ShowUserEmail && ctx.ContextUser.Email != "" && ctx.IsSigned && !ctx.ContextUser.KeepEmailPrivate - ctx.Data["ContextUserLocationMapURL"] = setting.Service.UserLocationMapURL + url.QueryEscape(ctx.ContextUser.Location) - + if setting.Service.UserLocationMapURL != "" { + ctx.Data["ContextUserLocationMapURL"] = setting.Service.UserLocationMapURL + url.QueryEscape(ctx.ContextUser.Location) + } // Show OpenID URIs openIDs, err := user_model.GetUserOpenIDs(ctx, ctx.ContextUser.ID) if err != nil { @@ -114,7 +115,7 @@ func LoadHeaderCount(ctx *context.Context) error { Actor: ctx.Doer, OwnerID: ctx.ContextUser.ID, Private: ctx.IsSigned, - Collaborate: util.OptionalBoolFalse, + Collaborate: optional.Some(false), IncludeDescription: setting.UI.SearchRepoDescription, }) if err != nil { @@ -130,7 +131,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/swagger_json.go b/routers/web/swagger_json.go index 42e9dbe96..fc39b504a 100644 --- a/routers/web/swagger_json.go +++ b/routers/web/swagger_json.go @@ -4,7 +4,7 @@ package web import ( - "code.gitea.io/gitea/modules/context" + "code.gitea.io/gitea/services/context" ) // SwaggerV1Json render swagger v1 json diff --git a/routers/web/user/avatar.go b/routers/web/user/avatar.go index 772cc38be..04f510161 100644 --- a/routers/web/user/avatar.go +++ b/routers/web/user/avatar.go @@ -9,8 +9,8 @@ import ( "code.gitea.io/gitea/models/avatars" user_model "code.gitea.io/gitea/models/user" - "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/httpcache" + "code.gitea.io/gitea/services/context" ) func cacheableRedirect(ctx *context.Context, location string) { diff --git a/routers/web/user/code.go b/routers/web/user/code.go index ee514a7cf..eb711b76e 100644 --- a/routers/web/user/code.go +++ b/routers/web/user/code.go @@ -8,10 +8,10 @@ import ( repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/modules/base" - "code.gitea.io/gitea/modules/context" code_indexer "code.gitea.io/gitea/modules/indexer/code" "code.gitea.io/gitea/modules/setting" shared_user "code.gitea.io/gitea/routers/web/shared/user" + "code.gitea.io/gitea/services/context" ) const ( diff --git a/routers/web/user/home.go b/routers/web/user/home.go index 8759ba32b..3ff4efc48 100644 --- a/routers/web/user/home.go +++ b/routers/web/user/home.go @@ -24,15 +24,14 @@ import ( user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/base" "code.gitea.io/gitea/modules/container" - "code.gitea.io/gitea/modules/context" issue_indexer "code.gitea.io/gitea/modules/indexer/issues" "code.gitea.io/gitea/modules/log" "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/routers/web/feed" - context_service "code.gitea.io/gitea/services/context" + "code.gitea.io/gitea/services/context" issue_service "code.gitea.io/gitea/services/issue" pull_service "code.gitea.io/gitea/services/pull" @@ -162,8 +161,8 @@ func Milestones(ctx *context.Context) { Private: true, AllPublic: false, // Include also all public repositories of users and public organisations AllLimited: false, // Include also all public repositories of limited organisations - Archived: util.OptionalBoolFalse, - HasMilestones: util.OptionalBoolTrue, // Just needs display repos has milestones + Archived: optional.Some(false), + HasMilestones: optional.Some(true), // Just needs display repos has milestones } if ctxUser.IsOrganization() && ctx.Org.Team != nil { @@ -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, @@ -466,9 +465,9 @@ func buildIssueOverview(ctx *context.Context, unitType unit.Type) { Private: true, AllPublic: false, AllLimited: false, - Collaborate: util.OptionalBoolNone, + Collaborate: optional.None[bool](), UnitType: unitType, - Archived: util.OptionalBoolFalse, + Archived: optional.Some(false), } if team != nil { repoOpts.TeamID = team.ID @@ -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") @@ -714,7 +713,7 @@ func UsernameSubRoute(ctx *context.Context) { username := ctx.Params("username") reloadParam := func(suffix string) (success bool) { ctx.SetParams("username", strings.TrimSuffix(username, suffix)) - context_service.UserAssignmentWeb()(ctx) + context.UserAssignmentWeb()(ctx) if ctx.Written() { return false } @@ -744,7 +743,7 @@ func UsernameSubRoute(ctx *context.Context) { return } if reloadParam(".rss") { - context_service.UserAssignmentWeb()(ctx) + context.UserAssignmentWeb()(ctx) feed.ShowUserFeedRSS(ctx) } case strings.HasSuffix(username, ".atom"): @@ -756,7 +755,7 @@ func UsernameSubRoute(ctx *context.Context) { feed.ShowUserFeedAtom(ctx) } default: - context_service.UserAssignmentWeb()(ctx) + context.UserAssignmentWeb()(ctx) if !ctx.Written() { ctx.Data["EnableFeed"] = setting.Other.EnableFeed OwnerProfile(ctx) @@ -803,12 +802,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/home_test.go b/routers/web/user/home_test.go index a32b015cd..1cc988630 100644 --- a/routers/web/user/home_test.go +++ b/routers/web/user/home_test.go @@ -10,8 +10,10 @@ import ( "code.gitea.io/gitea/models/db" repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/models/unittest" - "code.gitea.io/gitea/modules/contexttest" "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/templates" + "code.gitea.io/gitea/services/context" + "code.gitea.io/gitea/services/contexttest" "github.com/stretchr/testify/assert" ) @@ -113,3 +115,18 @@ func TestMilestonesForSpecificRepo(t *testing.T) { assert.Len(t, ctx.Data["Milestones"], 1) assert.Len(t, ctx.Data["Repos"], 2) // both repo 42 and 1 have milestones and both are owned by user 2 } + +func TestDashboardPagination(t *testing.T) { + ctx, _ := contexttest.MockContext(t, "/", contexttest.MockContextOption{Render: templates.HTMLRenderer()}) + page := context.NewPagination(10, 3, 1, 3) + + setting.AppSubURL = "/SubPath" + out, err := ctx.RenderToHTML("base/paginate", map[string]any{"Link": setting.AppSubURL, "Page": page}) + assert.NoError(t, err) + assert.Contains(t, out, ``) + + setting.AppSubURL = "" + out, err = ctx.RenderToHTML("base/paginate", map[string]any{"Link": setting.AppSubURL, "Page": page}) + assert.NoError(t, err) + assert.Contains(t, out, ``) +} diff --git a/routers/web/user/notification.go b/routers/web/user/notification.go index 26f77cfc3..324205ed9 100644 --- a/routers/web/user/notification.go +++ b/routers/web/user/notification.go @@ -16,11 +16,12 @@ import ( issues_model "code.gitea.io/gitea/models/issues" repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/modules/base" - "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/optional" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/util" + "code.gitea.io/gitea/services/context" issue_service "code.gitea.io/gitea/services/issue" pull_service "code.gitea.io/gitea/services/pull" ) @@ -232,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 @@ -389,6 +389,21 @@ func NotificationWatching(ctx *context.Context) { orderBy = db.SearchOrderByRecentUpdated } + archived := ctx.FormOptionalBool("archived") + ctx.Data["IsArchived"] = archived + + fork := ctx.FormOptionalBool("fork") + ctx.Data["IsFork"] = fork + + mirror := ctx.FormOptionalBool("mirror") + ctx.Data["IsMirror"] = mirror + + template := ctx.FormOptionalBool("template") + ctx.Data["IsTemplate"] = template + + private := ctx.FormOptionalBool("private") + ctx.Data["IsPrivate"] = private + repos, count, err := repo_model.SearchRepository(ctx, &repo_model.SearchRepoOptions{ ListOptions: db.ListOptions{ PageSize: setting.UI.User.RepoPagingNum, @@ -399,9 +414,14 @@ func NotificationWatching(ctx *context.Context) { OrderBy: orderBy, Private: ctx.IsSigned, WatchedByID: ctx.Doer.ID, - Collaborate: util.OptionalBoolFalse, + Collaborate: optional.Some(false), TopicOnly: ctx.FormBool("topic"), IncludeDescription: setting.UI.SearchRepoDescription, + Archived: archived, + Fork: fork, + Mirror: mirror, + Template: template, + IsPrivate: private, }) if err != nil { ctx.ServerError("SearchRepository", err) diff --git a/routers/web/user/package.go b/routers/web/user/package.go index 708af3e43..3ecc59a2a 100644 --- a/routers/web/user/package.go +++ b/routers/web/user/package.go @@ -15,8 +15,8 @@ import ( repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/modules/base" "code.gitea.io/gitea/modules/container" - "code.gitea.io/gitea/modules/context" "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" @@ -25,6 +25,7 @@ import ( "code.gitea.io/gitea/modules/web" packages_helper "code.gitea.io/gitea/routers/api/packages/helper" shared_user "code.gitea.io/gitea/routers/web/shared/user" + "code.gitea.io/gitea/services/context" "code.gitea.io/gitea/services/forms" packages_service "code.gitea.io/gitea/services/packages" ) @@ -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/profile.go b/routers/web/user/profile.go index 4eec0e990..89d22d3ef 100644 --- a/routers/web/user/profile.go +++ b/routers/web/user/profile.go @@ -16,16 +16,17 @@ import ( repo_model "code.gitea.io/gitea/models/repo" user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/base" - "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/log" "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/routers/web/feed" "code.gitea.io/gitea/routers/web/org" shared_user "code.gitea.io/gitea/routers/web/shared/user" + "code.gitea.io/gitea/services/context" user_service "code.gitea.io/gitea/services/user" ) @@ -163,6 +164,21 @@ func prepareUserProfileTabData(ctx *context.Context, showPrivate bool, profileDb } ctx.Data["NumFollowing"] = numFollowing + archived := ctx.FormOptionalBool("archived") + ctx.Data["IsArchived"] = archived + + fork := ctx.FormOptionalBool("fork") + ctx.Data["IsFork"] = fork + + mirror := ctx.FormOptionalBool("mirror") + ctx.Data["IsMirror"] = mirror + + template := ctx.FormOptionalBool("template") + ctx.Data["IsTemplate"] = template + + private := ctx.FormOptionalBool("private") + ctx.Data["IsPrivate"] = private + switch tab { case "followers": ctx.Data["Cards"] = followers @@ -205,10 +221,15 @@ func prepareUserProfileTabData(ctx *context.Context, showPrivate bool, profileDb OrderBy: orderBy, Private: ctx.IsSigned, StarredByID: ctx.ContextUser.ID, - Collaborate: util.OptionalBoolFalse, + Collaborate: optional.Some(false), TopicOnly: topicOnly, Language: language, IncludeDescription: setting.UI.SearchRepoDescription, + Archived: archived, + Fork: fork, + Mirror: mirror, + Template: template, + IsPrivate: private, }) if err != nil { ctx.ServerError("SearchRepository", err) @@ -227,10 +248,15 @@ func prepareUserProfileTabData(ctx *context.Context, showPrivate bool, profileDb OrderBy: orderBy, Private: ctx.IsSigned, WatchedByID: ctx.ContextUser.ID, - Collaborate: util.OptionalBoolFalse, + Collaborate: optional.Some(false), TopicOnly: topicOnly, Language: language, IncludeDescription: setting.UI.SearchRepoDescription, + Archived: archived, + Fork: fork, + Mirror: mirror, + Template: template, + IsPrivate: private, }) if err != nil { ctx.ServerError("SearchRepository", err) @@ -272,10 +298,15 @@ func prepareUserProfileTabData(ctx *context.Context, showPrivate bool, profileDb OwnerID: ctx.ContextUser.ID, OrderBy: orderBy, Private: ctx.IsSigned, - Collaborate: util.OptionalBoolFalse, + Collaborate: optional.Some(false), TopicOnly: topicOnly, Language: language, IncludeDescription: setting.UI.SearchRepoDescription, + Archived: archived, + Fork: fork, + Mirror: mirror, + Template: template, + IsPrivate: private, }) if err != nil { ctx.ServerError("SearchRepository", err) diff --git a/routers/web/user/search.go b/routers/web/user/search.go index 4d090a378..fb7729bbe 100644 --- a/routers/web/user/search.go +++ b/routers/web/user/search.go @@ -8,7 +8,7 @@ import ( "code.gitea.io/gitea/models/db" user_model "code.gitea.io/gitea/models/user" - "code.gitea.io/gitea/modules/context" + "code.gitea.io/gitea/services/context" "code.gitea.io/gitea/services/convert" ) diff --git a/routers/web/user/setting/account.go b/routers/web/user/setting/account.go index 6042e0b6c..ef02cd24a 100644 --- a/routers/web/user/setting/account.go +++ b/routers/web/user/setting/account.go @@ -13,13 +13,13 @@ import ( user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/auth/password" "code.gitea.io/gitea/modules/base" - "code.gitea.io/gitea/modules/context" "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/web" "code.gitea.io/gitea/services/auth" + "code.gitea.io/gitea/services/context" "code.gitea.io/gitea/services/forms" "code.gitea.io/gitea/services/mailer" "code.gitea.io/gitea/services/user" diff --git a/routers/web/user/setting/account_test.go b/routers/web/user/setting/account_test.go index 6742c382e..9fdc5e4d5 100644 --- a/routers/web/user/setting/account_test.go +++ b/routers/web/user/setting/account_test.go @@ -8,9 +8,9 @@ import ( "testing" "code.gitea.io/gitea/models/unittest" - "code.gitea.io/gitea/modules/contexttest" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/web" + "code.gitea.io/gitea/services/contexttest" "code.gitea.io/gitea/services/forms" "github.com/stretchr/testify/assert" diff --git a/routers/web/user/setting/adopt.go b/routers/web/user/setting/adopt.go index decb35c1e..171c1933d 100644 --- a/routers/web/user/setting/adopt.go +++ b/routers/web/user/setting/adopt.go @@ -8,9 +8,9 @@ import ( repo_model "code.gitea.io/gitea/models/repo" user_model "code.gitea.io/gitea/models/user" - "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/util" + "code.gitea.io/gitea/services/context" repo_service "code.gitea.io/gitea/services/repository" ) diff --git a/routers/web/user/setting/applications.go b/routers/web/user/setting/applications.go index a7e31fd50..e3822ca98 100644 --- a/routers/web/user/setting/applications.go +++ b/routers/web/user/setting/applications.go @@ -10,9 +10,9 @@ import ( auth_model "code.gitea.io/gitea/models/auth" "code.gitea.io/gitea/models/db" "code.gitea.io/gitea/modules/base" - "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/web" + "code.gitea.io/gitea/services/context" "code.gitea.io/gitea/services/forms" ) diff --git a/routers/web/user/setting/blocked_users.go b/routers/web/user/setting/blocked_users.go index ed1c340fb..3f35b2ead 100644 --- a/routers/web/user/setting/blocked_users.go +++ b/routers/web/user/setting/blocked_users.go @@ -9,8 +9,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/context" "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/services/context" ) const ( diff --git a/routers/web/user/setting/keys.go b/routers/web/user/setting/keys.go index 16410d06f..cb01913bd 100644 --- a/routers/web/user/setting/keys.go +++ b/routers/web/user/setting/keys.go @@ -5,15 +5,16 @@ package setting import ( + "fmt" "net/http" asymkey_model "code.gitea.io/gitea/models/asymkey" "code.gitea.io/gitea/models/db" "code.gitea.io/gitea/modules/base" - "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/web" asymkey_service "code.gitea.io/gitea/services/asymkey" + "code.gitea.io/gitea/services/context" "code.gitea.io/gitea/services/forms" ) @@ -77,6 +78,11 @@ func KeysPost(ctx *context.Context) { ctx.Flash.Success(ctx.Tr("settings.add_principal_success", form.Content)) ctx.Redirect(setting.AppSubURL + "/user/settings/keys") case "gpg": + if setting.Admin.UserDisabledFeatures.Contains(setting.UserFeatureManageGPGKeys) { + ctx.NotFound("Not Found", fmt.Errorf("gpg keys setting is not allowed to be visited")) + return + } + token := asymkey_model.VerificationToken(ctx.Doer, 1) lastToken := asymkey_model.VerificationToken(ctx.Doer, 0) @@ -224,6 +230,10 @@ func KeysPost(ctx *context.Context) { func DeleteKey(ctx *context.Context) { switch ctx.FormString("type") { case "gpg": + if setting.Admin.UserDisabledFeatures.Contains(setting.UserFeatureManageGPGKeys) { + ctx.NotFound("Not Found", fmt.Errorf("gpg keys setting is not allowed to be visited")) + return + } if err := asymkey_model.DeleteGPGKey(ctx, ctx.Doer, ctx.FormInt64("id")); err != nil { ctx.Flash.Error("DeleteGPGKey: " + err.Error()) } else { diff --git a/routers/web/user/setting/oauth2.go b/routers/web/user/setting/oauth2.go index 93142c21f..1f485e06c 100644 --- a/routers/web/user/setting/oauth2.go +++ b/routers/web/user/setting/oauth2.go @@ -5,8 +5,8 @@ package setting import ( "code.gitea.io/gitea/modules/base" - "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/services/context" ) const ( diff --git a/routers/web/user/setting/oauth2_common.go b/routers/web/user/setting/oauth2_common.go index fecaa4b87..85d1e820a 100644 --- a/routers/web/user/setting/oauth2_common.go +++ b/routers/web/user/setting/oauth2_common.go @@ -9,10 +9,10 @@ import ( "code.gitea.io/gitea/models/auth" "code.gitea.io/gitea/modules/base" - "code.gitea.io/gitea/modules/context" "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" "code.gitea.io/gitea/services/forms" ) diff --git a/routers/web/user/setting/packages.go b/routers/web/user/setting/packages.go index 34d18f999..413265949 100644 --- a/routers/web/user/setting/packages.go +++ b/routers/web/user/setting/packages.go @@ -9,11 +9,11 @@ import ( user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/base" - "code.gitea.io/gitea/modules/context" chef_module "code.gitea.io/gitea/modules/packages/chef" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/util" shared "code.gitea.io/gitea/routers/web/shared/packages" + "code.gitea.io/gitea/services/context" ) const ( diff --git a/routers/web/user/setting/profile.go b/routers/web/user/setting/profile.go index 24a807d51..49eb050dc 100644 --- a/routers/web/user/setting/profile.go +++ b/routers/web/user/setting/profile.go @@ -20,7 +20,6 @@ import ( repo_model "code.gitea.io/gitea/models/repo" user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/base" - "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/optional" "code.gitea.io/gitea/modules/setting" @@ -29,6 +28,7 @@ import ( "code.gitea.io/gitea/modules/util" "code.gitea.io/gitea/modules/web" "code.gitea.io/gitea/modules/web/middleware" + "code.gitea.io/gitea/services/context" "code.gitea.io/gitea/services/forms" user_service "code.gitea.io/gitea/services/user" ) diff --git a/routers/web/user/setting/runner.go b/routers/web/user/setting/runner.go index 451fd0ca9..2bb10cceb 100644 --- a/routers/web/user/setting/runner.go +++ b/routers/web/user/setting/runner.go @@ -4,8 +4,8 @@ package setting import ( - "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/services/context" ) func RedirectToDefaultSetting(ctx *context.Context) { diff --git a/routers/web/user/setting/security/2fa.go b/routers/web/user/setting/security/2fa.go index 7858b634c..cd0910236 100644 --- a/routers/web/user/setting/security/2fa.go +++ b/routers/web/user/setting/security/2fa.go @@ -13,10 +13,10 @@ import ( "strings" "code.gitea.io/gitea/models/auth" - "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/web" + "code.gitea.io/gitea/services/context" "code.gitea.io/gitea/services/forms" "github.com/pquerna/otp" diff --git a/routers/web/user/setting/security/openid.go b/routers/web/user/setting/security/openid.go index 9a207e149..8f788e173 100644 --- a/routers/web/user/setting/security/openid.go +++ b/routers/web/user/setting/security/openid.go @@ -8,10 +8,10 @@ import ( user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/auth/openid" - "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/web" + "code.gitea.io/gitea/services/context" "code.gitea.io/gitea/services/forms" ) diff --git a/routers/web/user/setting/security/security.go b/routers/web/user/setting/security/security.go index 3647d606e..8d6859ab8 100644 --- a/routers/web/user/setting/security/security.go +++ b/routers/web/user/setting/security/security.go @@ -12,10 +12,10 @@ 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/context" + "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" ) const ( @@ -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/routers/web/user/setting/security/webauthn.go b/routers/web/user/setting/security/webauthn.go index ce103528c..e382c8b9a 100644 --- a/routers/web/user/setting/security/webauthn.go +++ b/routers/web/user/setting/security/webauthn.go @@ -11,10 +11,10 @@ import ( "code.gitea.io/gitea/models/auth" wa "code.gitea.io/gitea/modules/auth/webauthn" - "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/web" + "code.gitea.io/gitea/services/context" "code.gitea.io/gitea/services/forms" "github.com/go-webauthn/webauthn/protocol" diff --git a/routers/web/user/setting/webhooks.go b/routers/web/user/setting/webhooks.go index 679b72e50..4423b6278 100644 --- a/routers/web/user/setting/webhooks.go +++ b/routers/web/user/setting/webhooks.go @@ -9,8 +9,8 @@ import ( "code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/webhook" "code.gitea.io/gitea/modules/base" - "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/services/context" ) const ( diff --git a/routers/web/user/stop_watch.go b/routers/web/user/stop_watch.go index 86f66e64a..38f74ea45 100644 --- a/routers/web/user/stop_watch.go +++ b/routers/web/user/stop_watch.go @@ -8,7 +8,7 @@ import ( "code.gitea.io/gitea/models/db" issues_model "code.gitea.io/gitea/models/issues" - "code.gitea.io/gitea/modules/context" + "code.gitea.io/gitea/services/context" "code.gitea.io/gitea/services/convert" ) diff --git a/routers/web/user/task.go b/routers/web/user/task.go index bec68c5f2..8476767e9 100644 --- a/routers/web/user/task.go +++ b/routers/web/user/task.go @@ -8,8 +8,8 @@ import ( "strconv" admin_model "code.gitea.io/gitea/models/admin" - "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/json" + "code.gitea.io/gitea/services/context" ) // TaskStatus returns task's status diff --git a/routers/web/web.go b/routers/web/web.go index fc09ed2b6..114a50cf0 100644 --- a/routers/web/web.go +++ b/routers/web/web.go @@ -12,7 +12,6 @@ import ( "code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/perm" "code.gitea.io/gitea/models/unit" - "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/metrics" "code.gitea.io/gitea/modules/public" @@ -44,7 +43,7 @@ import ( user_setting "code.gitea.io/gitea/routers/web/user/setting" "code.gitea.io/gitea/routers/web/user/setting/security" auth_service "code.gitea.io/gitea/services/auth" - context_service "code.gitea.io/gitea/services/context" + "code.gitea.io/gitea/services/context" "code.gitea.io/gitea/services/forms" "code.gitea.io/gitea/services/lfs" @@ -795,7 +794,7 @@ func registerRoutes(m *web.Route) { m.Methods("GET, OPTIONS", "/attachments/{uuid}", optionsCorsHandler(), repo.GetAttachment) }, ignSignIn) - m.Post("/{username}", reqSignIn, context_service.UserAssignmentWeb(), user.Action) + m.Post("/{username}", reqSignIn, context.UserAssignmentWeb(), user.Action) reqRepoAdmin := context.RequireRepoAdmin() reqRepoCodeWriter := context.RequireRepoWriter(unit.TypeCode) @@ -1029,7 +1028,7 @@ func registerRoutes(m *web.Route) { m.Group("", func() { m.Get("/code", user.CodeSearch) }, reqUnitAccess(unit.TypeCode, perm.AccessModeRead, false), individualPermsChecker) - }, ignSignIn, context_service.UserAssignmentWeb(), context.OrgAssignment()) // for "/{username}/-" (packages, projects, code) + }, ignSignIn, context.UserAssignmentWeb(), context.OrgAssignment()) // for "/{username}/-" (packages, projects, code) m.Group("/{username}/{reponame}", func() { m.Group("/settings", func() { diff --git a/routers/web/webfinger.go b/routers/web/webfinger.go index faa35b8d2..a87c426b3 100644 --- a/routers/web/webfinger.go +++ b/routers/web/webfinger.go @@ -10,9 +10,9 @@ import ( "strings" user_model "code.gitea.io/gitea/models/user" - "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/services/context" ) // https://datatracker.ietf.org/doc/html/draft-ietf-appsawg-webfinger-14#section-4.4 diff --git a/services/actions/job_emitter.go b/services/actions/job_emitter.go index fe3931238..d2bbbd9a7 100644 --- a/services/actions/job_emitter.go +++ b/services/actions/job_emitter.go @@ -7,12 +7,14 @@ import ( "context" "errors" "fmt" + "strings" actions_model "code.gitea.io/gitea/models/actions" "code.gitea.io/gitea/models/db" "code.gitea.io/gitea/modules/graceful" "code.gitea.io/gitea/modules/queue" + "github.com/nektos/act/pkg/jobparser" "xorm.io/builder" ) @@ -76,12 +78,15 @@ func checkJobsOfRun(ctx context.Context, runID int64) error { type jobStatusResolver struct { statuses map[int64]actions_model.Status needs map[int64][]int64 + jobMap map[int64]*actions_model.ActionRunJob } func newJobStatusResolver(jobs actions_model.ActionJobList) *jobStatusResolver { idToJobs := make(map[string][]*actions_model.ActionRunJob, len(jobs)) + jobMap := make(map[int64]*actions_model.ActionRunJob) for _, job := range jobs { idToJobs[job.JobID] = append(idToJobs[job.JobID], job) + jobMap[job.ID] = job } statuses := make(map[int64]actions_model.Status, len(jobs)) @@ -97,6 +102,7 @@ func newJobStatusResolver(jobs actions_model.ActionJobList) *jobStatusResolver { return &jobStatusResolver{ statuses: statuses, needs: needs, + jobMap: jobMap, } } @@ -135,7 +141,20 @@ func (r *jobStatusResolver) resolve() map[int64]actions_model.Status { if allSucceed { ret[id] = actions_model.StatusWaiting } else { - ret[id] = actions_model.StatusSkipped + // If a job's "if" condition is "always()", the job should always run even if some of its dependencies did not succeed. + // See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idneeds + always := false + if wfJobs, _ := jobparser.Parse(r.jobMap[id].WorkflowPayload); len(wfJobs) == 1 { + _, wfJob := wfJobs[0].Job() + expr := strings.TrimSpace(strings.TrimSuffix(strings.TrimPrefix(wfJob.If.Value, "${{"), "}}")) + always = expr == "always()" + } + + if always { + ret[id] = actions_model.StatusWaiting + } else { + ret[id] = actions_model.StatusSkipped + } } } } diff --git a/services/actions/job_emitter_test.go b/services/actions/job_emitter_test.go index e81aa61d8..038df7d4f 100644 --- a/services/actions/job_emitter_test.go +++ b/services/actions/job_emitter_test.go @@ -70,6 +70,62 @@ func Test_jobStatusResolver_Resolve(t *testing.T) { }, want: map[int64]actions_model.Status{}, }, + { + name: "with ${{ always() }} condition", + jobs: actions_model.ActionJobList{ + {ID: 1, JobID: "job1", Status: actions_model.StatusFailure, Needs: []string{}}, + {ID: 2, JobID: "job2", Status: actions_model.StatusBlocked, Needs: []string{"job1"}, WorkflowPayload: []byte( + ` +name: test +on: push +jobs: + job2: + runs-on: ubuntu-latest + needs: job1 + if: ${{ always() }} + steps: + - run: echo "always run" +`)}, + }, + want: map[int64]actions_model.Status{2: actions_model.StatusWaiting}, + }, + { + name: "with always() condition", + jobs: actions_model.ActionJobList{ + {ID: 1, JobID: "job1", Status: actions_model.StatusFailure, Needs: []string{}}, + {ID: 2, JobID: "job2", Status: actions_model.StatusBlocked, Needs: []string{"job1"}, WorkflowPayload: []byte( + ` +name: test +on: push +jobs: + job2: + runs-on: ubuntu-latest + needs: job1 + if: always() + steps: + - run: echo "always run" +`)}, + }, + want: map[int64]actions_model.Status{2: actions_model.StatusWaiting}, + }, + { + name: "without always() condition", + jobs: actions_model.ActionJobList{ + {ID: 1, JobID: "job1", Status: actions_model.StatusFailure, Needs: []string{}}, + {ID: 2, JobID: "job2", Status: actions_model.StatusBlocked, Needs: []string{"job1"}, WorkflowPayload: []byte( + ` +name: test +on: push +jobs: + job2: + runs-on: ubuntu-latest + needs: job1 + steps: + - run: echo "not always run" +`)}, + }, + want: map[int64]actions_model.Status{2: actions_model.StatusSkipped}, + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { diff --git a/services/actions/notifier.go b/services/actions/notifier.go index e144484da..aa88d4e0d 100644 --- a/services/actions/notifier.go +++ b/services/actions/notifier.go @@ -152,7 +152,13 @@ func (n *actionsNotifier) IssueChangeAssignee(ctx context.Context, doer *user_mo } else { action = api.HookIssueAssigned } - notifyIssueChange(ctx, doer, issue, webhook_module.HookEventPullRequestAssign, action) + + hookEvent := webhook_module.HookEventIssueAssign + if issue.IsPull { + hookEvent = webhook_module.HookEventPullRequestAssign + } + + notifyIssueChange(ctx, doer, issue, hookEvent, action) } // IssueChangeMilestone notifies assignee to notifiers @@ -165,14 +171,26 @@ func (n *actionsNotifier) IssueChangeMilestone(ctx context.Context, doer *user_m } else { action = api.HookIssueDemilestoned } - notifyIssueChange(ctx, doer, issue, webhook_module.HookEventPullRequestMilestone, action) + + hookEvent := webhook_module.HookEventIssueMilestone + if issue.IsPull { + hookEvent = webhook_module.HookEventPullRequestMilestone + } + + notifyIssueChange(ctx, doer, issue, hookEvent, action) } func (n *actionsNotifier) IssueChangeLabels(ctx context.Context, doer *user_model.User, issue *issues_model.Issue, _, _ []*issues_model.Label, ) { ctx = withMethod(ctx, "IssueChangeLabels") - notifyIssueChange(ctx, doer, issue, webhook_module.HookEventPullRequestLabel, api.HookIssueLabelUpdated) + + hookEvent := webhook_module.HookEventIssueLabel + if issue.IsPull { + hookEvent = webhook_module.HookEventPullRequestLabel + } + + notifyIssueChange(ctx, doer, issue, hookEvent, api.HookIssueLabelUpdated) } func notifyIssueChange(ctx context.Context, doer *user_model.User, issue *issues_model.Issue, event webhook_module.HookEventType, action api.HookIssueAction) { diff --git a/services/actions/notifier_helper.go b/services/actions/notifier_helper.go index 2d138aaf3..19a5c66b7 100644 --- a/services/actions/notifier_helper.go +++ b/services/actions/notifier_helper.go @@ -117,6 +117,9 @@ func notify(ctx context.Context, input *notifyInput) error { log.Debug("ignore executing %v for event %v whose doer is %v", getMethod(ctx), input.Event, input.Doer.Name) return nil } + if input.Repo.IsEmpty { + return nil + } if unit_model.TypeActions.UnitGlobalDisabled() { return nil } diff --git a/services/attachment/attachment.go b/services/attachment/attachment.go index 1bcd460e3..4481966b4 100644 --- a/services/attachment/attachment.go +++ b/services/attachment/attachment.go @@ -12,8 +12,8 @@ import ( "code.gitea.io/gitea/models/db" repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/modules/storage" - "code.gitea.io/gitea/modules/upload" "code.gitea.io/gitea/modules/util" + "code.gitea.io/gitea/services/context/upload" "github.com/google/uuid" ) @@ -44,14 +44,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/auth.go b/services/auth/auth.go index e53ff02dc..c10872313 100644 --- a/services/auth/auth.go +++ b/services/auth/auth.go @@ -12,12 +12,12 @@ import ( user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/auth/webauthn" - gitea_context "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/optional" "code.gitea.io/gitea/modules/session" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/web/middleware" + gitea_context "code.gitea.io/gitea/services/context" user_service "code.gitea.io/gitea/services/user" ) diff --git a/services/auth/signin.go b/services/auth/signin.go index fafe3ef3c..e116a088e 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 3ad6e307f..5c2568154 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 f4edb507f..ac3264783 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 8c0fc77a9..64a127e97 100644 --- a/services/auth/sspi.go +++ b/services/auth/sspi.go @@ -14,13 +14,12 @@ import ( "code.gitea.io/gitea/models/db" user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/base" - gitea_context "code.gitea.io/gitea/modules/context" "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" gouuid "github.com/google/uuid" ) @@ -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/modules/context/access_log.go b/services/context/access_log.go similarity index 100% rename from modules/context/access_log.go rename to services/context/access_log.go diff --git a/modules/context/api.go b/services/context/api.go similarity index 100% rename from modules/context/api.go rename to services/context/api.go diff --git a/modules/context/api_org.go b/services/context/api_org.go similarity index 100% rename from modules/context/api_org.go rename to services/context/api_org.go diff --git a/modules/context/api_test.go b/services/context/api_test.go similarity index 100% rename from modules/context/api_test.go rename to services/context/api_test.go diff --git a/modules/context/base.go b/services/context/base.go similarity index 92% rename from modules/context/base.go rename to services/context/base.go index fa05850a1..c4aa467ff 100644 --- a/modules/context/base.go +++ b/services/context/base.go @@ -17,8 +17,8 @@ import ( "code.gitea.io/gitea/modules/httplib" "code.gitea.io/gitea/modules/json" "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/optional" "code.gitea.io/gitea/modules/translation" - "code.gitea.io/gitea/modules/util" "code.gitea.io/gitea/modules/web/middleware" "github.com/go-chi/chi/v5" @@ -207,17 +207,17 @@ func (b *Base) FormBool(key string) bool { return v } -// FormOptionalBool returns an OptionalBoolTrue or OptionalBoolFalse if the value -// for the provided key exists in the form else it returns OptionalBoolNone -func (b *Base) FormOptionalBool(key string) util.OptionalBool { +// FormOptionalBool returns an optional.Some(true) or optional.Some(false) if the value +// for the provided key exists in the form else it returns optional.None[bool]() +func (b *Base) FormOptionalBool(key string) optional.Option[bool] { value := b.Req.FormValue(key) if len(value) == 0 { - return util.OptionalBoolNone + return optional.None[bool]() } s := b.Req.FormValue(key) v, _ := strconv.ParseBool(s) v = v || strings.EqualFold(s, "on") - return util.OptionalBoolOf(v) + return optional.Some(v) } func (b *Base) SetFormString(key, value string) { @@ -265,6 +265,14 @@ func (b *Base) Redirect(location string, status ...int) { // So in this case, we should remove the session cookie from the response header removeSessionCookieHeader(b.Resp) } + // in case the request is made by htmx, have it redirect the browser instead of trying to follow the redirect inside htmx + if b.Req.Header.Get("HX-Request") == "true" { + b.Resp.Header().Set("HX-Redirect", location) + // we have to return a non-redirect status code so XMLHTTPRequest will not immediately follow the redirect + // so as to give htmx redirect logic a chance to run + b.Status(http.StatusNoContent) + return + } http.Redirect(b.Resp, b.Req, location, code) } diff --git a/modules/context/captcha.go b/services/context/captcha.go similarity index 100% rename from modules/context/captcha.go rename to services/context/captcha.go diff --git a/modules/context/context.go b/services/context/context.go similarity index 100% rename from modules/context/context.go rename to services/context/context.go diff --git a/modules/context/context_cookie.go b/services/context/context_cookie.go similarity index 100% rename from modules/context/context_cookie.go rename to services/context/context_cookie.go diff --git a/modules/context/context_model.go b/services/context/context_model.go similarity index 100% rename from modules/context/context_model.go rename to services/context/context_model.go diff --git a/modules/context/context_request.go b/services/context/context_request.go similarity index 100% rename from modules/context/context_request.go rename to services/context/context_request.go diff --git a/modules/context/context_response.go b/services/context/context_response.go similarity index 94% rename from modules/context/context_response.go rename to services/context/context_response.go index 829bca1f5..372b4cb38 100644 --- a/modules/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/modules/context/context_template.go b/services/context/context_template.go similarity index 100% rename from modules/context/context_template.go rename to services/context/context_template.go diff --git a/modules/context/context_test.go b/services/context/context_test.go similarity index 100% rename from modules/context/context_test.go rename to services/context/context_test.go diff --git a/modules/context/csrf.go b/services/context/csrf.go similarity index 100% rename from modules/context/csrf.go rename to services/context/csrf.go diff --git a/modules/context/org.go b/services/context/org.go similarity index 100% rename from modules/context/org.go rename to services/context/org.go diff --git a/modules/context/package.go b/services/context/package.go similarity index 100% rename from modules/context/package.go rename to services/context/package.go diff --git a/modules/context/pagination.go b/services/context/pagination.go similarity index 100% rename from modules/context/pagination.go rename to services/context/pagination.go diff --git a/modules/context/permission.go b/services/context/permission.go similarity index 100% rename from modules/context/permission.go rename to services/context/permission.go diff --git a/modules/context/private.go b/services/context/private.go similarity index 100% rename from modules/context/private.go rename to services/context/private.go diff --git a/modules/context/repo.go b/services/context/repo.go similarity index 99% rename from modules/context/repo.go rename to services/context/repo.go index e8ed1134f..e78dfc585 100644 --- a/modules/context/repo.go +++ b/services/context/repo.go @@ -547,7 +547,7 @@ func RepoAssignment(ctx *Context) context.CancelFunc { ctx.Data["NumTags"], err = db.Count[repo_model.Release](ctx, repo_model.FindReleasesOptions{ IncludeDrafts: true, IncludeTags: true, - HasSha1: util.OptionalBoolTrue, // only draft releases which are created with existing tags + HasSha1: optional.Some(true), // only draft releases which are created with existing tags RepoID: ctx.Repo.Repository.ID, }) if err != nil { diff --git a/modules/context/response.go b/services/context/response.go similarity index 100% rename from modules/context/response.go rename to services/context/response.go diff --git a/modules/upload/upload.go b/services/context/upload/upload.go similarity index 98% rename from modules/upload/upload.go rename to services/context/upload/upload.go index cd1071586..77a7eb937 100644 --- a/modules/upload/upload.go +++ b/services/context/upload/upload.go @@ -11,9 +11,9 @@ import ( "regexp" "strings" - "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/services/context" ) // ErrFileTypeForbidden not allowed file type error diff --git a/modules/upload/upload_test.go b/services/context/upload/upload_test.go similarity index 100% rename from modules/upload/upload_test.go rename to services/context/upload/upload_test.go diff --git a/services/context/user.go b/services/context/user.go index 8b2faf336..4c9cd2928 100644 --- a/services/context/user.go +++ b/services/context/user.go @@ -9,12 +9,11 @@ import ( "strings" user_model "code.gitea.io/gitea/models/user" - "code.gitea.io/gitea/modules/context" ) // UserAssignmentWeb returns a middleware to handle context-user assignment for web routes -func UserAssignmentWeb() func(ctx *context.Context) { - return func(ctx *context.Context) { +func UserAssignmentWeb() func(ctx *Context) { + return func(ctx *Context) { errorFn := func(status int, title string, obj any) { err, ok := obj.(error) if !ok { @@ -32,8 +31,8 @@ func UserAssignmentWeb() func(ctx *context.Context) { } // UserIDAssignmentAPI returns a middleware to handle context-user assignment for api routes -func UserIDAssignmentAPI() func(ctx *context.APIContext) { - return func(ctx *context.APIContext) { +func UserIDAssignmentAPI() func(ctx *APIContext) { + return func(ctx *APIContext) { userID := ctx.ParamsInt64(":user-id") if ctx.IsSigned && ctx.Doer.ID == userID { @@ -53,13 +52,13 @@ func UserIDAssignmentAPI() func(ctx *context.APIContext) { } // UserAssignmentAPI returns a middleware to handle context-user assignment for api routes -func UserAssignmentAPI() func(ctx *context.APIContext) { - return func(ctx *context.APIContext) { +func UserAssignmentAPI() func(ctx *APIContext) { + return func(ctx *APIContext) { ctx.ContextUser = userAssignment(ctx.Base, ctx.Doer, ctx.Error) } } -func userAssignment(ctx *context.Base, doer *user_model.User, errCb func(int, string, any)) (contextUser *user_model.User) { +func userAssignment(ctx *Base, doer *user_model.User, errCb func(int, string, any)) (contextUser *user_model.User) { username := ctx.Params(":username") if doer != nil && doer.LowerName == strings.ToLower(username) { @@ -70,7 +69,7 @@ func userAssignment(ctx *context.Base, doer *user_model.User, errCb func(int, st if err != nil { if user_model.IsErrUserNotExist(err) { if redirectUserID, err := user_model.LookupUserRedirect(ctx, username); err == nil { - context.RedirectToUser(ctx, username, redirectUserID) + RedirectToUser(ctx, username, redirectUserID) } else if user_model.IsErrUserRedirectNotExist(err) { errCb(http.StatusNotFound, "GetUserByName", err) } else { diff --git a/modules/context/utils.go b/services/context/utils.go similarity index 100% rename from modules/context/utils.go rename to services/context/utils.go diff --git a/modules/context/xsrf.go b/services/context/xsrf.go similarity index 100% rename from modules/context/xsrf.go rename to services/context/xsrf.go diff --git a/modules/context/xsrf_test.go b/services/context/xsrf_test.go similarity index 100% rename from modules/context/xsrf_test.go rename to services/context/xsrf_test.go diff --git a/modules/contexttest/context_tests.go b/services/contexttest/context_tests.go similarity index 90% rename from modules/contexttest/context_tests.go rename to services/contexttest/context_tests.go index 9ca028bb6..431017a30 100644 --- a/modules/contexttest/context_tests.go +++ b/services/contexttest/context_tests.go @@ -12,16 +12,17 @@ import ( "net/url" "strings" "testing" + "time" access_model "code.gitea.io/gitea/models/perm/access" repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/models/unittest" user_model "code.gitea.io/gitea/models/user" - "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/gitrepo" "code.gitea.io/gitea/modules/templates" "code.gitea.io/gitea/modules/translation" "code.gitea.io/gitea/modules/web/middleware" + "code.gitea.io/gitea/services/context" "github.com/go-chi/chi/v5" "github.com/stretchr/testify/assert" @@ -40,8 +41,19 @@ func mockRequest(t *testing.T, reqPath string) *http.Request { return req } +type MockContextOption struct { + Render context.Render +} + // MockContext mock context for unit tests -func MockContext(t *testing.T, reqPath string) (*context.Context, *httptest.ResponseRecorder) { +func MockContext(t *testing.T, reqPath string, opts ...MockContextOption) (*context.Context, *httptest.ResponseRecorder) { + var opt MockContextOption + if len(opts) > 0 { + opt = opts[0] + } + if opt.Render == nil { + opt.Render = &MockRender{} + } resp := httptest.NewRecorder() req := mockRequest(t, reqPath) base, baseCleanUp := context.NewBaseContext(resp, req) @@ -49,8 +61,9 @@ func MockContext(t *testing.T, reqPath string) (*context.Context, *httptest.Resp base.Data = middleware.GetContextData(req.Context()) base.Locale = &translation.MockLocale{} - ctx := context.NewWebContext(base, &MockRender{}, nil) - + ctx := context.NewWebContext(base, opt.Render, nil) + ctx.PageData = map[string]any{} + ctx.Data["PageStartTime"] = time.Now() chiCtx := chi.NewRouteContext() ctx.Base.AppendContextValue(chi.RouteCtxKey, chiCtx) return ctx, resp diff --git a/services/convert/git_commit.go b/services/convert/git_commit.go index ed08691c8..e0efcddbc 100644 --- a/services/convert/git_commit.go +++ b/services/convert/git_commit.go @@ -10,11 +10,11 @@ import ( repo_model "code.gitea.io/gitea/models/repo" user_model "code.gitea.io/gitea/models/user" - ctx "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/log" api "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/util" + ctx "code.gitea.io/gitea/services/context" "code.gitea.io/gitea/services/gitdiff" ) diff --git a/services/convert/package.go b/services/convert/package.go index e90ce8a00..b5fca21a3 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 4b3cacc60..81276f8f4 100644 --- a/services/forms/admin.go +++ b/services/forms/admin.go @@ -6,9 +6,9 @@ package forms import ( "net/http" - "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/web/middleware" + "code.gitea.io/gitea/services/context" "gitea.com/go-chi/binding" ) @@ -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/forms/auth_form.go b/services/forms/auth_form.go index 25acbbb99..c9f3182b3 100644 --- a/services/forms/auth_form.go +++ b/services/forms/auth_form.go @@ -6,8 +6,8 @@ package forms import ( "net/http" - "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/web/middleware" + "code.gitea.io/gitea/services/context" "gitea.com/go-chi/binding" ) diff --git a/services/forms/org.go b/services/forms/org.go index 6e2d78751..3677fcf42 100644 --- a/services/forms/org.go +++ b/services/forms/org.go @@ -7,9 +7,9 @@ package forms import ( "net/http" - "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/web/middleware" + "code.gitea.io/gitea/services/context" "gitea.com/go-chi/binding" ) diff --git a/services/forms/package_form.go b/services/forms/package_form.go index 2f08dfe9f..cc940d42d 100644 --- a/services/forms/package_form.go +++ b/services/forms/package_form.go @@ -6,8 +6,8 @@ package forms import ( "net/http" - "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/web/middleware" + "code.gitea.io/gitea/services/context" "gitea.com/go-chi/binding" ) diff --git a/services/forms/repo_branch_form.go b/services/forms/repo_branch_form.go index 5deb0ae46..42e6c85c3 100644 --- a/services/forms/repo_branch_form.go +++ b/services/forms/repo_branch_form.go @@ -6,8 +6,8 @@ package forms import ( "net/http" - "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/web/middleware" + "code.gitea.io/gitea/services/context" "gitea.com/go-chi/binding" ) diff --git a/services/forms/repo_form.go b/services/forms/repo_form.go index da54f4de6..f9ebb6eba 100644 --- a/services/forms/repo_form.go +++ b/services/forms/repo_form.go @@ -12,10 +12,10 @@ import ( "code.gitea.io/gitea/models" issues_model "code.gitea.io/gitea/models/issues" project_model "code.gitea.io/gitea/models/project" - "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/web/middleware" + "code.gitea.io/gitea/services/context" "code.gitea.io/gitea/services/webhook" "gitea.com/go-chi/binding" diff --git a/services/forms/repo_tag_form.go b/services/forms/repo_tag_form.go index 4dd99f9e3..013568473 100644 --- a/services/forms/repo_tag_form.go +++ b/services/forms/repo_tag_form.go @@ -6,8 +6,8 @@ package forms import ( "net/http" - "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/web/middleware" + "code.gitea.io/gitea/services/context" "gitea.com/go-chi/binding" ) diff --git a/services/forms/runner.go b/services/forms/runner.go index 6d16cfce4..6abfc66fc 100644 --- a/services/forms/runner.go +++ b/services/forms/runner.go @@ -6,8 +6,8 @@ package forms import ( "net/http" - "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/web/middleware" + "code.gitea.io/gitea/services/context" "gitea.com/go-chi/binding" ) diff --git a/services/forms/user_form.go b/services/forms/user_form.go index fd4649025..77316fb13 100644 --- a/services/forms/user_form.go +++ b/services/forms/user_form.go @@ -10,11 +10,11 @@ import ( "strings" auth_model "code.gitea.io/gitea/models/auth" - "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/validation" "code.gitea.io/gitea/modules/web/middleware" + "code.gitea.io/gitea/services/context" "gitea.com/go-chi/binding" ) diff --git a/services/forms/user_form_auth_openid.go b/services/forms/user_form_auth_openid.go index d8137a8d1..ca1c77e32 100644 --- a/services/forms/user_form_auth_openid.go +++ b/services/forms/user_form_auth_openid.go @@ -6,8 +6,8 @@ package forms import ( "net/http" - "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/web/middleware" + "code.gitea.io/gitea/services/context" "gitea.com/go-chi/binding" ) diff --git a/services/forms/user_form_hidden_comments.go b/services/forms/user_form_hidden_comments.go index 03e629a55..c21fddf47 100644 --- a/services/forms/user_form_hidden_comments.go +++ b/services/forms/user_form_hidden_comments.go @@ -7,8 +7,8 @@ import ( "math/big" issues_model "code.gitea.io/gitea/models/issues" - "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/services/context" ) type hiddenCommentTypeGroupsType map[string][]issues_model.CommentType diff --git a/services/gitdiff/gitdiff.go b/services/gitdiff/gitdiff.go index 715c5bf9b..2b796181d 100644 --- a/services/gitdiff/gitdiff.go +++ b/services/gitdiff/gitdiff.go @@ -152,7 +152,7 @@ func (d *DiffLine) GetBlobExcerptQuery() string { // GetExpandDirection gets DiffLineExpandDirection func (d *DiffLine) GetExpandDirection() DiffLineExpandDirection { - if d.Type != DiffLineSection || d.SectionInfo == nil || d.SectionInfo.RightIdx-d.SectionInfo.LastRightIdx <= 1 { + if d.Type != DiffLineSection || d.SectionInfo == nil || d.SectionInfo.LeftIdx-d.SectionInfo.LastLeftIdx <= 1 || d.SectionInfo.RightIdx-d.SectionInfo.LastRightIdx <= 1 { return DiffLineExpandNone } if d.SectionInfo.LastLeftIdx <= 0 && d.SectionInfo.LastRightIdx <= 0 { diff --git a/services/lfs/locks.go b/services/lfs/locks.go index 08d743265..2a362b1c0 100644 --- a/services/lfs/locks.go +++ b/services/lfs/locks.go @@ -11,12 +11,12 @@ import ( auth_model "code.gitea.io/gitea/models/auth" git_model "code.gitea.io/gitea/models/git" repo_model "code.gitea.io/gitea/models/repo" - "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/json" lfs_module "code.gitea.io/gitea/modules/lfs" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/setting" api "code.gitea.io/gitea/modules/structs" + "code.gitea.io/gitea/services/context" "code.gitea.io/gitea/services/convert" ) diff --git a/services/lfs/server.go b/services/lfs/server.go index 56714120a..706be0d08 100644 --- a/services/lfs/server.go +++ b/services/lfs/server.go @@ -26,12 +26,12 @@ 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/context" "code.gitea.io/gitea/modules/json" lfs_module "code.gitea.io/gitea/modules/lfs" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/storage" + "code.gitea.io/gitea/services/context" "github.com/golang-jwt/jwt/v5" ) diff --git a/services/mailer/incoming/incoming_handler.go b/services/mailer/incoming/incoming_handler.go index 5ce2cd5fd..dc0b53982 100644 --- a/services/mailer/incoming/incoming_handler.go +++ b/services/mailer/incoming/incoming_handler.go @@ -14,9 +14,9 @@ import ( user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/setting" - "code.gitea.io/gitea/modules/upload" "code.gitea.io/gitea/modules/util" attachment_service "code.gitea.io/gitea/services/attachment" + "code.gitea.io/gitea/services/context/upload" issue_service "code.gitea.io/gitea/services/issue" incoming_payload "code.gitea.io/gitea/services/mailer/incoming/payload" "code.gitea.io/gitea/services/mailer/token" diff --git a/services/mailer/mail_admin_new_user.go b/services/mailer/mail_admin_new_user.go index ecf0ddf5f..aa0571e57 100644 --- a/services/mailer/mail_admin_new_user.go +++ b/services/mailer/mail_admin_new_user.go @@ -55,13 +55,13 @@ func mailNewUser(ctx context.Context, u *user_model.User, lang string, tos []str subject := locale.TrString("mail.admin.new_user.subject", u.Name) body := locale.TrString("mail.admin.new_user.text", manageUserURL) mailMeta := map[string]any{ - "NewUser": u, - "NewUserUrl": u.HTMLURL(), - "Subject": subject, - "Body": body, - "Language": locale.Language(), - "Locale": locale, - "Str2html": templates.Str2html, + "NewUser": u, + "NewUserUrl": u.HTMLURL(), + "Subject": subject, + "Body": body, + "Language": locale.Language(), + "Locale": locale, + "SanitizeHTML": templates.SanitizeHTML, } var mailBody bytes.Buffer diff --git a/services/markup/processorhelper.go b/services/markup/processorhelper.go index 3551f85c4..a4378678a 100644 --- a/services/markup/processorhelper.go +++ b/services/markup/processorhelper.go @@ -7,8 +7,8 @@ import ( "context" "code.gitea.io/gitea/models/user" - gitea_context "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/markup" + gitea_context "code.gitea.io/gitea/services/context" ) func ProcessorHelper() *markup.ProcessorHelper { diff --git a/services/markup/processorhelper_test.go b/services/markup/processorhelper_test.go index ef8f56224..170edae0e 100644 --- a/services/markup/processorhelper_test.go +++ b/services/markup/processorhelper_test.go @@ -12,8 +12,8 @@ import ( "code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/unittest" "code.gitea.io/gitea/models/user" - gitea_context "code.gitea.io/gitea/modules/context" - "code.gitea.io/gitea/modules/contexttest" + gitea_context "code.gitea.io/gitea/services/context" + "code.gitea.io/gitea/services/contexttest" "github.com/stretchr/testify/assert" ) diff --git a/services/migrations/gitea_uploader.go b/services/migrations/gitea_uploader.go index 717be7b7f..9baae6d31 100644 --- a/services/migrations/gitea_uploader.go +++ b/services/migrations/gitea_uploader.go @@ -483,6 +483,10 @@ func (g *GiteaLocalUploader) CreateComments(comments ...*base.Comment) error { } switch cm.Type { + case issues_model.CommentTypeReopen: + cm.Content = "" + case issues_model.CommentTypeClose: + cm.Content = "" case issues_model.CommentTypeAssignees: if assigneeID, ok := comment.Meta["AssigneeID"].(int); ok { cm.AssigneeID = int64(assigneeID) @@ -503,6 +507,8 @@ func (g *GiteaLocalUploader) CreateComments(comments ...*base.Comment) error { cm.NewRef = fmt.Sprint(comment.Meta["NewRef"]) cm.Content = "" } + case issues_model.CommentTypeMergePull: + cm.Content = "" case issues_model.CommentTypePRScheduledToAutoMerge, issues_model.CommentTypePRUnScheduledToAutoMerge: cm.Content = "" default: diff --git a/services/migrations/gitea_uploader_test.go b/services/migrations/gitea_uploader_test.go index 33b7c6808..e98582f31 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/migrations/gitlab.go b/services/migrations/gitlab.go index 5e49ae6d5..bbc44e958 100644 --- a/services/migrations/gitlab.go +++ b/services/migrations/gitlab.go @@ -517,6 +517,60 @@ func (g *GitlabDownloader) GetComments(commentable base.Commentable) ([]*base.Co } page = resp.NextPage } + + page = 1 + for { + var stateEvents []*gitlab.StateEvent + var resp *gitlab.Response + var err error + if context.IsMergeRequest { + stateEvents, resp, err = g.client.ResourceStateEvents.ListMergeStateEvents(g.repoID, int(commentable.GetForeignIndex()), &gitlab.ListStateEventsOptions{ + ListOptions: gitlab.ListOptions{ + Page: page, + PerPage: g.maxPerPage, + }, + }, nil, gitlab.WithContext(g.ctx)) + } else { + stateEvents, resp, err = g.client.ResourceStateEvents.ListIssueStateEvents(g.repoID, int(commentable.GetForeignIndex()), &gitlab.ListStateEventsOptions{ + ListOptions: gitlab.ListOptions{ + Page: page, + PerPage: g.maxPerPage, + }, + }, nil, gitlab.WithContext(g.ctx)) + } + if err != nil { + return nil, false, fmt.Errorf("error while listing state events: %v %w", g.repoID, err) + } + + for _, stateEvent := range stateEvents { + comment := &base.Comment{ + IssueIndex: commentable.GetLocalIndex(), + Index: int64(stateEvent.ID), + PosterID: int64(stateEvent.User.ID), + PosterName: stateEvent.User.Username, + Content: "", + Created: *stateEvent.CreatedAt, + } + switch stateEvent.State { + case gitlab.ClosedEventType: + comment.CommentType = issues_model.CommentTypeClose.String() + case gitlab.MergedEventType: + comment.CommentType = issues_model.CommentTypeMergePull.String() + case gitlab.ReopenedEventType: + comment.CommentType = issues_model.CommentTypeReopen.String() + default: + // Ignore other event types + continue + } + allComments = append(allComments, comment) + } + + if resp.NextPage == 0 { + break + } + page = resp.NextPage + } + return allComments, true, nil } diff --git a/services/migrations/testdata/gitlab/full_download/_api_v4_projects_15578026 b/services/migrations/testdata/gitlab/full_download/_api_v4_projects_15578026 index 4ecfe77e6..e102c2ee1 100644 --- a/services/migrations/testdata/gitlab/full_download/_api_v4_projects_15578026 +++ b/services/migrations/testdata/gitlab/full_download/_api_v4_projects_15578026 @@ -1,22 +1,17 @@ X-Frame-Options: SAMEORIGIN -Ratelimit-Resettime: Thu, 30 Nov 2023 08:45:46 GMT -Cf-Cache-Status: MISS -Set-Cookie: _cfuvid=TkY5Br2q4C67LJ2jZWlgdQaosj3Z4aI81Qb27PNKXfo-1701333886606-0-604800000; path=/; domain=.gitlab.com; HttpOnly; Secure; SameSite=None -Etag: W/"3cacfe29f44a69e84a577337eac55d89" -X-Content-Type-Options: nosniff -Ratelimit-Remaining: 1996 -Gitlab-Lb: haproxy-main-29-lb-gprd -Cache-Control: max-age=0, private, must-revalidate -Referrer-Policy: strict-origin-when-cross-origin -X-Gitlab-Meta: {"correlation_id":"291f87cd975a51a7b756806ce7b53e2e","version":"1"} -Ratelimit-Observed: 4 Vary: Origin, Accept-Encoding -Gitlab-Sv: localhost -Content-Security-Policy: default-src 'none' -Ratelimit-Reset: 1701333946 -Content-Type: application/json -X-Runtime: 0.101081 Strict-Transport-Security: max-age=31536000 -Ratelimit-Limit: 2000 +Cache-Control: max-age=0, private, must-revalidate +X-Content-Type-Options: nosniff +X-Gitlab-Meta: {"correlation_id":"fcbfb8d789b3f092196e301b01add051","version":"1"} +Gitlab-Sv: api-gke-us-east1-b +Cf-Cache-Status: MISS +Content-Security-Policy: default-src 'none' +Etag: W/"8db4917b3be5f4ca0d101a702179b75a" +X-Runtime: 0.230015 +Referrer-Policy: strict-origin-when-cross-origin +Gitlab-Lb: haproxy-main-39-lb-gprd +Set-Cookie: _cfuvid=cvUyaJC1KTpP.SBvDCjaIYRgZYh4zbY7BihbhwIUzt4-1709516922501-0.0.1.1-604800000; path=/; domain=.gitlab.com; HttpOnly; Secure; SameSite=None +Content-Type: application/json -{"id":15578026,"description":"Test repository for testing migration from gitlab to gitea","name":"test_repo","name_with_namespace":"gitea / test_repo","path":"test_repo","path_with_namespace":"gitea/test_repo","created_at":"2019-11-28T08:20:33.019Z","default_branch":"master","tag_list":["migration","test"],"topics":["migration","test"],"ssh_url_to_repo":"git@gitlab.com:gitea/test_repo.git","http_url_to_repo":"https://gitlab.com/gitea/test_repo.git","web_url":"https://gitlab.com/gitea/test_repo","readme_url":"https://gitlab.com/gitea/test_repo/-/blob/master/README.md","forks_count":1,"avatar_url":null,"star_count":0,"last_activity_at":"2020-04-19T19:46:04.527Z","namespace":{"id":3181312,"name":"gitea","path":"gitea","kind":"group","full_path":"gitea","parent_id":null,"avatar_url":"/uploads/-/system/group/avatar/3181312/gitea.png","web_url":"https://gitlab.com/groups/gitea"},"container_registry_image_prefix":"registry.gitlab.com/gitea/test_repo","_links":{"self":"https://gitlab.com/api/v4/projects/15578026","issues":"https://gitlab.com/api/v4/projects/15578026/issues","merge_requests":"https://gitlab.com/api/v4/projects/15578026/merge_requests","repo_branches":"https://gitlab.com/api/v4/projects/15578026/repository/branches","labels":"https://gitlab.com/api/v4/projects/15578026/labels","events":"https://gitlab.com/api/v4/projects/15578026/events","members":"https://gitlab.com/api/v4/projects/15578026/members","cluster_agents":"https://gitlab.com/api/v4/projects/15578026/cluster_agents"},"packages_enabled":true,"empty_repo":false,"archived":false,"visibility":"public","resolve_outdated_diff_discussions":false,"issues_enabled":true,"merge_requests_enabled":true,"wiki_enabled":true,"jobs_enabled":true,"snippets_enabled":true,"container_registry_enabled":true,"service_desk_enabled":true,"can_create_merge_request_in":true,"issues_access_level":"enabled","repository_access_level":"enabled","merge_requests_access_level":"enabled","forking_access_level":"enabled","wiki_access_level":"enabled","builds_access_level":"enabled","snippets_access_level":"enabled","pages_access_level":"enabled","analytics_access_level":"enabled","container_registry_access_level":"enabled","security_and_compliance_access_level":"private","releases_access_level":"enabled","environments_access_level":"enabled","feature_flags_access_level":"enabled","infrastructure_access_level":"enabled","monitor_access_level":"enabled","model_experiments_access_level":"enabled","emails_disabled":false,"emails_enabled":true,"shared_runners_enabled":true,"lfs_enabled":true,"creator_id":1241334,"import_status":"none","open_issues_count":0,"description_html":"\u003cp data-sourcepos=\"1:1-1:58\" dir=\"auto\"\u003eTest repository for testing migration from gitlab to gitea\u003c/p\u003e","updated_at":"2022-08-26T19:41:46.691Z","ci_config_path":null,"public_jobs":true,"shared_with_groups":[],"only_allow_merge_if_pipeline_succeeds":false,"allow_merge_on_skipped_pipeline":null,"request_access_enabled":true,"only_allow_merge_if_all_discussions_are_resolved":false,"remove_source_branch_after_merge":true,"printing_merge_request_link_enabled":true,"merge_method":"ff","squash_option":"default_off","enforce_auth_checks_on_uploads":true,"suggestion_commit_message":null,"merge_commit_template":null,"squash_commit_template":null,"issue_branch_template":null,"autoclose_referenced_issues":true,"external_authorization_classification_label":"","requirements_enabled":false,"requirements_access_level":"enabled","security_and_compliance_enabled":false,"compliance_frameworks":[],"permissions":{"project_access":null,"group_access":null}} \ No newline at end of file +{"id":15578026,"description":"Test repository for testing migration from gitlab to gitea","name":"test_repo","name_with_namespace":"gitea / test_repo","path":"test_repo","path_with_namespace":"gitea/test_repo","created_at":"2019-11-28T08:20:33.019Z","default_branch":"master","tag_list":["migration","test"],"topics":["migration","test"],"ssh_url_to_repo":"git@gitlab.com:gitea/test_repo.git","http_url_to_repo":"https://gitlab.com/gitea/test_repo.git","web_url":"https://gitlab.com/gitea/test_repo","readme_url":"https://gitlab.com/gitea/test_repo/-/blob/master/README.md","forks_count":1,"avatar_url":null,"star_count":0,"last_activity_at":"2020-04-19T19:46:04.527Z","namespace":{"id":3181312,"name":"gitea","path":"gitea","kind":"group","full_path":"gitea","parent_id":null,"avatar_url":"/uploads/-/system/group/avatar/3181312/gitea.png","web_url":"https://gitlab.com/groups/gitea"},"container_registry_image_prefix":"registry.gitlab.com/gitea/test_repo","_links":{"self":"https://gitlab.com/api/v4/projects/15578026","issues":"https://gitlab.com/api/v4/projects/15578026/issues","merge_requests":"https://gitlab.com/api/v4/projects/15578026/merge_requests","repo_branches":"https://gitlab.com/api/v4/projects/15578026/repository/branches","labels":"https://gitlab.com/api/v4/projects/15578026/labels","events":"https://gitlab.com/api/v4/projects/15578026/events","members":"https://gitlab.com/api/v4/projects/15578026/members","cluster_agents":"https://gitlab.com/api/v4/projects/15578026/cluster_agents"},"packages_enabled":true,"empty_repo":false,"archived":false,"visibility":"public","resolve_outdated_diff_discussions":false,"repository_object_format":"sha1","issues_enabled":true,"merge_requests_enabled":true,"wiki_enabled":true,"jobs_enabled":true,"snippets_enabled":true,"container_registry_enabled":true,"service_desk_enabled":true,"can_create_merge_request_in":true,"issues_access_level":"enabled","repository_access_level":"enabled","merge_requests_access_level":"enabled","forking_access_level":"enabled","wiki_access_level":"enabled","builds_access_level":"enabled","snippets_access_level":"enabled","pages_access_level":"enabled","analytics_access_level":"enabled","container_registry_access_level":"enabled","security_and_compliance_access_level":"private","releases_access_level":"enabled","environments_access_level":"enabled","feature_flags_access_level":"enabled","infrastructure_access_level":"enabled","monitor_access_level":"enabled","model_experiments_access_level":"enabled","model_registry_access_level":"enabled","emails_disabled":false,"emails_enabled":true,"shared_runners_enabled":true,"lfs_enabled":true,"creator_id":1241334,"import_status":"none","open_issues_count":0,"description_html":"\u003cp data-sourcepos=\"1:1-1:58\" dir=\"auto\"\u003eTest repository for testing migration from gitlab to gitea\u003c/p\u003e","updated_at":"2024-01-11T01:23:21.057Z","ci_config_path":null,"public_jobs":true,"shared_with_groups":[],"only_allow_merge_if_pipeline_succeeds":false,"allow_merge_on_skipped_pipeline":null,"request_access_enabled":true,"only_allow_merge_if_all_discussions_are_resolved":false,"remove_source_branch_after_merge":true,"printing_merge_request_link_enabled":true,"merge_method":"ff","squash_option":"default_off","enforce_auth_checks_on_uploads":true,"suggestion_commit_message":null,"merge_commit_template":null,"squash_commit_template":null,"issue_branch_template":null,"warn_about_potentially_unwanted_characters":true,"autoclose_referenced_issues":true,"external_authorization_classification_label":"","requirements_enabled":false,"requirements_access_level":"enabled","security_and_compliance_enabled":false,"compliance_frameworks":[],"permissions":{"project_access":null,"group_access":null}} \ No newline at end of file diff --git a/services/migrations/testdata/gitlab/full_download/_api_v4_projects_15578026_issues!page=1&per_page=2&sort=asc&state=all b/services/migrations/testdata/gitlab/full_download/_api_v4_projects_15578026_issues!page=1&per_page=2&sort=asc&state=all index 331a82720..17139efa2 100644 --- a/services/migrations/testdata/gitlab/full_download/_api_v4_projects_15578026_issues!page=1&per_page=2&sort=asc&state=all +++ b/services/migrations/testdata/gitlab/full_download/_api_v4_projects_15578026_issues!page=1&per_page=2&sort=asc&state=all @@ -1,29 +1,24 @@ +X-Content-Type-Options: nosniff +X-Per-Page: 2 +X-Total-Pages: 1 +Content-Type: application/json +X-Prev-Page: +X-Total: 2 Cache-Control: max-age=0, private, must-revalidate Vary: Origin, Accept-Encoding -Gitlab-Lb: haproxy-main-24-lb-gprd -Content-Type: application/json -X-Per-Page: 2 -X-Prev-Page: -Set-Cookie: _cfuvid=N.nfy5eIdFH5lXhsnMyEbeBkoxabcl1SVeyyP0_NrdE-1701333887790-0-604800000; path=/; domain=.gitlab.com; HttpOnly; Secure; SameSite=None -Content-Security-Policy: default-src 'none' -X-Content-Type-Options: nosniff -X-Next-Page: -X-Total-Pages: 1 -Etag: W/"4c0531a3595f741f229f5a105e013b95" -X-Gitlab-Meta: {"correlation_id":"b2eca136986f016d946685fb99287f1c","version":"1"} -Ratelimit-Observed: 8 -Ratelimit-Resettime: Thu, 30 Nov 2023 08:45:47 GMT -X-Frame-Options: SAMEORIGIN Referrer-Policy: strict-origin-when-cross-origin -Ratelimit-Remaining: 1992 -Gitlab-Sv: localhost -Cf-Cache-Status: MISS +Gitlab-Sv: api-gke-us-east1-d +X-Gitlab-Meta: {"correlation_id":"52846fcab419461a2c2f29f707dbd103","version":"1"} +X-Next-Page: Strict-Transport-Security: max-age=31536000 -Ratelimit-Limit: 2000 -X-Total: 2 -X-Page: 1 -X-Runtime: 0.178587 -Ratelimit-Reset: 1701333947 +Cf-Cache-Status: MISS Link: ; rel="first", ; rel="last" +Etag: W/"4c0531a3595f741f229f5a105e013b95" +X-Frame-Options: SAMEORIGIN +X-Page: 1 +Content-Security-Policy: default-src 'none' +Set-Cookie: _cfuvid=0ScIwDvsVw_dRSgtT9czuTLY6R5TGzB2UIk9653BEf0-1709516924974-0.0.1.1-604800000; path=/; domain=.gitlab.com; HttpOnly; Secure; SameSite=None +Gitlab-Lb: haproxy-main-38-lb-gprd +X-Runtime: 0.187797 [{"id":27687675,"iid":1,"project_id":15578026,"title":"Please add an animated gif icon to the merge button","description":"I just want the merge button to hurt my eyes a little. :stuck_out_tongue_closed_eyes:","state":"closed","created_at":"2019-11-28T08:43:35.459Z","updated_at":"2019-11-28T08:46:23.304Z","closed_at":"2019-11-28T08:46:23.275Z","closed_by":{"id":1241334,"username":"lafriks","name":"Lauris BH","state":"active","locked":false,"avatar_url":"https://gitlab.com/uploads/-/system/user/avatar/1241334/avatar.png","web_url":"https://gitlab.com/lafriks"},"labels":["bug","discussion"],"milestone":{"id":1082926,"iid":1,"project_id":15578026,"title":"1.0.0","description":"","state":"closed","created_at":"2019-11-28T08:42:30.301Z","updated_at":"2019-11-28T15:57:52.401Z","due_date":null,"start_date":null,"expired":false,"web_url":"https://gitlab.com/gitea/test_repo/-/milestones/1"},"assignees":[],"author":{"id":1241334,"username":"lafriks","name":"Lauris BH","state":"active","locked":false,"avatar_url":"https://gitlab.com/uploads/-/system/user/avatar/1241334/avatar.png","web_url":"https://gitlab.com/lafriks"},"type":"ISSUE","assignee":null,"user_notes_count":0,"merge_requests_count":0,"upvotes":1,"downvotes":0,"due_date":null,"confidential":false,"discussion_locked":null,"issue_type":"issue","web_url":"https://gitlab.com/gitea/test_repo/-/issues/1","time_stats":{"time_estimate":0,"total_time_spent":0,"human_time_estimate":null,"human_total_time_spent":null},"task_completion_status":{"count":0,"completed_count":0},"blocking_issues_count":0,"has_tasks":true,"task_status":"0 of 0 checklist items completed","_links":{"self":"https://gitlab.com/api/v4/projects/15578026/issues/1","notes":"https://gitlab.com/api/v4/projects/15578026/issues/1/notes","award_emoji":"https://gitlab.com/api/v4/projects/15578026/issues/1/award_emoji","project":"https://gitlab.com/api/v4/projects/15578026","closed_as_duplicate_of":null},"references":{"short":"#1","relative":"#1","full":"gitea/test_repo#1"},"severity":"UNKNOWN","moved_to_id":null,"service_desk_reply_to":null},{"id":27687706,"iid":2,"project_id":15578026,"title":"Test issue","description":"This is test issue 2, do not touch!","state":"closed","created_at":"2019-11-28T08:44:46.277Z","updated_at":"2019-11-28T08:45:44.987Z","closed_at":"2019-11-28T08:45:44.959Z","closed_by":{"id":1241334,"username":"lafriks","name":"Lauris BH","state":"active","locked":false,"avatar_url":"https://gitlab.com/uploads/-/system/user/avatar/1241334/avatar.png","web_url":"https://gitlab.com/lafriks"},"labels":["duplicate"],"milestone":{"id":1082927,"iid":2,"project_id":15578026,"title":"1.1.0","description":"","state":"active","created_at":"2019-11-28T08:42:44.575Z","updated_at":"2019-11-28T08:42:44.575Z","due_date":null,"start_date":null,"expired":false,"web_url":"https://gitlab.com/gitea/test_repo/-/milestones/2"},"assignees":[],"author":{"id":1241334,"username":"lafriks","name":"Lauris BH","state":"active","locked":false,"avatar_url":"https://gitlab.com/uploads/-/system/user/avatar/1241334/avatar.png","web_url":"https://gitlab.com/lafriks"},"type":"ISSUE","assignee":null,"user_notes_count":2,"merge_requests_count":0,"upvotes":1,"downvotes":1,"due_date":null,"confidential":false,"discussion_locked":null,"issue_type":"issue","web_url":"https://gitlab.com/gitea/test_repo/-/issues/2","time_stats":{"time_estimate":0,"total_time_spent":0,"human_time_estimate":null,"human_total_time_spent":null},"task_completion_status":{"count":0,"completed_count":0},"blocking_issues_count":0,"has_tasks":true,"task_status":"0 of 0 checklist items completed","_links":{"self":"https://gitlab.com/api/v4/projects/15578026/issues/2","notes":"https://gitlab.com/api/v4/projects/15578026/issues/2/notes","award_emoji":"https://gitlab.com/api/v4/projects/15578026/issues/2/award_emoji","project":"https://gitlab.com/api/v4/projects/15578026","closed_as_duplicate_of":null},"references":{"short":"#2","relative":"#2","full":"gitea/test_repo#2"},"severity":"UNKNOWN","moved_to_id":null,"service_desk_reply_to":null}] \ No newline at end of file diff --git a/services/migrations/testdata/gitlab/full_download/_api_v4_projects_15578026_issues_1_award_emoji!page=1&per_page=2 b/services/migrations/testdata/gitlab/full_download/_api_v4_projects_15578026_issues_1_award_emoji!page=1&per_page=2 index d8ab294ee..7b37f59f5 100644 --- a/services/migrations/testdata/gitlab/full_download/_api_v4_projects_15578026_issues_1_award_emoji!page=1&per_page=2 +++ b/services/migrations/testdata/gitlab/full_download/_api_v4_projects_15578026_issues_1_award_emoji!page=1&per_page=2 @@ -1,29 +1,24 @@ X-Total-Pages: 1 -Referrer-Policy: strict-origin-when-cross-origin -Cache-Control: max-age=0, private, must-revalidate -X-Frame-Options: SAMEORIGIN -X-Runtime: 0.052748 -X-Total: 2 -Gitlab-Sv: localhost -Link: ; rel="first", ; rel="last" -X-Content-Type-Options: nosniff -X-Gitlab-Meta: {"correlation_id":"22fc215ac386644c9cb8736b652cf702","version":"1"} -X-Per-Page: 2 -Strict-Transport-Security: max-age=31536000 -Ratelimit-Reset: 1701333947 -Content-Security-Policy: default-src 'none' -Ratelimit-Remaining: 1991 -Ratelimit-Observed: 9 -X-Next-Page: -Ratelimit-Resettime: Thu, 30 Nov 2023 08:45:47 GMT -Ratelimit-Limit: 2000 -Gitlab-Lb: haproxy-main-43-lb-gprd Cf-Cache-Status: MISS -Etag: W/"69c922434ed11248c864d157eb8eabfc" +Set-Cookie: _cfuvid=UtNiLvpRoIS0606tZnebN.nDbGog2IEOTI0M6iH6tKE-1709516925325-0.0.1.1-604800000; path=/; domain=.gitlab.com; HttpOnly; Secure; SameSite=None Content-Type: application/json +Link: ; rel="first", ; rel="last" +X-Gitlab-Meta: {"correlation_id":"7078187b1af666261210081509905846","version":"1"} +Strict-Transport-Security: max-age=31536000 Vary: Origin, Accept-Encoding +X-Total: 2 +Gitlab-Sv: api-gke-us-east1-b +Content-Security-Policy: default-src 'none' +X-Content-Type-Options: nosniff X-Page: 1 +X-Frame-Options: SAMEORIGIN X-Prev-Page: -Set-Cookie: _cfuvid=POpffkskz4lvLcv2Fhjp7lF3MsmIOugWDzFGtb3ZUig-1701333887995-0-604800000; path=/; domain=.gitlab.com; HttpOnly; Secure; SameSite=None +X-Runtime: 0.070454 +X-Next-Page: +Referrer-Policy: strict-origin-when-cross-origin +Gitlab-Lb: haproxy-main-51-lb-gprd +X-Per-Page: 2 +Cache-Control: max-age=0, private, must-revalidate +Etag: W/"69c922434ed11248c864d157eb8eabfc" [{"id":3009580,"name":"thumbsup","user":{"id":1241334,"username":"lafriks","name":"Lauris BH","state":"active","locked":false,"avatar_url":"https://gitlab.com/uploads/-/system/user/avatar/1241334/avatar.png","web_url":"https://gitlab.com/lafriks"},"created_at":"2019-11-28T08:43:40.322Z","updated_at":"2019-11-28T08:43:40.322Z","awardable_id":27687675,"awardable_type":"Issue","url":null},{"id":3009585,"name":"open_mouth","user":{"id":1241334,"username":"lafriks","name":"Lauris BH","state":"active","locked":false,"avatar_url":"https://gitlab.com/uploads/-/system/user/avatar/1241334/avatar.png","web_url":"https://gitlab.com/lafriks"},"created_at":"2019-11-28T08:44:01.902Z","updated_at":"2019-11-28T08:44:01.902Z","awardable_id":27687675,"awardable_type":"Issue","url":null}] \ No newline at end of file diff --git a/services/migrations/testdata/gitlab/full_download/_api_v4_projects_15578026_issues_1_award_emoji!page=2&per_page=2 b/services/migrations/testdata/gitlab/full_download/_api_v4_projects_15578026_issues_1_award_emoji!page=2&per_page=2 index 248afeff8..7f64231eb 100644 --- a/services/migrations/testdata/gitlab/full_download/_api_v4_projects_15578026_issues_1_award_emoji!page=2&per_page=2 +++ b/services/migrations/testdata/gitlab/full_download/_api_v4_projects_15578026_issues_1_award_emoji!page=2&per_page=2 @@ -1,31 +1,26 @@ -Content-Type: application/json Content-Length: 2 -X-Next-Page: -X-Gitlab-Meta: {"correlation_id":"6b9bc368e2cdc69a1b8e7d2dff7546c5","version":"1"} -Referrer-Policy: strict-origin-when-cross-origin -Ratelimit-Reset: 1701333948 +Cache-Control: max-age=0, private, must-revalidate +Accept-Ranges: bytes Strict-Transport-Security: max-age=31536000 -X-Per-Page: 2 -X-Total: 2 -Ratelimit-Limit: 2000 -Etag: W/"4f53cda18c2baa0c0354bb5f9a3ecbe5" -Link: ; rel="first", ; rel="last" -X-Runtime: 0.069944 -Ratelimit-Remaining: 1990 -Ratelimit-Resettime: Thu, 30 Nov 2023 08:45:48 GMT -Gitlab-Sv: localhost +Gitlab-Lb: haproxy-main-57-lb-gprd +Gitlab-Sv: api-gke-us-east1-b X-Prev-Page: +X-Runtime: 0.048686 +Cf-Cache-Status: MISS +Vary: Origin, Accept-Encoding +X-Per-Page: 2 +Referrer-Policy: strict-origin-when-cross-origin +X-Gitlab-Meta: {"correlation_id":"53764b779171a3a641999caf45eb5cda","version":"1"} +X-Page: 2 +X-Total: 2 X-Total-Pages: 1 -Ratelimit-Observed: 10 -Gitlab-Lb: haproxy-main-17-lb-gprd +Content-Type: application/json +X-Next-Page: +Set-Cookie: _cfuvid=.aWihkIt1YOKnLoix6oJ3avCXZ_942rAkWJpHXKtKXk-1709516926358-0.0.1.1-604800000; path=/; domain=.gitlab.com; HttpOnly; Secure; SameSite=None Content-Security-Policy: default-src 'none' X-Content-Type-Options: nosniff X-Frame-Options: SAMEORIGIN -Accept-Ranges: bytes -Cache-Control: max-age=0, private, must-revalidate -Vary: Origin, Accept-Encoding -X-Page: 2 -Cf-Cache-Status: MISS -Set-Cookie: _cfuvid=vcfsxezcg_2Kdh8xD5coOU_uxQIH1in.6BsRttrSIYg-1701333888217-0-604800000; path=/; domain=.gitlab.com; HttpOnly; Secure; SameSite=None +Etag: W/"4f53cda18c2baa0c0354bb5f9a3ecbe5" +Link: ; rel="first", ; rel="last" [] \ No newline at end of file diff --git a/services/migrations/testdata/gitlab/full_download/_api_v4_projects_15578026_issues_2_award_emoji!page=1&per_page=2 b/services/migrations/testdata/gitlab/full_download/_api_v4_projects_15578026_issues_2_award_emoji!page=1&per_page=2 index 70c50c8fe..db1573c43 100644 --- a/services/migrations/testdata/gitlab/full_download/_api_v4_projects_15578026_issues_2_award_emoji!page=1&per_page=2 +++ b/services/migrations/testdata/gitlab/full_download/_api_v4_projects_15578026_issues_2_award_emoji!page=1&per_page=2 @@ -1,29 +1,24 @@ -Cf-Cache-Status: MISS -Etag: W/"5fdbcbf64f34ba0e74ce9dd8d6e0efe3" +Vary: Origin, Accept-Encoding +Set-Cookie: _cfuvid=eR1OqXm9Zq42ps0oFIf0s4qBdC4lKtotvp9jBqOVcko-1709516927407-0.0.1.1-604800000; path=/; domain=.gitlab.com; HttpOnly; Secure; SameSite=None +Content-Security-Policy: default-src 'none' X-Content-Type-Options: nosniff -X-Per-Page: 2 -Ratelimit-Limit: 2000 -Set-Cookie: _cfuvid=NLtUZdQlWvWiXr4L8Zfc555FowZOCxJlA0pAOAEkNvg-1701333888445-0-604800000; path=/; domain=.gitlab.com; HttpOnly; Secure; SameSite=None -X-Runtime: 0.075612 -Ratelimit-Reset: 1701333948 -Ratelimit-Resettime: Thu, 30 Nov 2023 08:45:48 GMT +X-Next-Page: 2 X-Page: 1 X-Prev-Page: X-Total-Pages: 3 -X-Frame-Options: SAMEORIGIN -Referrer-Policy: strict-origin-when-cross-origin -Content-Security-Policy: default-src 'none' -Ratelimit-Observed: 11 -Gitlab-Lb: haproxy-main-09-lb-gprd -Gitlab-Sv: localhost -Ratelimit-Remaining: 1989 -Cache-Control: max-age=0, private, must-revalidate Link: ; rel="next", ; rel="first", ; rel="last" -X-Gitlab-Meta: {"correlation_id":"a69709cf552479bc5f5f3e4e1f808790","version":"1"} -X-Next-Page: 2 -Strict-Transport-Security: max-age=31536000 -Content-Type: application/json -Vary: Origin, Accept-Encoding +Referrer-Policy: strict-origin-when-cross-origin X-Total: 6 +Cache-Control: max-age=0, private, must-revalidate +X-Per-Page: 2 +Gitlab-Sv: api-gke-us-east1-d +X-Gitlab-Meta: {"correlation_id":"05328c4fe2465085c0b9a5a5a1103836","version":"1"} +X-Runtime: 0.075509 +Strict-Transport-Security: max-age=31536000 +Gitlab-Lb: haproxy-main-50-lb-gprd +Content-Type: application/json +Etag: W/"5fdbcbf64f34ba0e74ce9dd8d6e0efe3" +X-Frame-Options: SAMEORIGIN +Cf-Cache-Status: MISS [{"id":3009627,"name":"thumbsup","user":{"id":1241334,"username":"lafriks","name":"Lauris BH","state":"active","locked":false,"avatar_url":"https://gitlab.com/uploads/-/system/user/avatar/1241334/avatar.png","web_url":"https://gitlab.com/lafriks"},"created_at":"2019-11-28T08:46:42.657Z","updated_at":"2019-11-28T08:46:42.657Z","awardable_id":27687706,"awardable_type":"Issue","url":null},{"id":3009628,"name":"thumbsdown","user":{"id":1241334,"username":"lafriks","name":"Lauris BH","state":"active","locked":false,"avatar_url":"https://gitlab.com/uploads/-/system/user/avatar/1241334/avatar.png","web_url":"https://gitlab.com/lafriks"},"created_at":"2019-11-28T08:46:43.471Z","updated_at":"2019-11-28T08:46:43.471Z","awardable_id":27687706,"awardable_type":"Issue","url":null}] \ No newline at end of file diff --git a/services/migrations/testdata/gitlab/full_download/_api_v4_projects_15578026_issues_2_award_emoji!page=2&per_page=2 b/services/migrations/testdata/gitlab/full_download/_api_v4_projects_15578026_issues_2_award_emoji!page=2&per_page=2 index 1014d9dbc..d52e358e9 100644 --- a/services/migrations/testdata/gitlab/full_download/_api_v4_projects_15578026_issues_2_award_emoji!page=2&per_page=2 +++ b/services/migrations/testdata/gitlab/full_download/_api_v4_projects_15578026_issues_2_award_emoji!page=2&per_page=2 @@ -1,29 +1,24 @@ -Ratelimit-Limit: 2000 X-Content-Type-Options: nosniff -Ratelimit-Resettime: Thu, 30 Nov 2023 08:45:48 GMT -X-Total: 6 -Set-Cookie: _cfuvid=E5GyZy0rB2zrRH0ewMyrJd1wBrt7A2sGNmOHTiWwbYk-1701333888703-0-604800000; path=/; domain=.gitlab.com; HttpOnly; Secure; SameSite=None -X-Next-Page: 3 -X-Page: 2 -Link: ; rel="prev", ; rel="next", ; rel="first", ; rel="last" -X-Gitlab-Meta: {"correlation_id":"41e59fb2e78f5e68518b81bd4ff3bb1b","version":"1"} -X-Prev-Page: 1 -Cf-Cache-Status: MISS +X-Runtime: 0.091658 +Set-Cookie: _cfuvid=aVGYOkTTE5ngoJripH93fZ9JhYhafbwSPqzjRZ7JCyk-1709516927910-0.0.1.1-604800000; path=/; domain=.gitlab.com; HttpOnly; Secure; SameSite=None Referrer-Policy: strict-origin-when-cross-origin -Gitlab-Lb: haproxy-main-26-lb-gprd -Cache-Control: max-age=0, private, must-revalidate -Etag: W/"d16c513b32212d9286fce6f53340c1cf" -Vary: Origin, Accept-Encoding -X-Per-Page: 2 -Strict-Transport-Security: max-age=31536000 -Ratelimit-Reset: 1701333948 -Content-Type: application/json -X-Runtime: 0.105758 -Ratelimit-Remaining: 1988 -Content-Security-Policy: default-src 'none' X-Frame-Options: SAMEORIGIN -Gitlab-Sv: localhost +X-Gitlab-Meta: {"correlation_id":"b1d1356c71e3f52fc9bccd80a711467f","version":"1"} +X-Prev-Page: 1 +Strict-Transport-Security: max-age=31536000 +Gitlab-Sv: api-gke-us-east1-c +Content-Type: application/json +Content-Security-Policy: default-src 'none' +Vary: Origin, Accept-Encoding +X-Page: 2 +X-Per-Page: 2 +Cf-Cache-Status: MISS +X-Total: 6 +Gitlab-Lb: haproxy-main-13-lb-gprd +Etag: W/"d16c513b32212d9286fce6f53340c1cf" +X-Next-Page: 3 X-Total-Pages: 3 -Ratelimit-Observed: 12 +Cache-Control: max-age=0, private, must-revalidate +Link: ; rel="prev", ; rel="next", ; rel="first", ; rel="last" [{"id":3009632,"name":"laughing","user":{"id":1241334,"username":"lafriks","name":"Lauris BH","state":"active","locked":false,"avatar_url":"https://gitlab.com/uploads/-/system/user/avatar/1241334/avatar.png","web_url":"https://gitlab.com/lafriks"},"created_at":"2019-11-28T08:47:14.381Z","updated_at":"2019-11-28T08:47:14.381Z","awardable_id":27687706,"awardable_type":"Issue","url":null},{"id":3009634,"name":"tada","user":{"id":1241334,"username":"lafriks","name":"Lauris BH","state":"active","locked":false,"avatar_url":"https://gitlab.com/uploads/-/system/user/avatar/1241334/avatar.png","web_url":"https://gitlab.com/lafriks"},"created_at":"2019-11-28T08:47:18.254Z","updated_at":"2019-11-28T08:47:18.254Z","awardable_id":27687706,"awardable_type":"Issue","url":null}] \ No newline at end of file diff --git a/services/migrations/testdata/gitlab/full_download/_api_v4_projects_15578026_issues_2_award_emoji!page=3&per_page=2 b/services/migrations/testdata/gitlab/full_download/_api_v4_projects_15578026_issues_2_award_emoji!page=3&per_page=2 index 9c42bfb9b..e35aa62cd 100644 --- a/services/migrations/testdata/gitlab/full_download/_api_v4_projects_15578026_issues_2_award_emoji!page=3&per_page=2 +++ b/services/migrations/testdata/gitlab/full_download/_api_v4_projects_15578026_issues_2_award_emoji!page=3&per_page=2 @@ -1,29 +1,24 @@ -Content-Type: application/json -X-Content-Type-Options: nosniff -X-Frame-Options: SAMEORIGIN -Referrer-Policy: strict-origin-when-cross-origin -Link: ; rel="prev", ; rel="first", ; rel="last" -Cf-Cache-Status: MISS -Etag: W/"165d37bf09a54bb31f4619cca8722cb4" -Ratelimit-Observed: 13 -Ratelimit-Limit: 2000 -Set-Cookie: _cfuvid=W6F2uJSFkB3Iyl27_xtklVvP4Z_nSsjPqytClHPW9H8-1701333888913-0-604800000; path=/; domain=.gitlab.com; HttpOnly; Secure; SameSite=None -X-Page: 3 -X-Total-Pages: 3 -Strict-Transport-Security: max-age=31536000 -Ratelimit-Resettime: Thu, 30 Nov 2023 08:45:48 GMT +Gitlab-Lb: haproxy-main-13-lb-gprd +Set-Cookie: _cfuvid=t4_LSY2Wo_P8jPVZKgbX7DhNDlsiazGyv6awHkbP29M-1709516929175-0.0.1.1-604800000; path=/; domain=.gitlab.com; HttpOnly; Secure; SameSite=None Cache-Control: max-age=0, private, must-revalidate Vary: Origin, Accept-Encoding -X-Gitlab-Meta: {"correlation_id":"b805751aeb6f562dff684cec34dfdc0b","version":"1"} -X-Per-Page: 2 -X-Prev-Page: 2 -X-Runtime: 0.061943 -Gitlab-Lb: haproxy-main-11-lb-gprd -Gitlab-Sv: localhost +Referrer-Policy: strict-origin-when-cross-origin +Cf-Cache-Status: MISS X-Total: 6 -Ratelimit-Remaining: 1987 -Content-Security-Policy: default-src 'none' +X-Total-Pages: 3 +Etag: W/"165d37bf09a54bb31f4619cca8722cb4" +Link: ; rel="prev", ; rel="first", ; rel="last" +Gitlab-Sv: api-gke-us-east1-c +X-Runtime: 0.084688 +Strict-Transport-Security: max-age=31536000 +Content-Type: application/json +X-Content-Type-Options: nosniff +X-Prev-Page: 2 X-Next-Page: -Ratelimit-Reset: 1701333948 +X-Page: 3 +X-Frame-Options: SAMEORIGIN +X-Gitlab-Meta: {"correlation_id":"3d4b896e9b25fba2880f8cf4179b4db3","version":"1"} +Content-Security-Policy: default-src 'none' +X-Per-Page: 2 [{"id":3009636,"name":"confused","user":{"id":1241334,"username":"lafriks","name":"Lauris BH","state":"active","locked":false,"avatar_url":"https://gitlab.com/uploads/-/system/user/avatar/1241334/avatar.png","web_url":"https://gitlab.com/lafriks"},"created_at":"2019-11-28T08:47:27.248Z","updated_at":"2019-11-28T08:47:27.248Z","awardable_id":27687706,"awardable_type":"Issue","url":null},{"id":3009640,"name":"hearts","user":{"id":1241334,"username":"lafriks","name":"Lauris BH","state":"active","locked":false,"avatar_url":"https://gitlab.com/uploads/-/system/user/avatar/1241334/avatar.png","web_url":"https://gitlab.com/lafriks"},"created_at":"2019-11-28T08:47:33.059Z","updated_at":"2019-11-28T08:47:33.059Z","awardable_id":27687706,"awardable_type":"Issue","url":null}] \ No newline at end of file diff --git a/services/migrations/testdata/gitlab/full_download/_api_v4_projects_15578026_issues_2_award_emoji!page=4&per_page=2 b/services/migrations/testdata/gitlab/full_download/_api_v4_projects_15578026_issues_2_award_emoji!page=4&per_page=2 index e550e4ad1..2c757e203 100644 --- a/services/migrations/testdata/gitlab/full_download/_api_v4_projects_15578026_issues_2_award_emoji!page=4&per_page=2 +++ b/services/migrations/testdata/gitlab/full_download/_api_v4_projects_15578026_issues_2_award_emoji!page=4&per_page=2 @@ -1,31 +1,26 @@ -Ratelimit-Remaining: 1986 -Accept-Ranges: bytes -Set-Cookie: _cfuvid=DZQIMINjFohqKKjkWnojkq2xuUaqb42YEQg3BZXe68w-1701333889148-0-604800000; path=/; domain=.gitlab.com; HttpOnly; Secure; SameSite=None -Strict-Transport-Security: max-age=31536000 -X-Prev-Page: -Ratelimit-Reset: 1701333949 -Ratelimit-Limit: 2000 +Vary: Origin, Accept-Encoding +Content-Length: 2 Etag: W/"4f53cda18c2baa0c0354bb5f9a3ecbe5" -Cache-Control: max-age=0, private, must-revalidate X-Next-Page: X-Page: 4 -Referrer-Policy: strict-origin-when-cross-origin -Gitlab-Sv: localhost +Strict-Transport-Security: max-age=31536000 +Gitlab-Lb: haproxy-main-40-lb-gprd +Set-Cookie: _cfuvid=V6zFYEypjQbDjYSsP9fTmKa2nKJP5kvVJDoSbH7rU34-1709516930295-0.0.1.1-604800000; path=/; domain=.gitlab.com; HttpOnly; Secure; SameSite=None Content-Type: application/json -X-Content-Type-Options: nosniff -Link: ; rel="first", ; rel="last" -Vary: Origin, Accept-Encoding -Content-Security-Policy: default-src 'none' -X-Runtime: 0.081728 -X-Total: 6 -Content-Length: 2 -X-Frame-Options: SAMEORIGIN -X-Gitlab-Meta: {"correlation_id":"588184d2d9ad2c4a7e7c00a51575091c","version":"1"} -Cf-Cache-Status: MISS +X-Gitlab-Meta: {"correlation_id":"58338440ce0dd25dea95208140617efc","version":"1"} X-Total-Pages: 3 -Ratelimit-Observed: 14 -Ratelimit-Resettime: Thu, 30 Nov 2023 08:45:49 GMT -Gitlab-Lb: haproxy-main-34-lb-gprd +Cf-Cache-Status: MISS +Cache-Control: max-age=0, private, must-revalidate +X-Frame-Options: SAMEORIGIN +X-Total: 6 +X-Prev-Page: +Accept-Ranges: bytes +X-Content-Type-Options: nosniff +X-Runtime: 0.052295 +Referrer-Policy: strict-origin-when-cross-origin +Gitlab-Sv: api-gke-us-east1-c +Content-Security-Policy: default-src 'none' X-Per-Page: 2 +Link: ; rel="first", ; rel="last" [] \ No newline at end of file diff --git a/services/migrations/testdata/gitlab/full_download/_api_v4_projects_15578026_issues_2_discussions!page=1&per_page=100 b/services/migrations/testdata/gitlab/full_download/_api_v4_projects_15578026_issues_2_discussions!page=1&per_page=100 index d74fc325a..2dc290a40 100644 --- a/services/migrations/testdata/gitlab/full_download/_api_v4_projects_15578026_issues_2_discussions!page=1&per_page=100 +++ b/services/migrations/testdata/gitlab/full_download/_api_v4_projects_15578026_issues_2_discussions!page=1&per_page=100 @@ -1,29 +1,24 @@ -X-Runtime: 0.173849 -Content-Security-Policy: default-src 'none' +X-Gitlab-Meta: {"correlation_id":"f7ea96beef459528c06bcf21a37f8950","version":"1"} X-Per-Page: 100 -X-Prev-Page: -X-Total: 4 -Ratelimit-Observed: 15 -X-Page: 1 -Ratelimit-Remaining: 1985 +X-Runtime: 0.294630 Cache-Control: max-age=0, private, must-revalidate -X-Gitlab-Meta: {"correlation_id":"1d2b49b1b17e0c2d58c800a1b6c7eca3","version":"1"} -X-Next-Page: -Referrer-Policy: strict-origin-when-cross-origin -Cf-Cache-Status: MISS -Content-Type: application/json -Etag: W/"bcc91e8a7b2eac98b4d96ae791e0649d" -Vary: Origin, Accept-Encoding +Gitlab-Sv: gke-cny-api X-Frame-Options: SAMEORIGIN +X-Next-Page: +Etag: W/"bcc91e8a7b2eac98b4d96ae791e0649d" +X-Total: 4 +X-Page: 1 +Referrer-Policy: strict-origin-when-cross-origin +Gitlab-Lb: haproxy-main-32-lb-gprd Strict-Transport-Security: max-age=31536000 -Ratelimit-Reset: 1701333949 -Gitlab-Lb: haproxy-main-08-lb-gprd -Gitlab-Sv: localhost +Set-Cookie: _cfuvid=bVDOhVwoTt.rATMQeCGhPoIH4lvwoCZQqEHaWL0EOVY-1709516931074-0.0.1.1-604800000; path=/; domain=.gitlab.com; HttpOnly; Secure; SameSite=None Link: ; rel="first", ; rel="last" X-Content-Type-Options: nosniff +X-Prev-Page: +Content-Type: application/json +Cf-Cache-Status: MISS +Content-Security-Policy: default-src 'none' +Vary: Origin, Accept-Encoding X-Total-Pages: 1 -Ratelimit-Limit: 2000 -Set-Cookie: _cfuvid=yj.PGr9ftsz1kNpgtsmQhAcGpdMnklLE.NQ9h71hm5Q-1701333889475-0-604800000; path=/; domain=.gitlab.com; HttpOnly; Secure; SameSite=None -Ratelimit-Resettime: Thu, 30 Nov 2023 08:45:49 GMT [{"id":"617967369d98d8b73b6105a40318fe839f931a24","individual_note":true,"notes":[{"id":251637434,"type":null,"body":"This is a comment","attachment":null,"author":{"id":1241334,"username":"lafriks","name":"Lauris BH","state":"active","locked":false,"avatar_url":"https://gitlab.com/uploads/-/system/user/avatar/1241334/avatar.png","web_url":"https://gitlab.com/lafriks"},"created_at":"2019-11-28T08:44:52.501Z","updated_at":"2019-11-28T08:44:52.501Z","system":false,"noteable_id":27687706,"noteable_type":"Issue","project_id":15578026,"resolvable":false,"confidential":false,"internal":false,"noteable_iid":2,"commands_changes":{}}]},{"id":"b92d74daee411a17d844041bcd3c267ade58f680","individual_note":true,"notes":[{"id":251637528,"type":null,"body":"changed milestone to %2","attachment":null,"author":{"id":1241334,"username":"lafriks","name":"Lauris BH","state":"active","locked":false,"avatar_url":"https://gitlab.com/uploads/-/system/user/avatar/1241334/avatar.png","web_url":"https://gitlab.com/lafriks"},"created_at":"2019-11-28T08:45:02.329Z","updated_at":"2019-11-28T08:45:02.335Z","system":true,"noteable_id":27687706,"noteable_type":"Issue","project_id":15578026,"resolvable":false,"confidential":false,"internal":false,"noteable_iid":2,"commands_changes":{}}]},{"id":"6010f567d2b58758ef618070372c97891ac75349","individual_note":true,"notes":[{"id":251637892,"type":null,"body":"closed","attachment":null,"author":{"id":1241334,"username":"lafriks","name":"Lauris BH","state":"active","locked":false,"avatar_url":"https://gitlab.com/uploads/-/system/user/avatar/1241334/avatar.png","web_url":"https://gitlab.com/lafriks"},"created_at":"2019-11-28T08:45:45.007Z","updated_at":"2019-11-28T08:45:45.010Z","system":true,"noteable_id":27687706,"noteable_type":"Issue","project_id":15578026,"resolvable":false,"confidential":false,"internal":false,"noteable_iid":2,"commands_changes":{}}]},{"id":"632d0cbfd6a1a08f38aaf9ef7715116f4b188ebb","individual_note":true,"notes":[{"id":251637999,"type":null,"body":"A second comment","attachment":null,"author":{"id":1241334,"username":"lafriks","name":"Lauris BH","state":"active","locked":false,"avatar_url":"https://gitlab.com/uploads/-/system/user/avatar/1241334/avatar.png","web_url":"https://gitlab.com/lafriks"},"created_at":"2019-11-28T08:45:53.501Z","updated_at":"2019-11-28T08:45:53.501Z","system":false,"noteable_id":27687706,"noteable_type":"Issue","project_id":15578026,"resolvable":false,"confidential":false,"internal":false,"noteable_iid":2,"commands_changes":{}}]}] \ No newline at end of file diff --git a/services/migrations/testdata/gitlab/full_download/_api_v4_projects_15578026_issues_2_resource_state_events!page=1&per_page=100 b/services/migrations/testdata/gitlab/full_download/_api_v4_projects_15578026_issues_2_resource_state_events!page=1&per_page=100 new file mode 100644 index 000000000..a67d0c45b --- /dev/null +++ b/services/migrations/testdata/gitlab/full_download/_api_v4_projects_15578026_issues_2_resource_state_events!page=1&per_page=100 @@ -0,0 +1,26 @@ +Cf-Cache-Status: MISS +Etag: W/"4f53cda18c2baa0c0354bb5f9a3ecbe5" +X-Content-Type-Options: nosniff +Referrer-Policy: strict-origin-when-cross-origin +Gitlab-Lb: haproxy-main-52-lb-gprd +Content-Length: 2 +X-Prev-Page: +Set-Cookie: _cfuvid=W2TdoA.hvJeMOjx.ZmMBWpZVvCP6nNxmeM6PQsr8.Kw-1709516931498-0.0.1.1-604800000; path=/; domain=.gitlab.com; HttpOnly; Secure; SameSite=None +Link: ; rel="first", ; rel="last" +X-Frame-Options: SAMEORIGIN +Strict-Transport-Security: max-age=31536000 +Vary: Origin, Accept-Encoding +Content-Security-Policy: default-src 'none' +X-Gitlab-Meta: {"correlation_id":"527e08a612a163b94cd95046842d5e64","version":"1"} +X-Page: 1 +X-Per-Page: 100 +X-Total: 0 +Content-Type: application/json +Accept-Ranges: bytes +Cache-Control: max-age=0, private, must-revalidate +X-Next-Page: +X-Total-Pages: 1 +Gitlab-Sv: api-gke-us-east1-c +X-Runtime: 0.123529 + +[] \ No newline at end of file diff --git a/services/migrations/testdata/gitlab/full_download/_api_v4_projects_15578026_labels!page=1&per_page=100 b/services/migrations/testdata/gitlab/full_download/_api_v4_projects_15578026_labels!page=1&per_page=100 index c79889fbf..03a46d057 100644 --- a/services/migrations/testdata/gitlab/full_download/_api_v4_projects_15578026_labels!page=1&per_page=100 +++ b/services/migrations/testdata/gitlab/full_download/_api_v4_projects_15578026_labels!page=1&per_page=100 @@ -1,29 +1,24 @@ -Cache-Control: max-age=0, private, must-revalidate -Strict-Transport-Security: max-age=31536000 -Gitlab-Lb: haproxy-main-28-lb-gprd -Link: ; rel="first", ; rel="last" -X-Per-Page: 100 -X-Runtime: 0.149464 -X-Total: 9 -Ratelimit-Observed: 6 -Gitlab-Sv: localhost -X-Frame-Options: SAMEORIGIN -X-Gitlab-Meta: {"correlation_id":"2ccddf20767704a98ed6b582db3b103e","version":"1"} -X-Next-Page: X-Prev-Page: -X-Total-Pages: 1 -Ratelimit-Remaining: 1994 -Etag: W/"5a3fb9bc7b1018070943f4aa1353f8b6" -Ratelimit-Limit: 2000 -X-Page: 1 -Content-Type: application/json -Vary: Origin, Accept-Encoding -Set-Cookie: _cfuvid=geNpLvH8Cv5XeYfUVwtpaazw43v9lCcqHE.vyXGk3kU-1701333887126-0-604800000; path=/; domain=.gitlab.com; HttpOnly; Secure; SameSite=None -X-Content-Type-Options: nosniff -Ratelimit-Reset: 1701333947 -Ratelimit-Resettime: Thu, 30 Nov 2023 08:45:47 GMT -Content-Security-Policy: default-src 'none' Referrer-Policy: strict-origin-when-cross-origin +Content-Type: application/json +X-Per-Page: 100 +X-Total: 9 +X-Runtime: 0.114167 +X-Total-Pages: 1 +Set-Cookie: _cfuvid=UMIyFl_InnSbX4Uxs5X.6ssGMrTVlv5uJzGE_UhDR3w-1709516923392-0.0.1.1-604800000; path=/; domain=.gitlab.com; HttpOnly; Secure; SameSite=None +Cache-Control: max-age=0, private, must-revalidate +Link: ; rel="first", ; rel="last" +X-Content-Type-Options: nosniff +Gitlab-Sv: api-gke-us-east1-b +Content-Security-Policy: default-src 'none' +Vary: Origin, Accept-Encoding +X-Next-Page: +X-Frame-Options: SAMEORIGIN +X-Gitlab-Meta: {"correlation_id":"3b4e48efc61f09520ea23b3bca5ea469","version":"1"} +X-Page: 1 Cf-Cache-Status: MISS +Etag: W/"5a3fb9bc7b1018070943f4aa1353f8b6" +Strict-Transport-Security: max-age=31536000 +Gitlab-Lb: haproxy-main-30-lb-gprd [{"id":12959095,"name":"bug","description":null,"description_html":"","text_color":"#FFFFFF","color":"#d9534f","subscribed":false,"priority":null,"is_project_label":true},{"id":12959097,"name":"confirmed","description":null,"description_html":"","text_color":"#FFFFFF","color":"#d9534f","subscribed":false,"priority":null,"is_project_label":true},{"id":12959096,"name":"critical","description":null,"description_html":"","text_color":"#FFFFFF","color":"#d9534f","subscribed":false,"priority":null,"is_project_label":true},{"id":12959100,"name":"discussion","description":null,"description_html":"","text_color":"#FFFFFF","color":"#428bca","subscribed":false,"priority":null,"is_project_label":true},{"id":12959098,"name":"documentation","description":null,"description_html":"","text_color":"#1F1E24","color":"#f0ad4e","subscribed":false,"priority":null,"is_project_label":true},{"id":12959554,"name":"duplicate","description":null,"description_html":"","text_color":"#FFFFFF","color":"#7F8C8D","subscribed":false,"priority":null,"is_project_label":true},{"id":12959102,"name":"enhancement","description":null,"description_html":"","text_color":"#FFFFFF","color":"#5cb85c","subscribed":false,"priority":null,"is_project_label":true},{"id":12959101,"name":"suggestion","description":null,"description_html":"","text_color":"#FFFFFF","color":"#428bca","subscribed":false,"priority":null,"is_project_label":true},{"id":12959099,"name":"support","description":null,"description_html":"","text_color":"#1F1E24","color":"#f0ad4e","subscribed":false,"priority":null,"is_project_label":true}] \ No newline at end of file diff --git a/services/migrations/testdata/gitlab/full_download/_api_v4_projects_15578026_merge_requests!page=1&per_page=1&view=simple b/services/migrations/testdata/gitlab/full_download/_api_v4_projects_15578026_merge_requests!page=1&per_page=1&view=simple index 7eec1ca91..6f8d70200 100644 --- a/services/migrations/testdata/gitlab/full_download/_api_v4_projects_15578026_merge_requests!page=1&per_page=1&view=simple +++ b/services/migrations/testdata/gitlab/full_download/_api_v4_projects_15578026_merge_requests!page=1&per_page=1&view=simple @@ -1,29 +1,24 @@ -Content-Type: application/json -X-Page: 1 -Link: ; rel="next", ; rel="first", ; rel="last" -Vary: Origin, Accept-Encoding -X-Runtime: 0.139912 -X-Gitlab-Meta: {"correlation_id":"002c20b78ace441f5585931fed7093ed","version":"1"} -Gitlab-Sv: localhost -Cache-Control: max-age=0, private, must-revalidate -X-Total: 2 -X-Total-Pages: 2 -Ratelimit-Observed: 16 -Ratelimit-Limit: 2000 -X-Content-Type-Options: nosniff -Ratelimit-Remaining: 1984 -Set-Cookie: _cfuvid=6nsOEFMJm7NgrvYZAMGwiJBdm5A5CU71S33zOdN8Kyo-1701333889768-0-604800000; path=/; domain=.gitlab.com; HttpOnly; Secure; SameSite=None -X-Per-Page: 1 -X-Prev-Page: -Strict-Transport-Security: max-age=31536000 -Ratelimit-Reset: 1701333949 -Gitlab-Lb: haproxy-main-09-lb-gprd -X-Next-Page: 2 -Cf-Cache-Status: MISS Content-Security-Policy: default-src 'none' Etag: W/"14f72c1f555b0e6348d338190e9e4839" +Strict-Transport-Security: max-age=31536000 +Cf-Cache-Status: MISS +Set-Cookie: _cfuvid=V__PxQ60qzlepbd7My22SIsuTFfjEafoCsqahPDPjMg-1709516932676-0.0.1.1-604800000; path=/; domain=.gitlab.com; HttpOnly; Secure; SameSite=None X-Frame-Options: SAMEORIGIN +X-Per-Page: 1 +X-Total: 2 +X-Total-Pages: 2 +Gitlab-Sv: api-gke-us-east1-d +Content-Type: application/json +X-Content-Type-Options: nosniff +X-Next-Page: 2 Referrer-Policy: strict-origin-when-cross-origin -Ratelimit-Resettime: Thu, 30 Nov 2023 08:45:49 GMT +Vary: Origin, Accept-Encoding +Cache-Control: max-age=0, private, must-revalidate +Link: ; rel="next", ; rel="first", ; rel="last" +X-Prev-Page: +X-Gitlab-Meta: {"correlation_id":"7e815ab626b3ec958eb45b614106a759","version":"1"} +X-Page: 1 +X-Runtime: 0.130064 +Gitlab-Lb: haproxy-main-38-lb-gprd [{"id":43524600,"iid":2,"project_id":15578026,"title":"Test branch","description":"do not merge this PR","state":"opened","created_at":"2019-11-28T15:56:54.104Z","updated_at":"2020-04-19T19:24:21.108Z","web_url":"https://gitlab.com/gitea/test_repo/-/merge_requests/2"}] \ No newline at end of file diff --git a/services/migrations/testdata/gitlab/full_download/_api_v4_projects_15578026_merge_requests_1_approvals b/services/migrations/testdata/gitlab/full_download/_api_v4_projects_15578026_merge_requests_1_approvals index 80df508bc..7a3ab6b85 100644 --- a/services/migrations/testdata/gitlab/full_download/_api_v4_projects_15578026_merge_requests_1_approvals +++ b/services/migrations/testdata/gitlab/full_download/_api_v4_projects_15578026_merge_requests_1_approvals @@ -1,22 +1,17 @@ -Ratelimit-Resettime: Thu, 30 Nov 2023 08:45:51 GMT -Ratelimit-Limit: 2000 -Content-Security-Policy: default-src 'none' -X-Gitlab-Meta: {"correlation_id":"0a1a7339f3527e175a537afe058a6ac7","version":"1"} -Ratelimit-Observed: 21 Cache-Control: max-age=0, private, must-revalidate -Gitlab-Lb: haproxy-main-38-lb-gprd -X-Frame-Options: SAMEORIGIN +Content-Security-Policy: default-src 'none' Strict-Transport-Security: max-age=31536000 -Cf-Cache-Status: MISS -Content-Type: application/json -Etag: W/"19aa54b7d4531bd5ab98282e0b772f20" X-Content-Type-Options: nosniff -Set-Cookie: _cfuvid=J2edW64FLja6v0MZCh5tVbLYO42.VvIsTqQ.uj1Gr_k-1701333891171-0-604800000; path=/; domain=.gitlab.com; HttpOnly; Secure; SameSite=None -Ratelimit-Reset: 1701333951 -Gitlab-Sv: localhost +X-Frame-Options: SAMEORIGIN +Set-Cookie: _cfuvid=z0y3rhqnpB208dDD5k02RKi_y6HV6.i7lc65_MGJIHM-1709516935718-0.0.1.1-604800000; path=/; domain=.gitlab.com; HttpOnly; Secure; SameSite=None +Content-Type: application/json Vary: Origin, Accept-Encoding -Ratelimit-Remaining: 1979 -X-Runtime: 0.155712 +Gitlab-Sv: api-gke-us-east1-d Referrer-Policy: strict-origin-when-cross-origin +Gitlab-Lb: haproxy-main-38-lb-gprd +Cf-Cache-Status: MISS +Etag: W/"632b3d0f41fe1650d82b84feaa7b125d" +X-Gitlab-Meta: {"correlation_id":"68a6a29f5330b299ef95868936bd1b4b","version":"1"} +X-Runtime: 0.150028 -{"id":43486906,"iid":1,"project_id":15578026,"title":"Update README.md","description":"add warning to readme","state":"merged","created_at":"2019-11-28T08:54:41.034Z","updated_at":"2019-11-28T16:02:08.377Z","merge_status":"can_be_merged","approved":true,"approvals_required":0,"approvals_left":0,"require_password_to_approve":false,"approved_by":[{"user":{"id":527793,"username":"axifive","name":"Alexey Terentyev","state":"active","locked":false,"avatar_url":"https://secure.gravatar.com/avatar/06683cd6b2e2c2ce0ab00fb80cc0729f?s=80\u0026d=identicon","web_url":"https://gitlab.com/axifive"}},{"user":{"id":4102996,"username":"zeripath","name":"zeripath","state":"active","locked":false,"avatar_url":"https://secure.gravatar.com/avatar/1ae18535c2b1aed798da090448997248?s=80\u0026d=identicon","web_url":"https://gitlab.com/zeripath"}}],"suggested_approvers":[],"approvers":[],"approver_groups":[],"user_has_approved":false,"user_can_approve":false,"approval_rules_left":[],"has_approval_rules":true,"merge_request_approvers_available":false,"multiple_approval_rules_available":false,"invalid_approvers_rules":[]} \ No newline at end of file +{"id":43486906,"iid":1,"project_id":15578026,"title":"Update README.md","description":"add warning to readme","state":"merged","created_at":"2019-11-28T08:54:41.034Z","updated_at":"2019-11-28T16:02:08.377Z","merge_status":"can_be_merged","approved":true,"approvals_required":0,"approvals_left":0,"require_password_to_approve":false,"approved_by":[{"user":{"id":527793,"username":"axifive","name":"Alexey Terentyev","state":"active","locked":false,"avatar_url":"https://secure.gravatar.com/avatar/b5eee878c9129969b55d221a823fd15e55aad8dc15d521f4170e3c93728e02b6?s=80\u0026d=identicon","web_url":"https://gitlab.com/axifive"}},{"user":{"id":4102996,"username":"zeripath","name":"zeripath","state":"active","locked":false,"avatar_url":"https://secure.gravatar.com/avatar/3bad2cdad37aa0bbb3ad276ce8f77e32a1a9567a7083f0866d8df8ed0e92e5b5?s=80\u0026d=identicon","web_url":"https://gitlab.com/zeripath"}}],"suggested_approvers":[],"approvers":[],"approver_groups":[],"user_has_approved":false,"user_can_approve":false,"approval_rules_left":[],"has_approval_rules":true,"merge_request_approvers_available":false,"multiple_approval_rules_available":false,"invalid_approvers_rules":[]} \ No newline at end of file diff --git a/services/migrations/testdata/gitlab/full_download/_api_v4_projects_15578026_merge_requests_2 b/services/migrations/testdata/gitlab/full_download/_api_v4_projects_15578026_merge_requests_2 index 7119342f6..73441c917 100644 --- a/services/migrations/testdata/gitlab/full_download/_api_v4_projects_15578026_merge_requests_2 +++ b/services/migrations/testdata/gitlab/full_download/_api_v4_projects_15578026_merge_requests_2 @@ -1,22 +1,17 @@ -Etag: W/"914149155d75f8d8f7ed2e5351f0fadb" -X-Runtime: 0.234286 -Ratelimit-Remaining: 1983 -Strict-Transport-Security: max-age=31536000 -Referrer-Policy: strict-origin-when-cross-origin -Gitlab-Sv: localhost -Set-Cookie: _cfuvid=aYLZ68TRL8gsnraUk.zZIxRvuv981nIhZNIO9vVpgbU-1701333890175-0-604800000; path=/; domain=.gitlab.com; HttpOnly; Secure; SameSite=None X-Content-Type-Options: nosniff +X-Gitlab-Meta: {"correlation_id":"d351bb99dc07c885c71d8f5299208320","version":"1"} +Gitlab-Lb: haproxy-main-56-lb-gprd X-Frame-Options: SAMEORIGIN -Ratelimit-Observed: 17 Content-Type: application/json +Referrer-Policy: strict-origin-when-cross-origin +X-Runtime: 0.237643 +Strict-Transport-Security: max-age=31536000 +Gitlab-Sv: api-gke-us-east1-d Cache-Control: max-age=0, private, must-revalidate -Ratelimit-Resettime: Thu, 30 Nov 2023 08:45:50 GMT -Ratelimit-Limit: 2000 -Vary: Origin, Accept-Encoding Content-Security-Policy: default-src 'none' -Gitlab-Lb: haproxy-main-33-lb-gprd +Etag: W/"914149155d75f8d8f7ed2e5351f0fadb" +Vary: Origin, Accept-Encoding Cf-Cache-Status: MISS -Ratelimit-Reset: 1701333950 -X-Gitlab-Meta: {"correlation_id":"10d576ab8e82b745b7202a6daec3c5e1","version":"1"} +Set-Cookie: _cfuvid=yE9p3NWSIseWCeQl9amdJ0bfdfTyf7TIEOGJSzjcxTQ-1709516933254-0.0.1.1-604800000; path=/; domain=.gitlab.com; HttpOnly; Secure; SameSite=None {"id":43524600,"iid":2,"project_id":15578026,"title":"Test branch","description":"do not merge this PR","state":"opened","created_at":"2019-11-28T15:56:54.104Z","updated_at":"2020-04-19T19:24:21.108Z","merged_by":null,"merge_user":null,"merged_at":null,"closed_by":null,"closed_at":null,"target_branch":"master","source_branch":"feat/test","user_notes_count":0,"upvotes":1,"downvotes":0,"author":{"id":1241334,"username":"lafriks","name":"Lauris BH","state":"active","locked":false,"avatar_url":"https://gitlab.com/uploads/-/system/user/avatar/1241334/avatar.png","web_url":"https://gitlab.com/lafriks"},"assignees":[],"assignee":null,"reviewers":[],"source_project_id":15578026,"target_project_id":15578026,"labels":["bug"],"draft":false,"work_in_progress":false,"milestone":{"id":1082926,"iid":1,"project_id":15578026,"title":"1.0.0","description":"","state":"closed","created_at":"2019-11-28T08:42:30.301Z","updated_at":"2019-11-28T15:57:52.401Z","due_date":null,"start_date":null,"expired":false,"web_url":"https://gitlab.com/gitea/test_repo/-/milestones/1"},"merge_when_pipeline_succeeds":false,"merge_status":"can_be_merged","detailed_merge_status":"mergeable","sha":"9f733b96b98a4175276edf6a2e1231489c3bdd23","merge_commit_sha":null,"squash_commit_sha":null,"discussion_locked":null,"should_remove_source_branch":null,"force_remove_source_branch":true,"prepared_at":"2019-11-28T15:56:54.104Z","reference":"!2","references":{"short":"!2","relative":"!2","full":"gitea/test_repo!2"},"web_url":"https://gitlab.com/gitea/test_repo/-/merge_requests/2","time_stats":{"time_estimate":0,"total_time_spent":0,"human_time_estimate":null,"human_total_time_spent":null},"squash":true,"squash_on_merge":true,"task_completion_status":{"count":0,"completed_count":0},"has_conflicts":false,"blocking_discussions_resolved":true,"approvals_before_merge":null,"subscribed":false,"changes_count":"1","latest_build_started_at":null,"latest_build_finished_at":null,"first_deployed_to_production_at":null,"pipeline":null,"head_pipeline":null,"diff_refs":{"base_sha":"c59c9b451acca9d106cc19d61d87afe3fbbb8b83","head_sha":"9f733b96b98a4175276edf6a2e1231489c3bdd23","start_sha":"c59c9b451acca9d106cc19d61d87afe3fbbb8b83"},"merge_error":null,"first_contribution":false,"user":{"can_merge":false}} \ No newline at end of file diff --git a/services/migrations/testdata/gitlab/full_download/_api_v4_projects_15578026_merge_requests_2_approvals b/services/migrations/testdata/gitlab/full_download/_api_v4_projects_15578026_merge_requests_2_approvals index 02a1deae2..e9e5f3ad0 100644 --- a/services/migrations/testdata/gitlab/full_download/_api_v4_projects_15578026_merge_requests_2_approvals +++ b/services/migrations/testdata/gitlab/full_download/_api_v4_projects_15578026_merge_requests_2_approvals @@ -1,22 +1,17 @@ -Vary: Origin, Accept-Encoding -Ratelimit-Remaining: 1978 -Gitlab-Lb: haproxy-main-04-lb-gprd -Set-Cookie: _cfuvid=cKUtcpJODQwk9SDRn91k1DY8CY5Tg238DXGgT0a2go0-1701333891493-0-604800000; path=/; domain=.gitlab.com; HttpOnly; Secure; SameSite=None +Gitlab-Sv: api-gke-us-east1-c Content-Type: application/json -Cf-Cache-Status: MISS -Etag: W/"ce2f774c1b05c5c8a14ec9274444cba3" -Ratelimit-Limit: 2000 +Vary: Origin, Accept-Encoding +Gitlab-Lb: haproxy-main-49-lb-gprd +X-Gitlab-Meta: {"correlation_id":"ea044fc89155ed7f76093b9cc3a7d4ea","version":"1"} +X-Runtime: 0.144068 +Strict-Transport-Security: max-age=31536000 +Etag: W/"58109b687618e6b9e49ff812d5a911df" X-Content-Type-Options: nosniff Cache-Control: max-age=0, private, must-revalidate -X-Gitlab-Meta: {"correlation_id":"98ee1da556bdb3d764679ebab9ab5312","version":"1"} -Referrer-Policy: strict-origin-when-cross-origin X-Frame-Options: SAMEORIGIN -Gitlab-Sv: localhost +Set-Cookie: _cfuvid=bjDdu13341ZREKL1340bXPm8TFCQkeafZBecRxoqNv0-1709516936936-0.0.1.1-604800000; path=/; domain=.gitlab.com; HttpOnly; Secure; SameSite=None +Cf-Cache-Status: MISS Content-Security-Policy: default-src 'none' -X-Runtime: 0.165471 -Strict-Transport-Security: max-age=31536000 -Ratelimit-Observed: 22 -Ratelimit-Reset: 1701333951 -Ratelimit-Resettime: Thu, 30 Nov 2023 08:45:51 GMT +Referrer-Policy: strict-origin-when-cross-origin -{"id":43524600,"iid":2,"project_id":15578026,"title":"Test branch","description":"do not merge this PR","state":"opened","created_at":"2019-11-28T15:56:54.104Z","updated_at":"2020-04-19T19:24:21.108Z","merge_status":"can_be_merged","approved":true,"approvals_required":0,"approvals_left":0,"require_password_to_approve":false,"approved_by":[{"user":{"id":4575606,"username":"real6543","name":"6543","state":"active","locked":false,"avatar_url":"https://gitlab.com/uploads/-/system/user/avatar/4575606/avatar.png","web_url":"https://gitlab.com/real6543"}}],"suggested_approvers":[],"approvers":[],"approver_groups":[{"group":{"id":3181312,"web_url":"https://gitlab.com/groups/gitea","name":"gitea","path":"gitea","description":"Mirror of Gitea source code repositories","visibility":"public","share_with_group_lock":false,"require_two_factor_authentication":false,"two_factor_grace_period":48,"project_creation_level":"maintainer","auto_devops_enabled":null,"subgroup_creation_level":"owner","emails_disabled":false,"emails_enabled":true,"mentions_disabled":null,"lfs_enabled":true,"default_branch_protection":2,"default_branch_protection_defaults":{"allowed_to_push":[{"access_level":30}],"allow_force_push":true,"allowed_to_merge":[{"access_level":30}]},"avatar_url":"https://gitlab.com/uploads/-/system/group/avatar/3181312/gitea.png","request_access_enabled":true,"full_name":"gitea","full_path":"gitea","created_at":"2018-07-04T16:32:10.176Z","parent_id":null,"shared_runners_setting":"enabled","ldap_cn":null,"ldap_access":null,"wiki_access_level":"enabled"}}],"user_has_approved":false,"user_can_approve":false,"approval_rules_left":[],"has_approval_rules":true,"merge_request_approvers_available":false,"multiple_approval_rules_available":false,"invalid_approvers_rules":[]} \ No newline at end of file +{"id":43524600,"iid":2,"project_id":15578026,"title":"Test branch","description":"do not merge this PR","state":"opened","created_at":"2019-11-28T15:56:54.104Z","updated_at":"2020-04-19T19:24:21.108Z","merge_status":"can_be_merged","approved":true,"approvals_required":0,"approvals_left":0,"require_password_to_approve":false,"approved_by":[{"user":{"id":4575606,"username":"real6543","name":"6543","state":"active","locked":false,"avatar_url":"https://gitlab.com/uploads/-/system/user/avatar/4575606/avatar.png","web_url":"https://gitlab.com/real6543"}}],"suggested_approvers":[],"approvers":[],"approver_groups":[{"group":{"id":3181312,"web_url":"https://gitlab.com/groups/gitea","name":"gitea","path":"gitea","description":"Mirror of Gitea source code repositories","visibility":"public","share_with_group_lock":false,"require_two_factor_authentication":false,"two_factor_grace_period":48,"project_creation_level":"maintainer","auto_devops_enabled":null,"subgroup_creation_level":"owner","emails_disabled":false,"emails_enabled":true,"mentions_disabled":null,"lfs_enabled":true,"math_rendering_limits_enabled":true,"lock_math_rendering_limits_enabled":false,"default_branch_protection":2,"default_branch_protection_defaults":{"allowed_to_push":[{"access_level":30}],"allow_force_push":true,"allowed_to_merge":[{"access_level":30}]},"avatar_url":"https://gitlab.com/uploads/-/system/group/avatar/3181312/gitea.png","request_access_enabled":true,"full_name":"gitea","full_path":"gitea","created_at":"2018-07-04T16:32:10.176Z","parent_id":null,"organization_id":1,"shared_runners_setting":"enabled","ldap_cn":null,"ldap_access":null,"wiki_access_level":"enabled"}}],"user_has_approved":false,"user_can_approve":false,"approval_rules_left":[],"has_approval_rules":true,"merge_request_approvers_available":false,"multiple_approval_rules_available":false,"invalid_approvers_rules":[]} \ No newline at end of file diff --git a/services/migrations/testdata/gitlab/full_download/_api_v4_projects_15578026_merge_requests_2_award_emoji!page=1&per_page=1 b/services/migrations/testdata/gitlab/full_download/_api_v4_projects_15578026_merge_requests_2_award_emoji!page=1&per_page=1 index aab7a74df..3d99cfbe2 100644 --- a/services/migrations/testdata/gitlab/full_download/_api_v4_projects_15578026_merge_requests_2_award_emoji!page=1&per_page=1 +++ b/services/migrations/testdata/gitlab/full_download/_api_v4_projects_15578026_merge_requests_2_award_emoji!page=1&per_page=1 @@ -1,29 +1,24 @@ -X-Prev-Page: -X-Runtime: 0.066211 -Strict-Transport-Security: max-age=31536000 -Content-Security-Policy: default-src 'none' -X-Per-Page: 1 -X-Total: 2 -Ratelimit-Reset: 1701333950 -Ratelimit-Limit: 2000 -Cf-Cache-Status: MISS -X-Content-Type-Options: nosniff -X-Gitlab-Meta: {"correlation_id":"d0f8c843558e938161d7307b686f1cd9","version":"1"} -Gitlab-Sv: localhost -Set-Cookie: _cfuvid=WFMplweUX3zWl6uoteYRHeDcpElbTNYhWrIBbNEVC3A-1701333890399-0-604800000; path=/; domain=.gitlab.com; HttpOnly; Secure; SameSite=None -Content-Type: application/json -X-Total-Pages: 2 +Set-Cookie: _cfuvid=2_c1M0pqgnG1D4bNm2QluJ9AGXZ7FyB14t_v4ittTjY-1709516933765-0.0.1.1-604800000; path=/; domain=.gitlab.com; HttpOnly; Secure; SameSite=None Etag: W/"798718b23a2ec66b16cce20cb7155116" -X-Next-Page: 2 -Link: ; rel="next", ; rel="first", ; rel="last" -Vary: Origin, Accept-Encoding -Ratelimit-Observed: 18 -Ratelimit-Resettime: Thu, 30 Nov 2023 08:45:50 GMT -X-Frame-Options: SAMEORIGIN -Referrer-Policy: strict-origin-when-cross-origin -Ratelimit-Remaining: 1982 -Gitlab-Lb: haproxy-main-31-lb-gprd +X-Runtime: 0.125829 +X-Total-Pages: 2 +Gitlab-Sv: api-gke-us-east1-b +Cf-Cache-Status: MISS +X-Prev-Page: Cache-Control: max-age=0, private, must-revalidate +Link: ; rel="next", ; rel="first", ; rel="last" +Content-Type: application/json +X-Content-Type-Options: nosniff +X-Gitlab-Meta: {"correlation_id":"9d8976ef2244076825f1e8a8bae3a090","version":"1"} +Vary: Origin, Accept-Encoding +Strict-Transport-Security: max-age=31536000 +X-Total: 2 +X-Frame-Options: SAMEORIGIN +X-Next-Page: 2 X-Page: 1 +X-Per-Page: 1 +Content-Security-Policy: default-src 'none' +Referrer-Policy: strict-origin-when-cross-origin +Gitlab-Lb: haproxy-main-45-lb-gprd [{"id":5541414,"name":"thumbsup","user":{"id":4575606,"username":"real6543","name":"6543","state":"active","locked":false,"avatar_url":"https://gitlab.com/uploads/-/system/user/avatar/4575606/avatar.png","web_url":"https://gitlab.com/real6543"},"created_at":"2020-09-02T23:42:34.310Z","updated_at":"2020-09-02T23:42:34.310Z","awardable_id":43524600,"awardable_type":"MergeRequest","url":null}] \ No newline at end of file diff --git a/services/migrations/testdata/gitlab/full_download/_api_v4_projects_15578026_merge_requests_2_award_emoji!page=2&per_page=1 b/services/migrations/testdata/gitlab/full_download/_api_v4_projects_15578026_merge_requests_2_award_emoji!page=2&per_page=1 index 5d85a567e..9981fc1c3 100644 --- a/services/migrations/testdata/gitlab/full_download/_api_v4_projects_15578026_merge_requests_2_award_emoji!page=2&per_page=1 +++ b/services/migrations/testdata/gitlab/full_download/_api_v4_projects_15578026_merge_requests_2_award_emoji!page=2&per_page=1 @@ -1,29 +1,24 @@ -Cf-Cache-Status: MISS -Etag: W/"e6776aaa57e6a81bf8a2d8823272cc70" -X-Frame-Options: SAMEORIGIN -X-Gitlab-Meta: {"correlation_id":"db01aae11b0cf7febcf051706159faae","version":"1"} -X-Total-Pages: 2 -Strict-Transport-Security: max-age=31536000 -Gitlab-Lb: haproxy-main-51-lb-gprd -X-Total: 2 -Referrer-Policy: strict-origin-when-cross-origin -Ratelimit-Limit: 2000 -Cache-Control: max-age=0, private, must-revalidate -X-Next-Page: -Set-Cookie: _cfuvid=X0n26HdiufQTXsshb4pvCyuf0jDSstPZ8GnIiyx57YU-1701333890628-0-604800000; path=/; domain=.gitlab.com; HttpOnly; Secure; SameSite=None -Link: ; rel="prev", ; rel="first", ; rel="last" -Ratelimit-Observed: 19 -Ratelimit-Reset: 1701333950 -Content-Type: application/json -Vary: Origin, Accept-Encoding -X-Per-Page: 1 -X-Runtime: 0.067511 -Gitlab-Sv: localhost -X-Prev-Page: 1 -Ratelimit-Remaining: 1981 -Ratelimit-Resettime: Thu, 30 Nov 2023 08:45:50 GMT -Content-Security-Policy: default-src 'none' X-Content-Type-Options: nosniff +Gitlab-Lb: haproxy-main-32-lb-gprd +Cache-Control: max-age=0, private, must-revalidate +Etag: W/"e6776aaa57e6a81bf8a2d8823272cc70" +X-Prev-Page: 1 +X-Runtime: 0.066771 +Referrer-Policy: strict-origin-when-cross-origin +Content-Security-Policy: default-src 'none' +Vary: Origin, Accept-Encoding +X-Frame-Options: SAMEORIGIN +X-Next-Page: +X-Per-Page: 1 +Set-Cookie: _cfuvid=XlmPD5BVPxHofXNdPbazM3JF2i5DbLlQUVqNW9K6Y28-1709516934208-0.0.1.1-604800000; path=/; domain=.gitlab.com; HttpOnly; Secure; SameSite=None +X-Gitlab-Meta: {"correlation_id":"e51679dffc5216e7c77a018a26343380","version":"1"} +X-Total: 2 +X-Total-Pages: 2 +Content-Type: application/json X-Page: 2 +Strict-Transport-Security: max-age=31536000 +Cf-Cache-Status: MISS +Link: ; rel="prev", ; rel="first", ; rel="last" +Gitlab-Sv: api-gke-us-east1-d [{"id":5541415,"name":"tada","user":{"id":4575606,"username":"real6543","name":"6543","state":"active","locked":false,"avatar_url":"https://gitlab.com/uploads/-/system/user/avatar/4575606/avatar.png","web_url":"https://gitlab.com/real6543"},"created_at":"2020-09-02T23:42:59.060Z","updated_at":"2020-09-02T23:42:59.060Z","awardable_id":43524600,"awardable_type":"MergeRequest","url":null}] \ No newline at end of file diff --git a/services/migrations/testdata/gitlab/full_download/_api_v4_projects_15578026_merge_requests_2_award_emoji!page=3&per_page=1 b/services/migrations/testdata/gitlab/full_download/_api_v4_projects_15578026_merge_requests_2_award_emoji!page=3&per_page=1 index aa5a50e45..07ff6e5ba 100644 --- a/services/migrations/testdata/gitlab/full_download/_api_v4_projects_15578026_merge_requests_2_award_emoji!page=3&per_page=1 +++ b/services/migrations/testdata/gitlab/full_download/_api_v4_projects_15578026_merge_requests_2_award_emoji!page=3&per_page=1 @@ -1,31 +1,26 @@ -X-Page: 3 -Strict-Transport-Security: max-age=31536000 -Accept-Ranges: bytes -Set-Cookie: _cfuvid=CBSpRhUuajZbJ9Mc_r7SkVmZawoSi5ofuts2TGyHgRk-1701333890842-0-604800000; path=/; domain=.gitlab.com; HttpOnly; Secure; SameSite=None -Cache-Control: max-age=0, private, must-revalidate -X-Prev-Page: -X-Total-Pages: 2 -Ratelimit-Reset: 1701333950 -Gitlab-Sv: localhost X-Content-Type-Options: nosniff -Ratelimit-Resettime: Thu, 30 Nov 2023 08:45:50 GMT -Gitlab-Lb: haproxy-main-05-lb-gprd -Etag: W/"4f53cda18c2baa0c0354bb5f9a3ecbe5" -Vary: Origin, Accept-Encoding -X-Frame-Options: SAMEORIGIN -X-Gitlab-Meta: {"correlation_id":"36817edd7cae21d5d6b875faf173ce80","version":"1"} -X-Per-Page: 1 -X-Total: 2 -Referrer-Policy: strict-origin-when-cross-origin -Content-Security-Policy: default-src 'none' -Link: ; rel="first", ; rel="last" +X-Prev-Page: +Accept-Ranges: bytes +Gitlab-Sv: api-gke-us-east1-d +X-Gitlab-Meta: {"correlation_id":"e19c4433df21888b10c912bab5311ecd","version":"1"} X-Next-Page: -X-Runtime: 0.061075 -Ratelimit-Limit: 2000 -Ratelimit-Observed: 20 +Strict-Transport-Security: max-age=31536000 +Gitlab-Lb: haproxy-main-26-lb-gprd +Etag: W/"4f53cda18c2baa0c0354bb5f9a3ecbe5" +Link: ; rel="first", ; rel="last" +X-Per-Page: 1 +Set-Cookie: _cfuvid=Lv9tmhZRx2Sa.lToTQ.C73MDyRvwOtmVmgEi4cbTrkQ-1709516935278-0.0.1.1-604800000; path=/; domain=.gitlab.com; HttpOnly; Secure; SameSite=None +X-Total-Pages: 2 Cf-Cache-Status: MISS -Content-Type: application/json Content-Length: 2 -Ratelimit-Remaining: 1980 +X-Page: 3 +X-Total: 2 +X-Frame-Options: SAMEORIGIN +Referrer-Policy: strict-origin-when-cross-origin +Content-Type: application/json +Cache-Control: max-age=0, private, must-revalidate +Vary: Origin, Accept-Encoding +X-Runtime: 0.056300 +Content-Security-Policy: default-src 'none' [] \ No newline at end of file diff --git a/services/migrations/testdata/gitlab/full_download/_api_v4_projects_15578026_milestones!page=1&per_page=100&state=all b/services/migrations/testdata/gitlab/full_download/_api_v4_projects_15578026_milestones!page=1&per_page=100&state=all index 78310e123..14a40dc50 100644 --- a/services/migrations/testdata/gitlab/full_download/_api_v4_projects_15578026_milestones!page=1&per_page=100&state=all +++ b/services/migrations/testdata/gitlab/full_download/_api_v4_projects_15578026_milestones!page=1&per_page=100&state=all @@ -1,29 +1,24 @@ -X-Content-Type-Options: nosniff -X-Next-Page: -Ratelimit-Observed: 5 -X-Frame-Options: SAMEORIGIN -X-Per-Page: 100 -Ratelimit-Limit: 2000 -Cf-Cache-Status: MISS -Strict-Transport-Security: max-age=31536000 -Referrer-Policy: strict-origin-when-cross-origin -Ratelimit-Resettime: Thu, 30 Nov 2023 08:45:46 GMT -Content-Security-Policy: default-src 'none' -Link: ; rel="first", ; rel="last" -X-Gitlab-Meta: {"correlation_id":"4f72373995f8681ce127c62d384745a3","version":"1"} -Gitlab-Sv: localhost -X-Runtime: 0.073691 -Ratelimit-Remaining: 1995 -Ratelimit-Reset: 1701333946 -Content-Type: application/json -Etag: W/"c8e2d3a5f05ee29c58b665c86684f9f9" -X-Page: 1 -Gitlab-Lb: haproxy-main-47-lb-gprd -Vary: Origin, Accept-Encoding -X-Prev-Page: X-Total: 2 -Cache-Control: max-age=0, private, must-revalidate +Referrer-Policy: strict-origin-when-cross-origin +Gitlab-Sv: api-gke-us-east1-d +X-Content-Type-Options: nosniff +X-Frame-Options: SAMEORIGIN +X-Next-Page: X-Total-Pages: 1 -Set-Cookie: _cfuvid=ZfjvK5rh2nTUjEDt1Guwzd8zrl6uCDplfE8NBPbdJ7c-1701333886832-0-604800000; path=/; domain=.gitlab.com; HttpOnly; Secure; SameSite=None +Cf-Cache-Status: MISS +Content-Type: application/json +Cache-Control: max-age=0, private, must-revalidate +Link: ; rel="first", ; rel="last" +Gitlab-Lb: haproxy-main-02-lb-gprd +Vary: Origin, Accept-Encoding +X-Per-Page: 100 +X-Runtime: 0.072314 +Strict-Transport-Security: max-age=31536000 +Set-Cookie: _cfuvid=AAzb4a45dTRraCeBWB2eYtD0LUdZnyMdcLZpKLKFKQY-1709516922946-0.0.1.1-604800000; path=/; domain=.gitlab.com; HttpOnly; Secure; SameSite=None +X-Page: 1 +Content-Security-Policy: default-src 'none' +Etag: W/"c8e2d3a5f05ee29c58b665c86684f9f9" +X-Gitlab-Meta: {"correlation_id":"3786d93aa260a78e86bd229427022c67","version":"1"} +X-Prev-Page: [{"id":1082927,"iid":2,"project_id":15578026,"title":"1.1.0","description":"","state":"active","created_at":"2019-11-28T08:42:44.575Z","updated_at":"2019-11-28T08:42:44.575Z","due_date":null,"start_date":null,"expired":false,"web_url":"https://gitlab.com/gitea/test_repo/-/milestones/2"},{"id":1082926,"iid":1,"project_id":15578026,"title":"1.0.0","description":"","state":"closed","created_at":"2019-11-28T08:42:30.301Z","updated_at":"2019-11-28T15:57:52.401Z","due_date":null,"start_date":null,"expired":false,"web_url":"https://gitlab.com/gitea/test_repo/-/milestones/1"}] \ No newline at end of file diff --git a/services/migrations/testdata/gitlab/full_download/_api_v4_projects_15578026_releases!page=1&per_page=100 b/services/migrations/testdata/gitlab/full_download/_api_v4_projects_15578026_releases!page=1&per_page=100 index 9be0b7472..5e0f064cd 100644 --- a/services/migrations/testdata/gitlab/full_download/_api_v4_projects_15578026_releases!page=1&per_page=100 +++ b/services/migrations/testdata/gitlab/full_download/_api_v4_projects_15578026_releases!page=1&per_page=100 @@ -1,29 +1,24 @@ -Strict-Transport-Security: max-age=31536000 -Referrer-Policy: strict-origin-when-cross-origin -Ratelimit-Reset: 1701333947 -X-Total: 1 -Ratelimit-Resettime: Thu, 30 Nov 2023 08:45:47 GMT -Ratelimit-Limit: 2000 -X-Runtime: 0.178411 -Gitlab-Lb: haproxy-main-15-lb-gprd -Vary: Origin, Accept-Encoding -X-Page: 1 -X-Frame-Options: SAMEORIGIN -Ratelimit-Observed: 7 -Cf-Cache-Status: MISS -Etag: W/"dccc7159dc4b46989d13128a7d6ee859" -X-Content-Type-Options: nosniff -Ratelimit-Remaining: 1993 -X-Gitlab-Meta: {"correlation_id":"0044a3de3ede2f913cabe6e464dd73c2","version":"1"} +Gitlab-Lb: haproxy-main-38-lb-gprd +X-Gitlab-Meta: {"correlation_id":"fe487506ab79b2641f2798820a003e65","version":"1"} +X-Runtime: 0.126232 X-Total-Pages: 1 -X-Next-Page: +X-Prev-Page: +Cache-Control: max-age=0, private, must-revalidate +Link: ; rel="first", ; rel="last" +X-Page: 1 X-Per-Page: 100 Content-Type: application/json +Vary: Origin, Accept-Encoding +X-Frame-Options: SAMEORIGIN +X-Next-Page: +Gitlab-Sv: api-gke-us-east1-d +X-Content-Type-Options: nosniff +Referrer-Policy: strict-origin-when-cross-origin +Cf-Cache-Status: MISS +Strict-Transport-Security: max-age=31536000 +Set-Cookie: _cfuvid=2dextQvrlcispQRNmodfvb.IH__P1bCF5jvS5aFrRjY-1709516924499-0.0.1.1-604800000; path=/; domain=.gitlab.com; HttpOnly; Secure; SameSite=None +Etag: W/"dccc7159dc4b46989d13128a7d6ee859" Content-Security-Policy: default-src 'none' -Set-Cookie: _cfuvid=h1ayMNs6W_kFPoFe28IpiaFUz1ZAPvY6npUWxARRx4I-1701333887452-0-604800000; path=/; domain=.gitlab.com; HttpOnly; Secure; SameSite=None -Link: ; rel="first", ; rel="last" -Gitlab-Sv: localhost -Cache-Control: max-age=0, private, must-revalidate -X-Prev-Page: +X-Total: 1 [{"name":"First Release","tag_name":"v0.9.99","description":"A test release","created_at":"2019-11-28T09:09:48.840Z","released_at":"2019-11-28T09:09:48.836Z","upcoming_release":false,"author":{"id":1241334,"username":"lafriks","name":"Lauris BH","state":"active","locked":false,"avatar_url":"https://gitlab.com/uploads/-/system/user/avatar/1241334/avatar.png","web_url":"https://gitlab.com/lafriks"},"commit":{"id":"0720a3ec57c1f843568298117b874319e7deee75","short_id":"0720a3ec","created_at":"2019-11-28T08:49:16.000+00:00","parent_ids":["93ea21ce45d35690c35e80961d239645139e872c"],"title":"Add new file","message":"Add new file","author_name":"Lauris BH","author_email":"lauris@nix.lv","authored_date":"2019-11-28T08:49:16.000+00:00","committer_name":"Lauris BH","committer_email":"lauris@nix.lv","committed_date":"2019-11-28T08:49:16.000+00:00","trailers":{},"extended_trailers":{},"web_url":"https://gitlab.com/gitea/test_repo/-/commit/0720a3ec57c1f843568298117b874319e7deee75"},"commit_path":"/gitea/test_repo/-/commit/0720a3ec57c1f843568298117b874319e7deee75","tag_path":"/gitea/test_repo/-/tags/v0.9.99","assets":{"count":4,"sources":[{"format":"zip","url":"https://gitlab.com/gitea/test_repo/-/archive/v0.9.99/test_repo-v0.9.99.zip"},{"format":"tar.gz","url":"https://gitlab.com/gitea/test_repo/-/archive/v0.9.99/test_repo-v0.9.99.tar.gz"},{"format":"tar.bz2","url":"https://gitlab.com/gitea/test_repo/-/archive/v0.9.99/test_repo-v0.9.99.tar.bz2"},{"format":"tar","url":"https://gitlab.com/gitea/test_repo/-/archive/v0.9.99/test_repo-v0.9.99.tar"}],"links":[]},"evidences":[{"sha":"89f1223473ee01f192a83d0cb89f4d1eac1de74f01ad","filepath":"https://gitlab.com/gitea/test_repo/-/releases/v0.9.99/evidences/52147.json","collected_at":"2019-11-28T09:09:48.888Z"}],"_links":{"closed_issues_url":"https://gitlab.com/gitea/test_repo/-/issues?release_tag=v0.9.99\u0026scope=all\u0026state=closed","closed_merge_requests_url":"https://gitlab.com/gitea/test_repo/-/merge_requests?release_tag=v0.9.99\u0026scope=all\u0026state=closed","merged_merge_requests_url":"https://gitlab.com/gitea/test_repo/-/merge_requests?release_tag=v0.9.99\u0026scope=all\u0026state=merged","opened_issues_url":"https://gitlab.com/gitea/test_repo/-/issues?release_tag=v0.9.99\u0026scope=all\u0026state=opened","opened_merge_requests_url":"https://gitlab.com/gitea/test_repo/-/merge_requests?release_tag=v0.9.99\u0026scope=all\u0026state=opened","self":"https://gitlab.com/gitea/test_repo/-/releases/v0.9.99"}}] \ No newline at end of file diff --git a/services/migrations/testdata/gitlab/full_download/_api_v4_projects_gitea%2Ftest_repo b/services/migrations/testdata/gitlab/full_download/_api_v4_projects_gitea%2Ftest_repo index 07fed52a8..490eebe79 100644 --- a/services/migrations/testdata/gitlab/full_download/_api_v4_projects_gitea%2Ftest_repo +++ b/services/migrations/testdata/gitlab/full_download/_api_v4_projects_gitea%2Ftest_repo @@ -1,22 +1,17 @@ -Content-Security-Policy: default-src 'none' -Vary: Origin, Accept-Encoding -Referrer-Policy: strict-origin-when-cross-origin -Gitlab-Sv: localhost -X-Content-Type-Options: nosniff -Ratelimit-Reset: 1701333946 -Ratelimit-Resettime: Thu, 30 Nov 2023 08:45:46 GMT -X-Runtime: 0.144599 -Content-Type: application/json -X-Gitlab-Meta: {"correlation_id":"919887b868b11ed34c5917e98b4be40d","version":"1"} -Ratelimit-Observed: 2 -Gitlab-Lb: haproxy-main-42-lb-gprd -Strict-Transport-Security: max-age=31536000 -Cf-Cache-Status: MISS -Ratelimit-Limit: 2000 -Set-Cookie: _cfuvid=BENIrMVlxs_tt.JplEkDKbUrMpOF_kjRRLJOifNTLqY-1701333886061-0-604800000; path=/; domain=.gitlab.com; HttpOnly; Secure; SameSite=None -Etag: W/"3cacfe29f44a69e84a577337eac55d89" X-Frame-Options: SAMEORIGIN +X-Gitlab-Meta: {"correlation_id":"d08798c744b97af051e81bc1f6fecabe","version":"1"} +Cf-Cache-Status: MISS +Vary: Origin, Accept-Encoding +X-Runtime: 0.282076 +Gitlab-Lb: haproxy-main-43-lb-gprd +Etag: W/"8db4917b3be5f4ca0d101a702179b75a" +Referrer-Policy: strict-origin-when-cross-origin +Set-Cookie: _cfuvid=q8qrvxAlkuGzqRsYQXzKrbLTHH6CWOF_x.icF64i9VQ-1709516921514-0.0.1.1-604800000; path=/; domain=.gitlab.com; HttpOnly; Secure; SameSite=None +Content-Security-Policy: default-src 'none' Cache-Control: max-age=0, private, must-revalidate -Ratelimit-Remaining: 1998 +X-Content-Type-Options: nosniff +Strict-Transport-Security: max-age=31536000 +Gitlab-Sv: api-gke-us-east1-c +Content-Type: application/json -{"id":15578026,"description":"Test repository for testing migration from gitlab to gitea","name":"test_repo","name_with_namespace":"gitea / test_repo","path":"test_repo","path_with_namespace":"gitea/test_repo","created_at":"2019-11-28T08:20:33.019Z","default_branch":"master","tag_list":["migration","test"],"topics":["migration","test"],"ssh_url_to_repo":"git@gitlab.com:gitea/test_repo.git","http_url_to_repo":"https://gitlab.com/gitea/test_repo.git","web_url":"https://gitlab.com/gitea/test_repo","readme_url":"https://gitlab.com/gitea/test_repo/-/blob/master/README.md","forks_count":1,"avatar_url":null,"star_count":0,"last_activity_at":"2020-04-19T19:46:04.527Z","namespace":{"id":3181312,"name":"gitea","path":"gitea","kind":"group","full_path":"gitea","parent_id":null,"avatar_url":"/uploads/-/system/group/avatar/3181312/gitea.png","web_url":"https://gitlab.com/groups/gitea"},"container_registry_image_prefix":"registry.gitlab.com/gitea/test_repo","_links":{"self":"https://gitlab.com/api/v4/projects/15578026","issues":"https://gitlab.com/api/v4/projects/15578026/issues","merge_requests":"https://gitlab.com/api/v4/projects/15578026/merge_requests","repo_branches":"https://gitlab.com/api/v4/projects/15578026/repository/branches","labels":"https://gitlab.com/api/v4/projects/15578026/labels","events":"https://gitlab.com/api/v4/projects/15578026/events","members":"https://gitlab.com/api/v4/projects/15578026/members","cluster_agents":"https://gitlab.com/api/v4/projects/15578026/cluster_agents"},"packages_enabled":true,"empty_repo":false,"archived":false,"visibility":"public","resolve_outdated_diff_discussions":false,"issues_enabled":true,"merge_requests_enabled":true,"wiki_enabled":true,"jobs_enabled":true,"snippets_enabled":true,"container_registry_enabled":true,"service_desk_enabled":true,"can_create_merge_request_in":true,"issues_access_level":"enabled","repository_access_level":"enabled","merge_requests_access_level":"enabled","forking_access_level":"enabled","wiki_access_level":"enabled","builds_access_level":"enabled","snippets_access_level":"enabled","pages_access_level":"enabled","analytics_access_level":"enabled","container_registry_access_level":"enabled","security_and_compliance_access_level":"private","releases_access_level":"enabled","environments_access_level":"enabled","feature_flags_access_level":"enabled","infrastructure_access_level":"enabled","monitor_access_level":"enabled","model_experiments_access_level":"enabled","emails_disabled":false,"emails_enabled":true,"shared_runners_enabled":true,"lfs_enabled":true,"creator_id":1241334,"import_status":"none","open_issues_count":0,"description_html":"\u003cp data-sourcepos=\"1:1-1:58\" dir=\"auto\"\u003eTest repository for testing migration from gitlab to gitea\u003c/p\u003e","updated_at":"2022-08-26T19:41:46.691Z","ci_config_path":null,"public_jobs":true,"shared_with_groups":[],"only_allow_merge_if_pipeline_succeeds":false,"allow_merge_on_skipped_pipeline":null,"request_access_enabled":true,"only_allow_merge_if_all_discussions_are_resolved":false,"remove_source_branch_after_merge":true,"printing_merge_request_link_enabled":true,"merge_method":"ff","squash_option":"default_off","enforce_auth_checks_on_uploads":true,"suggestion_commit_message":null,"merge_commit_template":null,"squash_commit_template":null,"issue_branch_template":null,"autoclose_referenced_issues":true,"external_authorization_classification_label":"","requirements_enabled":false,"requirements_access_level":"enabled","security_and_compliance_enabled":false,"compliance_frameworks":[],"permissions":{"project_access":null,"group_access":null}} \ No newline at end of file +{"id":15578026,"description":"Test repository for testing migration from gitlab to gitea","name":"test_repo","name_with_namespace":"gitea / test_repo","path":"test_repo","path_with_namespace":"gitea/test_repo","created_at":"2019-11-28T08:20:33.019Z","default_branch":"master","tag_list":["migration","test"],"topics":["migration","test"],"ssh_url_to_repo":"git@gitlab.com:gitea/test_repo.git","http_url_to_repo":"https://gitlab.com/gitea/test_repo.git","web_url":"https://gitlab.com/gitea/test_repo","readme_url":"https://gitlab.com/gitea/test_repo/-/blob/master/README.md","forks_count":1,"avatar_url":null,"star_count":0,"last_activity_at":"2020-04-19T19:46:04.527Z","namespace":{"id":3181312,"name":"gitea","path":"gitea","kind":"group","full_path":"gitea","parent_id":null,"avatar_url":"/uploads/-/system/group/avatar/3181312/gitea.png","web_url":"https://gitlab.com/groups/gitea"},"container_registry_image_prefix":"registry.gitlab.com/gitea/test_repo","_links":{"self":"https://gitlab.com/api/v4/projects/15578026","issues":"https://gitlab.com/api/v4/projects/15578026/issues","merge_requests":"https://gitlab.com/api/v4/projects/15578026/merge_requests","repo_branches":"https://gitlab.com/api/v4/projects/15578026/repository/branches","labels":"https://gitlab.com/api/v4/projects/15578026/labels","events":"https://gitlab.com/api/v4/projects/15578026/events","members":"https://gitlab.com/api/v4/projects/15578026/members","cluster_agents":"https://gitlab.com/api/v4/projects/15578026/cluster_agents"},"packages_enabled":true,"empty_repo":false,"archived":false,"visibility":"public","resolve_outdated_diff_discussions":false,"repository_object_format":"sha1","issues_enabled":true,"merge_requests_enabled":true,"wiki_enabled":true,"jobs_enabled":true,"snippets_enabled":true,"container_registry_enabled":true,"service_desk_enabled":true,"can_create_merge_request_in":true,"issues_access_level":"enabled","repository_access_level":"enabled","merge_requests_access_level":"enabled","forking_access_level":"enabled","wiki_access_level":"enabled","builds_access_level":"enabled","snippets_access_level":"enabled","pages_access_level":"enabled","analytics_access_level":"enabled","container_registry_access_level":"enabled","security_and_compliance_access_level":"private","releases_access_level":"enabled","environments_access_level":"enabled","feature_flags_access_level":"enabled","infrastructure_access_level":"enabled","monitor_access_level":"enabled","model_experiments_access_level":"enabled","model_registry_access_level":"enabled","emails_disabled":false,"emails_enabled":true,"shared_runners_enabled":true,"lfs_enabled":true,"creator_id":1241334,"import_status":"none","open_issues_count":0,"description_html":"\u003cp data-sourcepos=\"1:1-1:58\" dir=\"auto\"\u003eTest repository for testing migration from gitlab to gitea\u003c/p\u003e","updated_at":"2024-01-11T01:23:21.057Z","ci_config_path":null,"public_jobs":true,"shared_with_groups":[],"only_allow_merge_if_pipeline_succeeds":false,"allow_merge_on_skipped_pipeline":null,"request_access_enabled":true,"only_allow_merge_if_all_discussions_are_resolved":false,"remove_source_branch_after_merge":true,"printing_merge_request_link_enabled":true,"merge_method":"ff","squash_option":"default_off","enforce_auth_checks_on_uploads":true,"suggestion_commit_message":null,"merge_commit_template":null,"squash_commit_template":null,"issue_branch_template":null,"warn_about_potentially_unwanted_characters":true,"autoclose_referenced_issues":true,"external_authorization_classification_label":"","requirements_enabled":false,"requirements_access_level":"enabled","security_and_compliance_enabled":false,"compliance_frameworks":[],"permissions":{"project_access":null,"group_access":null}} \ No newline at end of file diff --git a/services/migrations/testdata/gitlab/full_download/_api_v4_version b/services/migrations/testdata/gitlab/full_download/_api_v4_version index 7c2cd320a..e61313f6b 100644 --- a/services/migrations/testdata/gitlab/full_download/_api_v4_version +++ b/services/migrations/testdata/gitlab/full_download/_api_v4_version @@ -1,22 +1,17 @@ -Etag: W/"4e5c0a031c3aacb6ba0a3c19e67d7592" -Ratelimit-Observed: 1 -Content-Type: application/json -Ratelimit-Remaining: 1999 -Set-Cookie: _cfuvid=qtYbzv8YeGg4q7XaV0aAE2.YqWIp_xrYPGilXrlecsk-1701333885742-0-604800000; path=/; domain=.gitlab.com; HttpOnly; Secure; SameSite=None -X-Gitlab-Meta: {"correlation_id":"c7c75f0406e1b1b9705a6d7e9bdb06a5","version":"1"} -X-Runtime: 0.039264 -Cf-Cache-Status: MISS -Content-Security-Policy: default-src 'none' -Ratelimit-Reset: 1701333945 -Gitlab-Sv: localhost -Strict-Transport-Security: max-age=31536000 -Vary: Origin, Accept-Encoding +Etag: W/"796348ca31c2f886c4bf67753358302b" X-Content-Type-Options: nosniff -Referrer-Policy: strict-origin-when-cross-origin -Ratelimit-Resettime: Thu, 30 Nov 2023 08:45:45 GMT -Gitlab-Lb: haproxy-main-23-lb-gprd +Gitlab-Lb: haproxy-main-22-lb-gprd +Set-Cookie: _cfuvid=XONUYaYMv2vYBZLhOZoclracol_W8SXVwL7kwoXROjM-1709516920902-0.0.1.1-604800000; path=/; domain=.gitlab.com; HttpOnly; Secure; SameSite=None +X-Gitlab-Meta: {"correlation_id":"0defa7748a7bd70616af6bd0f338094c","version":"1"} +Strict-Transport-Security: max-age=31536000 +Gitlab-Sv: api-gke-us-east1-c +Cf-Cache-Status: MISS +Content-Type: application/json Cache-Control: max-age=0, private, must-revalidate +Content-Security-Policy: default-src 'none' X-Frame-Options: SAMEORIGIN -Ratelimit-Limit: 2000 +X-Runtime: 0.035674 +Vary: Origin, Accept-Encoding +Referrer-Policy: strict-origin-when-cross-origin -{"version":"16.7.0-pre","revision":"acd848a9228","kas":{"enabled":true,"externalUrl":"wss://kas.gitlab.com","version":"v16.7.0-rc2"},"enterprise":true} \ No newline at end of file +{"version":"16.10.0-pre","revision":"432cc3c7389","kas":{"enabled":true,"externalUrl":"wss://kas.gitlab.com","version":"v16.10.0-rc1"},"enterprise":true} \ No newline at end of file diff --git a/services/packages/cleanup/cleanup.go b/services/packages/cleanup/cleanup.go index 0ff8077bc..5d5120c6a 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 dd3f158db..3f5f43bbc 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 56d5cc04d..64b1ddd86 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/pull.go b/services/pull/pull.go index ef6c589a2..34f3391a6 100644 --- a/services/pull/pull.go +++ b/services/pull/pull.go @@ -21,7 +21,6 @@ import ( user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/base" "code.gitea.io/gitea/modules/container" - gitea_context "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/gitrepo" "code.gitea.io/gitea/modules/graceful" @@ -31,6 +30,7 @@ import ( "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/sync" "code.gitea.io/gitea/modules/util" + gitea_context "code.gitea.io/gitea/services/context" issue_service "code.gitea.io/gitea/services/issue" notify_service "code.gitea.io/gitea/services/notify" ) diff --git a/services/pull/review.go b/services/pull/review.go index 39644479f..1220d5472 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/archiver/archiver_test.go b/services/repository/archiver/archiver_test.go index 5deec259d..ec6e9dfac 100644 --- a/services/repository/archiver/archiver_test.go +++ b/services/repository/archiver/archiver_test.go @@ -10,7 +10,7 @@ import ( "code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/unittest" - "code.gitea.io/gitea/modules/contexttest" + "code.gitea.io/gitea/services/contexttest" _ "code.gitea.io/gitea/models/actions" diff --git a/services/repository/branch.go b/services/repository/branch.go index 39be3984a..c3a7282f4 100644 --- a/services/repository/branch.go +++ b/services/repository/branch.go @@ -23,7 +23,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" notify_service "code.gitea.io/gitea/services/notify" files_service "code.gitea.io/gitea/services/repository/files" @@ -52,7 +51,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 @@ -60,7 +59,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/repository/commit.go b/services/repository/commit.go index 2497910a8..e8c0262ef 100644 --- a/services/repository/commit.go +++ b/services/repository/commit.go @@ -7,8 +7,8 @@ import ( "context" "fmt" - gitea_ctx "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/util" + gitea_ctx "code.gitea.io/gitea/services/context" ) type ContainedLinks struct { // TODO: better name? diff --git a/services/repository/create.go b/services/repository/create.go index c3b50ae74..9bc0b93ef 100644 --- a/services/repository/create.go +++ b/services/repository/create.go @@ -157,7 +157,7 @@ func initRepository(ctx context.Context, repoPath string, u *user_model.User, re } // Apply changes and commit. - if err = repo_module.InitRepoCommit(ctx, tmpDir, repo, u, opts.DefaultBranch); err != nil { + if err = initRepoCommit(ctx, tmpDir, repo, u, opts.DefaultBranch); err != nil { return fmt.Errorf("initRepoCommit: %w", err) } } diff --git a/services/repository/files/content_test.go b/services/repository/files/content_test.go index d50847789..4811f9d32 100644 --- a/services/repository/files/content_test.go +++ b/services/repository/files/content_test.go @@ -7,9 +7,9 @@ import ( "testing" "code.gitea.io/gitea/models/unittest" - "code.gitea.io/gitea/modules/contexttest" "code.gitea.io/gitea/modules/gitrepo" api "code.gitea.io/gitea/modules/structs" + "code.gitea.io/gitea/services/contexttest" _ "code.gitea.io/gitea/models/actions" diff --git a/services/repository/files/diff_test.go b/services/repository/files/diff_test.go index fbd2f3e70..7cec979d7 100644 --- a/services/repository/files/diff_test.go +++ b/services/repository/files/diff_test.go @@ -8,8 +8,8 @@ import ( repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/models/unittest" - "code.gitea.io/gitea/modules/contexttest" "code.gitea.io/gitea/modules/json" + "code.gitea.io/gitea/services/contexttest" "code.gitea.io/gitea/services/gitdiff" "github.com/stretchr/testify/assert" diff --git a/services/repository/files/file_test.go b/services/repository/files/file_test.go index 675ddbddb..a5b3aad91 100644 --- a/services/repository/files/file_test.go +++ b/services/repository/files/file_test.go @@ -7,10 +7,10 @@ import ( "testing" "code.gitea.io/gitea/models/unittest" - "code.gitea.io/gitea/modules/contexttest" "code.gitea.io/gitea/modules/gitrepo" "code.gitea.io/gitea/modules/setting" api "code.gitea.io/gitea/modules/structs" + "code.gitea.io/gitea/services/contexttest" "github.com/stretchr/testify/assert" ) diff --git a/services/repository/files/search_test.go b/services/repository/files/search_test.go index c24bb731a..959ddaa9f 100644 --- a/services/repository/files/search_test.go +++ b/services/repository/files/search_test.go @@ -4,7 +4,7 @@ import ( "testing" "code.gitea.io/gitea/models/unittest" - "code.gitea.io/gitea/modules/contexttest" + "code.gitea.io/gitea/services/contexttest" "github.com/stretchr/testify/assert" ) diff --git a/services/repository/files/tree_test.go b/services/repository/files/tree_test.go index 528ef500d..508f20090 100644 --- a/services/repository/files/tree_test.go +++ b/services/repository/files/tree_test.go @@ -7,8 +7,8 @@ import ( "testing" "code.gitea.io/gitea/models/unittest" - "code.gitea.io/gitea/modules/contexttest" api "code.gitea.io/gitea/modules/structs" + "code.gitea.io/gitea/services/contexttest" "github.com/stretchr/testify/assert" ) diff --git a/modules/repository/generate.go b/services/repository/generate.go similarity index 94% rename from modules/repository/generate.go rename to services/repository/generate.go index f622383bb..c444b60b2 100644 --- a/modules/repository/generate.go +++ b/services/repository/generate.go @@ -21,6 +21,7 @@ import ( "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/gitrepo" "code.gitea.io/gitea/modules/log" + repo_module "code.gitea.io/gitea/modules/repository" "code.gitea.io/gitea/modules/util" "github.com/gobwas/glob" @@ -242,7 +243,7 @@ func generateRepoCommit(ctx context.Context, repo, templateRepo, generateRepo *r defaultBranch = templateRepo.DefaultBranch } - return InitRepoCommit(ctx, tmpDir, repo, repo.Owner, defaultBranch) + return initRepoCommit(ctx, tmpDir, repo, repo.Owner, defaultBranch) } func generateGitContent(ctx context.Context, repo, templateRepo, generateRepo *repo_model.Repository) (err error) { @@ -292,7 +293,7 @@ func GenerateGitContent(ctx context.Context, templateRepo, generateRepo *repo_mo return err } - if err := UpdateRepoSize(ctx, generateRepo); err != nil { + if err := repo_module.UpdateRepoSize(ctx, generateRepo); err != nil { return fmt.Errorf("failed to update size for repository: %w", err) } @@ -323,8 +324,8 @@ func (gro GenerateRepoOptions) IsValid() bool { gro.IssueLabels || gro.ProtectedBranch // or other items as they are added } -// GenerateRepository generates a repository from a template -func GenerateRepository(ctx context.Context, doer, owner *user_model.User, templateRepo *repo_model.Repository, opts GenerateRepoOptions) (_ *repo_model.Repository, err error) { +// generateRepository generates a repository from a template +func generateRepository(ctx context.Context, doer, owner *user_model.User, templateRepo *repo_model.Repository, opts GenerateRepoOptions) (_ *repo_model.Repository, err error) { generateRepo := &repo_model.Repository{ OwnerID: owner.ID, Owner: owner, @@ -341,7 +342,7 @@ func GenerateRepository(ctx context.Context, doer, owner *user_model.User, templ ObjectFormatName: templateRepo.ObjectFormatName, } - if err = CreateRepositoryByExample(ctx, doer, owner, generateRepo, false, false); err != nil { + if err = repo_module.CreateRepositoryByExample(ctx, doer, owner, generateRepo, false, false); err != nil { return nil, err } @@ -358,11 +359,11 @@ func GenerateRepository(ctx context.Context, doer, owner *user_model.User, templ } } - if err = CheckInitRepository(ctx, owner.Name, generateRepo.Name, generateRepo.ObjectFormatName); err != nil { + if err = repo_module.CheckInitRepository(ctx, owner.Name, generateRepo.Name, generateRepo.ObjectFormatName); err != nil { return generateRepo, err } - if err = CheckDaemonExportOK(ctx, generateRepo); err != nil { + if err = repo_module.CheckDaemonExportOK(ctx, generateRepo); err != nil { return generateRepo, fmt.Errorf("checkDaemonExportOK: %w", err) } diff --git a/modules/repository/generate_test.go b/services/repository/generate_test.go similarity index 100% rename from modules/repository/generate_test.go rename to services/repository/generate_test.go diff --git a/services/repository/init.go b/services/repository/init.go new file mode 100644 index 000000000..817fa4abd --- /dev/null +++ b/services/repository/init.go @@ -0,0 +1,83 @@ +// Copyright 2024 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package repository + +import ( + "context" + "fmt" + "os" + "time" + + repo_model "code.gitea.io/gitea/models/repo" + user_model "code.gitea.io/gitea/models/user" + "code.gitea.io/gitea/modules/git" + "code.gitea.io/gitea/modules/log" + repo_module "code.gitea.io/gitea/modules/repository" + "code.gitea.io/gitea/modules/setting" + asymkey_service "code.gitea.io/gitea/services/asymkey" +) + +// initRepoCommit temporarily changes with work directory. +func initRepoCommit(ctx context.Context, tmpPath string, repo *repo_model.Repository, u *user_model.User, defaultBranch string) (err error) { + commitTimeStr := time.Now().Format(time.RFC3339) + + sig := u.NewGitSig() + // Because this may call hooks we should pass in the environment + env := append(os.Environ(), + "GIT_AUTHOR_NAME="+sig.Name, + "GIT_AUTHOR_EMAIL="+sig.Email, + "GIT_AUTHOR_DATE="+commitTimeStr, + "GIT_COMMITTER_DATE="+commitTimeStr, + ) + committerName := sig.Name + committerEmail := sig.Email + + if stdout, _, err := git.NewCommand(ctx, "add", "--all"). + SetDescription(fmt.Sprintf("initRepoCommit (git add): %s", tmpPath)). + RunStdString(&git.RunOpts{Dir: tmpPath}); err != nil { + log.Error("git add --all failed: Stdout: %s\nError: %v", stdout, err) + return fmt.Errorf("git add --all: %w", err) + } + + cmd := git.NewCommand(ctx, "commit", "--message=Initial commit"). + AddOptionFormat("--author='%s <%s>'", sig.Name, sig.Email) + + sign, keyID, signer, _ := asymkey_service.SignInitialCommit(ctx, tmpPath, u) + if sign { + cmd.AddOptionFormat("-S%s", keyID) + + if repo.GetTrustModel() == repo_model.CommitterTrustModel || repo.GetTrustModel() == repo_model.CollaboratorCommitterTrustModel { + // need to set the committer to the KeyID owner + committerName = signer.Name + committerEmail = signer.Email + } + } else { + cmd.AddArguments("--no-gpg-sign") + } + + env = append(env, + "GIT_COMMITTER_NAME="+committerName, + "GIT_COMMITTER_EMAIL="+committerEmail, + ) + + if stdout, _, err := cmd. + SetDescription(fmt.Sprintf("initRepoCommit (git commit): %s", tmpPath)). + RunStdString(&git.RunOpts{Dir: tmpPath, Env: env}); err != nil { + log.Error("Failed to commit: %v: Stdout: %s\nError: %v", cmd.String(), stdout, err) + return fmt.Errorf("git commit: %w", err) + } + + if len(defaultBranch) == 0 { + defaultBranch = setting.Repository.DefaultBranch + } + + if stdout, _, err := git.NewCommand(ctx, "push", "origin").AddDynamicArguments("HEAD:" + defaultBranch). + SetDescription(fmt.Sprintf("initRepoCommit (git push): %s", tmpPath)). + RunStdString(&git.RunOpts{Dir: tmpPath, Env: repo_module.InternalPushingEnvironment(u, repo)}); err != nil { + log.Error("Failed to push back to HEAD: Stdout: %s\nError: %v", stdout, err) + return fmt.Errorf("git push: %w", err) + } + + return nil +} diff --git a/services/repository/template.go b/services/repository/template.go index 06cf05026..36a680c8e 100644 --- a/services/repository/template.go +++ b/services/repository/template.go @@ -11,7 +11,6 @@ import ( issues_model "code.gitea.io/gitea/models/issues" repo_model "code.gitea.io/gitea/models/repo" user_model "code.gitea.io/gitea/models/user" - repo_module "code.gitea.io/gitea/modules/repository" notify_service "code.gitea.io/gitea/services/notify" ) @@ -63,7 +62,7 @@ func GenerateProtectedBranch(ctx context.Context, templateRepo, generateRepo *re } // GenerateRepository generates a repository from a template -func GenerateRepository(ctx context.Context, doer, owner *user_model.User, templateRepo *repo_model.Repository, opts repo_module.GenerateRepoOptions) (_ *repo_model.Repository, err error) { +func GenerateRepository(ctx context.Context, doer, owner *user_model.User, templateRepo *repo_model.Repository, opts GenerateRepoOptions) (_ *repo_model.Repository, err error) { if !doer.IsAdmin && !owner.CanCreateRepo() { return nil, repo_model.ErrReachLimitOfRepo{ Limit: owner.MaxRepoCreation, @@ -72,14 +71,14 @@ func GenerateRepository(ctx context.Context, doer, owner *user_model.User, templ var generateRepo *repo_model.Repository if err = db.WithTx(ctx, func(ctx context.Context) error { - generateRepo, err = repo_module.GenerateRepository(ctx, doer, owner, templateRepo, opts) + generateRepo, err = generateRepository(ctx, doer, owner, templateRepo, opts) if err != nil { return err } // Git Content if opts.GitContent && !templateRepo.IsEmpty { - if err = repo_module.GenerateGitContent(ctx, templateRepo, generateRepo); err != nil { + if err = GenerateGitContent(ctx, templateRepo, generateRepo); err != nil { return err } } diff --git a/services/webhook/webhook.go b/services/webhook/webhook.go index 068be29cc..996942d1e 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/tailwind.config.js b/tailwind.config.js index 8c474c33a..7f3682200 100644 --- a/tailwind.config.js +++ b/tailwind.config.js @@ -6,6 +6,7 @@ const isProduction = env.NODE_ENV !== 'development'; export default { prefix: 'tw-', + important: true, // the frameworks are mixed together, so tailwind needs to override other framework's styles content: [ isProduction && '!./templates/devtest/**/*', isProduction && '!./web_src/js/standalone/devtest.js', diff --git a/templates/admin/dashboard.tmpl b/templates/admin/dashboard.tmpl index 8088315f1..53a12cbe2 100644 --- a/templates/admin/dashboard.tmpl +++ b/templates/admin/dashboard.tmpl @@ -2,7 +2,7 @@
{{if .NeedUpdate}}
-

{{(ctx.Locale.Tr "admin.dashboard.new_version_hint" .RemoteVersion AppVer) | Str2html}}

+

{{(ctx.Locale.Tr "admin.dashboard.new_version_hint" .RemoteVersion AppVer) | SanitizeHTML}}

{{end}}

diff --git a/templates/admin/repo/list.tmpl b/templates/admin/repo/list.tmpl index e11247aed..e977c8307 100644 --- a/templates/admin/repo/list.tmpl +++ b/templates/admin/repo/list.tmpl @@ -7,7 +7,7 @@

- {{template "admin/repo/search" .}} + {{template "shared/repo_search" .}}
diff --git a/templates/admin/repo/search.tmpl b/templates/admin/repo/search.tmpl deleted file mode 100644 index 247ec5491..000000000 --- a/templates/admin/repo/search.tmpl +++ /dev/null @@ -1,29 +0,0 @@ - diff --git a/templates/admin/self_check.tmpl b/templates/admin/self_check.tmpl index 6bca01ec6..fafaf9242 100644 --- a/templates/admin/self_check.tmpl +++ b/templates/admin/self_check.tmpl @@ -20,7 +20,7 @@ {{if .DatabaseCheckInconsistentCollationColumns}}
{{ctx.Locale.Tr "admin.self_check.database_inconsistent_collation_columns" .DatabaseCheckResult.DatabaseCollation}} -
    +
      {{range .DatabaseCheckInconsistentCollationColumns}}
    • {{.}}
    • {{end}} diff --git a/templates/admin/user/edit.tmpl b/templates/admin/user/edit.tmpl index fcb8ce082..159c82109 100644 --- a/templates/admin/user/edit.tmpl +++ b/templates/admin/user/edit.tmpl @@ -70,6 +70,21 @@

      {{ctx.Locale.Tr "admin.users.password_helper"}}

+ +
+ + +
+
diff --git a/templates/admin/user/view_details.tmpl b/templates/admin/user/view_details.tmpl index 21425eecb..be2f32b5e 100644 --- a/templates/admin/user/view_details.tmpl +++ b/templates/admin/user/view_details.tmpl @@ -48,6 +48,14 @@ {{svg "octicon-x"}} {{end}}
+ {{if .User.Language}} +
+ + {{ctx.Locale.Tr "settings.language"}}: + {{range .AllLangs}}{{if eq $.User.Language .Lang}}{{.Name}}{{end}}{{end}} + +
+ {{end}} {{if .User.Location}}
{{svg "octicon-location"}}{{.User.Location}} diff --git a/templates/base/alert.tmpl b/templates/base/alert.tmpl index 160584f76..760d3bfa2 100644 --- a/templates/base/alert.tmpl +++ b/templates/base/alert.tmpl @@ -1,20 +1,20 @@ {{if .Flash.ErrorMsg}}
-

{{.Flash.ErrorMsg | Str2html}}

+

{{.Flash.ErrorMsg | SanitizeHTML}}

{{end}} {{if .Flash.SuccessMsg}}
-

{{.Flash.SuccessMsg | Str2html}}

+

{{.Flash.SuccessMsg | SanitizeHTML}}

{{end}} {{if .Flash.InfoMsg}}
-

{{.Flash.InfoMsg | Str2html}}

+

{{.Flash.InfoMsg | SanitizeHTML}}

{{end}} {{if .Flash.WarningMsg}}
-

{{.Flash.WarningMsg | Str2html}}

+

{{.Flash.WarningMsg | SanitizeHTML}}

{{end}} diff --git a/templates/base/alert_details.tmpl b/templates/base/alert_details.tmpl index 1d7ec15dc..6801c8240 100644 --- a/templates/base/alert_details.tmpl +++ b/templates/base/alert_details.tmpl @@ -2,6 +2,6 @@
{{.Summary}} - {{.Details | Str2html}} + {{.Details | SanitizeHTML}}
diff --git a/templates/base/head_navbar.tmpl b/templates/base/head_navbar.tmpl index fb0301aeb..06fc5913d 100644 --- a/templates/base/head_navbar.tmpl +++ b/templates/base/head_navbar.tmpl @@ -13,14 +13,14 @@ diff --git a/templates/base/paginate.tmpl b/templates/base/paginate.tmpl index 503817c33..ef7d0b341 100644 --- a/templates/base/paginate.tmpl +++ b/templates/base/paginate.tmpl @@ -1,13 +1,15 @@ -{{$paginationLink := .Page.GetParams}} +{{$paginationParams := .Page.GetParams}} +{{$paginationLink := $.Link}} +{{if eq $paginationLink AppSubUrl}}{{$paginationLink = print $paginationLink "/"}}{{end}} {{with .Page.Paginater}} {{if gt .TotalPages 1}}
diff --git a/templates/home.tmpl b/templates/home.tmpl index 78364431e..393525dcd 100644 --- a/templates/home.tmpl +++ b/templates/home.tmpl @@ -17,7 +17,7 @@ {{svg "octicon-flame"}} {{ctx.Locale.Tr "startpage.install"}}

- {{ctx.Locale.Tr "startpage.install_desc" | Str2html}} + {{ctx.Locale.Tr "startpage.install_desc" | SanitizeHTML}}

@@ -25,7 +25,7 @@ {{svg "octicon-device-desktop"}} {{ctx.Locale.Tr "startpage.platform"}}

- {{ctx.Locale.Tr "startpage.platform_desc" | Str2html}} + {{ctx.Locale.Tr "startpage.platform_desc" | SanitizeHTML}}

@@ -35,7 +35,7 @@ {{svg "octicon-rocket"}} {{ctx.Locale.Tr "startpage.lightweight"}}

- {{ctx.Locale.Tr "startpage.lightweight_desc" | Str2html}} + {{ctx.Locale.Tr "startpage.lightweight_desc" | SanitizeHTML}}

@@ -43,7 +43,7 @@ {{svg "octicon-code"}} {{ctx.Locale.Tr "startpage.license"}}

- {{ctx.Locale.Tr "startpage.license_desc" | Str2html}} + {{ctx.Locale.Tr "startpage.license_desc" | SanitizeHTML}}

diff --git a/templates/mail/auth/activate.tmpl b/templates/mail/auth/activate.tmpl index a15afe3d4..c50717d31 100644 --- a/templates/mail/auth/activate.tmpl +++ b/templates/mail/auth/activate.tmpl @@ -8,8 +8,8 @@ {{$activate_url := printf "%suser/activate?code=%s" AppUrl (QueryEscape .Code)}} -

{{.locale.Tr "mail.activate_account.text_1" (.DisplayName|DotEscape) AppName | Str2html}}


-

{{.locale.Tr "mail.activate_account.text_2" .ActiveCodeLives | Str2html}}

{{$activate_url}}


+

{{.locale.Tr "mail.activate_account.text_1" (.DisplayName|DotEscape) AppName | SanitizeHTML}}


+

{{.locale.Tr "mail.activate_account.text_2" .ActiveCodeLives | SanitizeHTML}}

{{$activate_url}}


{{.locale.Tr "mail.link_not_working_do_paste"}}

© {{AppName}}

diff --git a/templates/mail/auth/activate_email.tmpl b/templates/mail/auth/activate_email.tmpl index b15cc2a68..30fcb99ab 100644 --- a/templates/mail/auth/activate_email.tmpl +++ b/templates/mail/auth/activate_email.tmpl @@ -8,8 +8,8 @@ {{$activate_url := printf "%suser/activate_email?code=%s&email=%s" AppUrl (QueryEscape .Code) (QueryEscape .Email)}} -

{{.locale.Tr "mail.hi_user_x" (.DisplayName|DotEscape) | Str2html}}


-

{{.locale.Tr "mail.activate_email.text" .ActiveCodeLives | Str2html}}

{{$activate_url}}


+

{{.locale.Tr "mail.hi_user_x" (.DisplayName|DotEscape) | SanitizeHTML}}


+

{{.locale.Tr "mail.activate_email.text" .ActiveCodeLives | SanitizeHTML}}

{{$activate_url}}


{{.locale.Tr "mail.link_not_working_do_paste"}}

© {{AppName}}

diff --git a/templates/mail/auth/register_notify.tmpl b/templates/mail/auth/register_notify.tmpl index 224c84545..27c685e58 100644 --- a/templates/mail/auth/register_notify.tmpl +++ b/templates/mail/auth/register_notify.tmpl @@ -8,7 +8,7 @@ {{$set_pwd_url := printf "%[1]suser/forgot_password" AppUrl}} -

{{.locale.Tr "mail.hi_user_x" (.DisplayName|DotEscape) | Str2html}}


+

{{.locale.Tr "mail.hi_user_x" (.DisplayName|DotEscape) | SanitizeHTML}}


{{.locale.Tr "mail.register_notify.text_1" AppName}}


{{.locale.Tr "mail.register_notify.text_2" .Username}}

{{AppUrl}}user/login


{{.locale.Tr "mail.register_notify.text_3" $set_pwd_url}}


diff --git a/templates/mail/auth/reset_passwd.tmpl b/templates/mail/auth/reset_passwd.tmpl index 172844c95..e1af5b483 100644 --- a/templates/mail/auth/reset_passwd.tmpl +++ b/templates/mail/auth/reset_passwd.tmpl @@ -8,8 +8,8 @@ {{$recover_url := printf "%suser/recover_account?code=%s" AppUrl (QueryEscape .Code)}} -

{{.locale.Tr "mail.hi_user_x" (.DisplayName|DotEscape) | Str2html}}


-

{{.locale.Tr "mail.reset_password.text" .ResetPwdCodeLives | Str2html}}

{{$recover_url}}


+

{{.locale.Tr "mail.hi_user_x" (.DisplayName|DotEscape) | SanitizeHTML}}


+

{{.locale.Tr "mail.reset_password.text" .ResetPwdCodeLives | SanitizeHTML}}

{{$recover_url}}


{{.locale.Tr "mail.link_not_working_do_paste"}}

© {{AppName}}

diff --git a/templates/mail/issue/default.tmpl b/templates/mail/issue/default.tmpl index 49887e1e1..796dc403b 100644 --- a/templates/mail/issue/default.tmpl +++ b/templates/mail/issue/default.tmpl @@ -16,7 +16,7 @@ - {{if .IsMention}}

{{.locale.Tr "mail.issue.x_mentioned_you" .Doer.Name | Str2html}}

{{end}} + {{if .IsMention}}

{{.locale.Tr "mail.issue.x_mentioned_you" .Doer.Name | SanitizeHTML}}

{{end}} {{if eq .ActionName "push"}}

{{if .Comment.IsForcePush}} @@ -30,7 +30,7 @@ {{.locale.Tr "mail.issue.action.force_push" .Doer.Name .Comment.Issue.PullRequest.HeadBranch $oldCommitLink $newCommitLink}} {{else}} - {{.locale.TrN (len .Comment.Commits) "mail.issue.action.push_1" "mail.issue.action.push_n" .Doer.Name .Comment.Issue.PullRequest.HeadBranch (len .Comment.Commits) | Str2html}} + {{.locale.TrN (len .Comment.Commits) "mail.issue.action.push_1" "mail.issue.action.push_n" .Doer.Name .Comment.Issue.PullRequest.HeadBranch (len .Comment.Commits) | SanitizeHTML}} {{end}}

{{end}} @@ -58,14 +58,14 @@ {{.locale.Tr "mail.issue.action.new" .Doer.Name .Issue.Index}} {{end}} {{else}} - {{.Body | Str2html}} + {{.Body | SanitizeHTML}} {{end -}} {{- range .ReviewComments}}
{{$.locale.Tr "mail.issue.in_tree_path" .TreePath}}
{{.Patch}}
-
{{.RenderedContent | SafeHTML}}
+
{{.RenderedContent}}
{{end -}} {{if eq .ActionName "push"}} diff --git a/templates/mail/notify/admin_new_user.tmpl b/templates/mail/notify/admin_new_user.tmpl index 34d1584f6..04f90b61a 100644 --- a/templates/mail/notify/admin_new_user.tmpl +++ b/templates/mail/notify/admin_new_user.tmpl @@ -13,9 +13,9 @@
    -

    {{.Locale.Tr "mail.admin.new_user.user_info" | Str2html}}: @{{.NewUser.Name}}

    -
  • {{.Locale.Tr "admin.users.created" | Str2html}}: {{DateTime "full" .NewUser.CreatedUnix}}
  • +

    {{.Locale.Tr "mail.admin.new_user.user_info" | SanitizeHTML}}: @{{.NewUser.Name}}

    +
  • {{.Locale.Tr "admin.users.created" | SanitizeHTML}}: {{DateTime "full" .NewUser.CreatedUnix}}
-

{{.Body | Str2html}}

+

{{.Body | SanitizeHTML}}

diff --git a/templates/mail/notify/repo_transfer.tmpl b/templates/mail/notify/repo_transfer.tmpl index 597048ddf..8c8b27648 100644 --- a/templates/mail/notify/repo_transfer.tmpl +++ b/templates/mail/notify/repo_transfer.tmpl @@ -5,7 +5,7 @@ {{.Subject}} -{{$url := HTMLFormat "%[2]s" .Link .Repo)}} +{{$url := HTMLFormat "%[2]s" .Link .Repo}}

{{.Subject}}. {{.locale.Tr "mail.repo.transfer.body" $url}} diff --git a/templates/mail/release.tmpl b/templates/mail/release.tmpl index 62a16573c..90a3caa4c 100644 --- a/templates/mail/release.tmpl +++ b/templates/mail/release.tmpl @@ -22,7 +22,7 @@ {{.locale.Tr "mail.release.note"}}
{{- if eq .Release.RenderedNote ""}} {{else}} - {{.Release.RenderedNote | Str2html}} + {{.Release.RenderedNote}} {{end -}}



diff --git a/templates/mail/team_invite.tmpl b/templates/mail/team_invite.tmpl index d21b7843e..67b368f34 100644 --- a/templates/mail/team_invite.tmpl +++ b/templates/mail/team_invite.tmpl @@ -5,7 +5,7 @@ -

{{.locale.Tr "mail.team_invite.text_1" (DotEscape .Inviter.DisplayName) (DotEscape .Team.Name) (DotEscape .Organization.DisplayName) | Str2html}}

+

{{.locale.Tr "mail.team_invite.text_1" (DotEscape .Inviter.DisplayName) (DotEscape .Team.Name) (DotEscape .Organization.DisplayName) | SanitizeHTML}}

{{.locale.Tr "mail.team_invite.text_2"}}

{{.InviteURL}}

{{.locale.Tr "mail.link_not_working_do_paste"}}

{{.locale.Tr "mail.team_invite.text_3" .Invite.Email}}

diff --git a/templates/org/header.tmpl b/templates/org/header.tmpl index 8423fd7d3..efbbc43b1 100644 --- a/templates/org/header.tmpl +++ b/templates/org/header.tmpl @@ -18,7 +18,7 @@ {{end}} - {{if .RenderedDescription}}
{{.RenderedDescription | Str2html}}
{{end}} + {{if .RenderedDescription}}
{{.RenderedDescription}}
{{end}}
{{if .Org.Location}}
{{svg "octicon-location"}} {{.Org.Location}}
{{end}} {{if .Org.Website}}
{{svg "octicon-link"}} {{.Org.Website}}
{{end}} diff --git a/templates/org/home.tmpl b/templates/org/home.tmpl index 1c8a083ae..d0a39c04f 100644 --- a/templates/org/home.tmpl +++ b/templates/org/home.tmpl @@ -11,9 +11,9 @@
{{if .ProfileReadme}} -
{{.ProfileReadme | Str2html}}
+
{{.ProfileReadme}}
{{end}} - {{template "explore/repo_search" .}} + {{template "shared/repo_search" .}} {{template "explore/repo_list" .}} {{template "base/paginate" .}}
diff --git a/templates/org/settings/delete.tmpl b/templates/org/settings/delete.tmpl index 2cf8238f5..8c93e7548 100644 --- a/templates/org/settings/delete.tmpl +++ b/templates/org/settings/delete.tmpl @@ -6,7 +6,7 @@
-

{{svg "octicon-alert"}} {{ctx.Locale.Tr "org.settings.delete_prompt" | Str2html}}

+

{{svg "octicon-alert"}} {{ctx.Locale.Tr "org.settings.delete_prompt" | SanitizeHTML}}

{{.CsrfTokenHtml}} diff --git a/templates/org/settings/labels.tmpl b/templates/org/settings/labels.tmpl index b12ea8d9f..56931def8 100644 --- a/templates/org/settings/labels.tmpl +++ b/templates/org/settings/labels.tmpl @@ -2,7 +2,7 @@
- {{ctx.Locale.Tr "org.settings.labels_desc" | Str2html}} + {{ctx.Locale.Tr "org.settings.labels_desc" | SanitizeHTML}}
diff --git a/templates/org/team/invite.tmpl b/templates/org/team/invite.tmpl index e003d1475..5a8780c20 100644 --- a/templates/org/team/invite.tmpl +++ b/templates/org/team/invite.tmpl @@ -7,7 +7,7 @@ {{ctx.AvatarUtils.Avatar .Organization 140}}
-
{{ctx.Locale.Tr "org.teams.invite.title" .Team.Name .Organization.Name | Str2html}}
+
{{ctx.Locale.Tr "org.teams.invite.title" .Team.Name .Organization.Name | SanitizeHTML}}
{{ctx.Locale.Tr "org.teams.invite.by" .Inviter.Name}}
{{ctx.Locale.Tr "org.teams.invite.description"}}
diff --git a/templates/org/team/new.tmpl b/templates/org/team/new.tmpl index 0178a20fb..99b16ee22 100644 --- a/templates/org/team/new.tmpl +++ b/templates/org/team/new.tmpl @@ -32,14 +32,14 @@
- {{ctx.Locale.Tr "org.teams.specific_repositories_helper" | Str2html}} + {{ctx.Locale.Tr "org.teams.specific_repositories_helper" | SanitizeHTML}}
- {{ctx.Locale.Tr "org.teams.all_repositories_helper" | Str2html}} + {{ctx.Locale.Tr "org.teams.all_repositories_helper" | SanitizeHTML}}
diff --git a/templates/org/team/sidebar.tmpl b/templates/org/team/sidebar.tmpl index 509c6382d..e59c0e561 100644 --- a/templates/org/team/sidebar.tmpl +++ b/templates/org/team/sidebar.tmpl @@ -27,16 +27,16 @@
{{if eq .Team.LowerName "owners"}}
- {{ctx.Locale.Tr "org.teams.owners_permission_desc" | Str2html}} + {{ctx.Locale.Tr "org.teams.owners_permission_desc" | SanitizeHTML}}
{{else}}

{{ctx.Locale.Tr "org.team_access_desc"}}

    {{if .Team.IncludesAllRepositories}} -
  • {{ctx.Locale.Tr "org.teams.all_repositories" | Str2html}}
  • +
  • {{ctx.Locale.Tr "org.teams.all_repositories" | SanitizeHTML}}
  • {{else}} -
  • {{ctx.Locale.Tr "org.teams.specific_repositories" | Str2html}}
  • +
  • {{ctx.Locale.Tr "org.teams.specific_repositories" | SanitizeHTML}}
  • {{end}} {{if .Team.CanCreateOrgRepo}}
  • {{ctx.Locale.Tr "org.teams.can_create_org_repo"}}
  • @@ -44,10 +44,10 @@
{{if (eq .Team.AccessMode 2)}}

{{ctx.Locale.Tr "org.settings.permission"}}

- {{ctx.Locale.Tr "org.teams.write_permission_desc" | Str2html}} + {{ctx.Locale.Tr "org.teams.write_permission_desc" | SanitizeHTML}} {{else if (eq .Team.AccessMode 3)}}

{{ctx.Locale.Tr "org.settings.permission"}}

- {{ctx.Locale.Tr "org.teams.admin_permission_desc" | Str2html}} + {{ctx.Locale.Tr "org.teams.admin_permission_desc" | SanitizeHTML}} {{else}}
diff --git a/templates/package/content/nuget.tmpl b/templates/package/content/nuget.tmpl index f4807b0ad..d56f50cb2 100644 --- a/templates/package/content/nuget.tmpl +++ b/templates/package/content/nuget.tmpl @@ -20,7 +20,7 @@

{{ctx.Locale.Tr "packages.about"}}

{{if .PackageDescriptor.Metadata.Description}}{{.PackageDescriptor.Metadata.Description}}{{end}} - {{if .PackageDescriptor.Metadata.ReleaseNotes}}{{Str2html .PackageDescriptor.Metadata.ReleaseNotes}}{{end}} + {{if .PackageDescriptor.Metadata.ReleaseNotes}}{{.PackageDescriptor.Metadata.ReleaseNotes}}{{end}}
{{end}} diff --git a/templates/projects/list.tmpl b/templates/projects/list.tmpl index cbff82dd7..30fbd498a 100644 --- a/templates/projects/list.tmpl +++ b/templates/projects/list.tmpl @@ -75,7 +75,7 @@ {{if .Description}}
- {{.RenderedContent|Str2html}} + {{.RenderedContent}}
{{end}} diff --git a/templates/projects/view.tmpl b/templates/projects/view.tmpl index b3ad03c35..3792ccca0 100644 --- a/templates/projects/view.tmpl +++ b/templates/projects/view.tmpl @@ -58,7 +58,7 @@ {{end}} -
{{$.Project.RenderedContent|Str2html}}
+
{{$.Project.RenderedContent}}
diff --git a/templates/repo/blame.tmpl b/templates/repo/blame.tmpl index 3bd5e3694..75104cdcd 100644 --- a/templates/repo/blame.tmpl +++ b/templates/repo/blame.tmpl @@ -2,11 +2,11 @@ {{$revsFileLink := URLJoin .RepoLink "src" .BranchNameSubURL "/.git-blame-ignore-revs"}} {{if .UsesIgnoreRevs}}
-

{{ctx.Locale.Tr "repo.blame.ignore_revs" $revsFileLink (print $revsFileLink "?bypass-blame-ignore=true") | Str2html}}

+

{{ctx.Locale.Tr "repo.blame.ignore_revs" $revsFileLink (print $revsFileLink "?bypass-blame-ignore=true") | SanitizeHTML}}

{{else}}
-

{{ctx.Locale.Tr "repo.blame.ignore_revs.failed" $revsFileLink | Str2html}}

+

{{ctx.Locale.Tr "repo.blame.ignore_revs.failed" $revsFileLink | SanitizeHTML}}

{{end}} {{end}} diff --git a/templates/repo/branch/list.tmpl b/templates/repo/branch/list.tmpl index 8ae7301c4..4aa0e22b7 100644 --- a/templates/repo/branch/list.tmpl +++ b/templates/repo/branch/list.tmpl @@ -210,7 +210,7 @@ {{ctx.Locale.Tr "repo.branch.delete_html"}}
-

{{ctx.Locale.Tr "repo.branch.delete_desc" | Str2html}}

+

{{ctx.Locale.Tr "repo.branch.delete_desc" | SanitizeHTML}}

{{template "base/modal_actions_confirm" .}} diff --git a/templates/repo/clone_script.tmpl b/templates/repo/clone_script.tmpl index 9ff826bc9..46e49e7f8 100644 --- a/templates/repo/clone_script.tmpl +++ b/templates/repo/clone_script.tmpl @@ -24,14 +24,22 @@ const btn = isSSH ? sshBtn : httpsBtn; if (!btn) return; - let link = btn.getAttribute('data-link'); - if (link.startsWith('http://') || link.startsWith('https://')) { - // use current protocol/host as the clone link - const url = new URL(link); - url.protocol = window.location.protocol; - url.host = window.location.host; - link = url.toString(); + // NOTE: Keep this function in sync with the one in the js folder + function toOriginUrl(urlStr) { + try { + if (urlStr.startsWith('http://') || urlStr.startsWith('https://') || urlStr.startsWith('/')) { + const {origin, protocol, hostname, port} = window.location; + const url = new URL(urlStr, origin); + url.protocol = protocol; + url.hostname = hostname; + url.port = port || (protocol === 'https:' ? '443' : '80'); + return url.toString(); + } + } catch {} + return urlStr; } + const link = toOriginUrl(btn.getAttribute('data-link')); + for (const el of document.getElementsByClassName('js-clone-url')) { el[el.nodeName === 'INPUT' ? 'value' : 'textContent'] = link; } diff --git a/templates/repo/commit_page.tmpl b/templates/repo/commit_page.tmpl index 115ee9295..7892a5716 100644 --- a/templates/repo/commit_page.tmpl +++ b/templates/repo/commit_page.tmpl @@ -276,7 +276,7 @@ {{TimeSince .NoteCommit.Author.When ctx.Locale}}
-
{{.NoteRendered | Str2html}}
+
{{.NoteRendered | SanitizeHTML}}
{{end}} {{template "repo/diff/box" .}} diff --git a/templates/repo/create.tmpl b/templates/repo/create.tmpl index d6ff22b7a..1ddf2c480 100644 --- a/templates/repo/create.tmpl +++ b/templates/repo/create.tmpl @@ -158,7 +158,7 @@ {{end}} - {{ctx.Locale.Tr "repo.license_helper_desc" "https://choosealicense.com/" | Str2html}} + {{ctx.Locale.Tr "repo.license_helper_desc" "https://choosealicense.com/" | SanitizeHTML}}
diff --git a/templates/repo/diff/box.tmpl b/templates/repo/diff/box.tmpl index 9dcc59cea..f9f18208e 100644 --- a/templates/repo/diff/box.tmpl +++ b/templates/repo/diff/box.tmpl @@ -19,7 +19,7 @@ {{end}} {{if not .DiffNotAvailable}}
- {{svg "octicon-diff" 16 "gt-mr-2"}}{{ctx.Locale.Tr "repo.diff.stats_desc" .Diff.NumFiles .Diff.TotalAddition .Diff.TotalDeletion | Str2html}} + {{svg "octicon-diff" 16 "gt-mr-2"}}{{ctx.Locale.Tr "repo.diff.stats_desc" .Diff.NumFiles .Diff.TotalAddition .Diff.TotalDeletion | SanitizeHTML}}
{{end}}
@@ -206,7 +206,7 @@ {{if $showFileViewToggle}} {{/* for image or CSV, it can have a horizontal scroll bar, there won't be review comment context menu (position absolute) which would be clipped by "overflow" */}}
-
+
{{if $isImage}} {{template "repo/diff/image_diff" dict "file" . "root" $ "blobBase" $blobBase "blobHead" $blobHead "sniffedTypeBase" $sniffedTypeBase "sniffedTypeHead" $sniffedTypeHead}} {{else}} diff --git a/templates/repo/diff/comments.tmpl b/templates/repo/diff/comments.tmpl index e567417fa..0bb577deb 100644 --- a/templates/repo/diff/comments.tmpl +++ b/templates/repo/diff/comments.tmpl @@ -55,7 +55,7 @@
{{if .RenderedContent}} - {{.RenderedContent|Str2html}} + {{.RenderedContent}} {{else}} {{ctx.Locale.Tr "repo.issues.no_content"}} {{end}} @@ -63,7 +63,7 @@
{{.Content}}
{{if .Attachments}} - {{template "repo/issue/view_content/attachments" dict "ctxData" $ "Attachments" .Attachments "Content" .RenderedContent}} + {{template "repo/issue/view_content/attachments" dict "ctxData" $ "Attachments" .Attachments "RenderedContent" .RenderedContent}} {{end}}
{{$reactions := .Reactions.GroupByType}} diff --git a/templates/repo/diff/compare.tmpl b/templates/repo/diff/compare.tmpl index 65b85b968..17e0d3e71 100644 --- a/templates/repo/diff/compare.tmpl +++ b/templates/repo/diff/compare.tmpl @@ -11,14 +11,6 @@ {{ctx.Locale.Tr "action.compare_commits_general"}} {{end}} - {{if .Flash.WarningMsg}} - {{/* - There's already an importing of alert.tmpl in new_form.tmpl, - but only the negative message will be displayed within forms for some reasons, see semantic.css:10659. - To avoid repeated negative messages, the importing here if for .Flash.WarningMsg only. - */}} - {{template "base/alert" .}} - {{end}} {{$BaseCompareName := $.BaseName -}} {{- $HeadCompareName := $.HeadRepo.OwnerName -}} {{- if and (eq $.BaseName $.HeadRepo.OwnerName) (ne $.Repository.Name $.HeadRepo.Name) -}} diff --git a/templates/repo/diff/stats.tmpl b/templates/repo/diff/stats.tmpl index db468ab6c..64ee17a7c 100644 --- a/templates/repo/diff/stats.tmpl +++ b/templates/repo/diff/stats.tmpl @@ -1,5 +1,5 @@ {{Eval .file.Addition "+" .file.Deletion}} - + {{/* if the denominator is zero, then the float result is "width: NaNpx", as before, it just works */}}
diff --git a/templates/repo/empty.tmpl b/templates/repo/empty.tmpl index 62194abe5..7a0e6926c 100644 --- a/templates/repo/empty.tmpl +++ b/templates/repo/empty.tmpl @@ -24,7 +24,7 @@
-

{{ctx.Locale.Tr "repo.clone_this_repo"}} {{ctx.Locale.Tr "repo.clone_helper" "http://git-scm.com/book/en/Git-Basics-Getting-a-Git-Repository" | Str2html}}

+

{{ctx.Locale.Tr "repo.clone_this_repo"}} {{ctx.Locale.Tr "repo.clone_helper" "http://git-scm.com/book/en/Git-Basics-Getting-a-Git-Repository" | SanitizeHTML}}

{{if and .CanWriteCode (not .Repository.IsArchived)}} diff --git a/templates/repo/issue/card.tmpl b/templates/repo/issue/card.tmpl index 7fb3d8282..5e524079c 100644 --- a/templates/repo/issue/card.tmpl +++ b/templates/repo/issue/card.tmpl @@ -6,7 +6,7 @@ {{end}}
{{end}} -
+
{{template "shared/issueicon" .}} diff --git a/templates/repo/issue/fields/checkboxes.tmpl b/templates/repo/issue/fields/checkboxes.tmpl index 237f2eb5d..b928b2be5 100644 --- a/templates/repo/issue/fields/checkboxes.tmpl +++ b/templates/repo/issue/fields/checkboxes.tmpl @@ -1,8 +1,8 @@ -
+
{{template "repo/issue/fields/header" .}} {{range $i, $opt := .item.Attributes.options}}
-
+
diff --git a/templates/repo/issue/fields/dropdown.tmpl b/templates/repo/issue/fields/dropdown.tmpl index 23aa373cd..b8df6908e 100644 --- a/templates/repo/issue/fields/dropdown.tmpl +++ b/templates/repo/issue/fields/dropdown.tmpl @@ -1,4 +1,4 @@ -
+
{{template "repo/issue/fields/header" .}} {{/* FIXME: required validation */}}
+
- @@ -55,7 +55,7 @@ {{$commitLink := printf "%s/commit/%s" $.RepoLink (PathEscape $commit.ID.String)}} {{RenderCommitMessageLinkSubject $.Context $commit.Message $commitLink ($.Repository.ComposeMetas ctx)}} {{else}} -
+
{{end}} diff --git a/templates/shared/repo_search.tmpl b/templates/shared/repo_search.tmpl new file mode 100644 index 000000000..2ea4bfaad --- /dev/null +++ b/templates/shared/repo_search.tmpl @@ -0,0 +1,67 @@ + +{{if and .PageIsExploreRepositories .OnlyShowRelevant}} +
+ {{ctx.Locale.Tr "explore.relevant_repositories" (printf "?only_show_relevant=0&sort=%s&q=%s&language=%s" $.SortType (QueryEscape $.Keyword) (QueryEscape $.Language))}} +
+{{end}} diff --git a/templates/shared/user/profile_big_avatar.tmpl b/templates/shared/user/profile_big_avatar.tmpl index f1b0560b3..4e25a5373 100644 --- a/templates/shared/user/profile_big_avatar.tmpl +++ b/templates/shared/user/profile_big_avatar.tmpl @@ -70,7 +70,7 @@ {{end}} {{if $.RenderedDescription}}
  • -
    {{$.RenderedDescription|Str2html}}
    +
    {{$.RenderedDescription}}
  • {{end}} {{range .OpenIDs}} diff --git a/templates/status/404.tmpl b/templates/status/404.tmpl index 289b9ea65..9e961e1b8 100644 --- a/templates/status/404.tmpl +++ b/templates/status/404.tmpl @@ -1,5 +1,5 @@ {{template "base/head" .}} -
    +
    {{if .IsRepo}}{{template "repo/header" .}}{{end}}

    404

    diff --git a/templates/status/500.tmpl b/templates/status/500.tmpl index d0c874614..c04b4af80 100644 --- a/templates/status/500.tmpl +++ b/templates/status/500.tmpl @@ -1,5 +1,5 @@ {{/* This page should only depend the minimal template functions/variables, to avoid triggering new panics. -* base template functions: AppName, AssetUrlPrefix, AssetVersion, AppSubUrl, ThemeName, Str2html +* base template functions: AppName, AssetUrlPrefix, AssetVersion, AppSubUrl, ThemeName, SanitizeHTML * ctx.Locale * .Flash * .ErrorMsg @@ -45,7 +45,7 @@ {{end}}
    {{if or .SignedUser.IsAdmin .ShowFooterVersion}}

    {{ctx.Locale.Tr "admin.config.app_ver"}}: {{AppVer}}

    {{end}} - {{if .SignedUser.IsAdmin}}

    {{ctx.Locale.Tr "error.report_message" | Str2html}}

    {{end}} + {{if .SignedUser.IsAdmin}}

    {{ctx.Locale.Tr "error.report_message" | SanitizeHTML}}

    {{end}}
    diff --git a/templates/swagger/v1_json.tmpl b/templates/swagger/v1_json.tmpl index ef292f2d6..04f71835c 100644 --- a/templates/swagger/v1_json.tmpl +++ b/templates/swagger/v1_json.tmpl @@ -12828,7 +12828,8 @@ }, "post": { "consumes": [ - "multipart/form-data" + "multipart/form-data", + "application/octet-stream" ], "produces": [ "application/json" @@ -12871,8 +12872,7 @@ "type": "file", "description": "attachment to upload", "name": "attachment", - "in": "formData", - "required": true + "in": "formData" } ], "responses": { @@ -21225,6 +21225,13 @@ "type": "object", "additionalProperties": {}, "x-go-name": "Validations" + }, + "visible": { + "type": "array", + "items": { + "$ref": "#/definitions/IssueFormFieldVisible" + }, + "x-go-name": "Visible" } }, "x-go-package": "code.gitea.io/gitea/modules/structs" @@ -21234,6 +21241,11 @@ "title": "IssueFormFieldType defines issue form field type, can be \"markdown\", \"textarea\", \"input\", \"dropdown\" or \"checkboxes\"", "x-go-package": "code.gitea.io/gitea/modules/structs" }, + "IssueFormFieldVisible": { + "description": "IssueFormFieldVisible defines issue form field visible", + "type": "string", + "x-go-package": "code.gitea.io/gitea/modules/structs" + }, "IssueLabelsOption": { "description": "IssueLabelsOption a collection of labels", "type": "object", diff --git a/templates/user/auth/finalize_openid.tmpl b/templates/user/auth/finalize_openid.tmpl index 7449e3bed..f7da41d16 100644 --- a/templates/user/auth/finalize_openid.tmpl +++ b/templates/user/auth/finalize_openid.tmpl @@ -35,7 +35,7 @@ {{if .ShowRegistrationButton}} {{end}} diff --git a/templates/user/auth/grant.tmpl b/templates/user/auth/grant.tmpl index 9c0bf33e2..d56692ccc 100644 --- a/templates/user/auth/grant.tmpl +++ b/templates/user/auth/grant.tmpl @@ -9,11 +9,11 @@ {{template "base/alert" .}}

    {{ctx.Locale.Tr "auth.authorize_application_description"}}
    - {{ctx.Locale.Tr "auth.authorize_application_created_by" .ApplicationCreatorLinkHTML | Str2html}} + {{ctx.Locale.Tr "auth.authorize_application_created_by" .ApplicationCreatorLinkHTML | SanitizeHTML}}

    -

    {{ctx.Locale.Tr "auth.authorize_redirect_notice" .ApplicationRedirectDomainHTML | Str2html}}

    +

    {{ctx.Locale.Tr "auth.authorize_redirect_notice" .ApplicationRedirectDomainHTML | SanitizeHTML}}

    diff --git a/templates/user/auth/reset_passwd.tmpl b/templates/user/auth/reset_passwd.tmpl index 2f470df44..c0bf693f4 100644 --- a/templates/user/auth/reset_passwd.tmpl +++ b/templates/user/auth/reset_passwd.tmpl @@ -34,7 +34,7 @@

    {{ctx.Locale.Tr "twofa"}}

    -
    {{ctx.Locale.Tr "settings.twofa_is_enrolled" | Str2html}}
    +
    {{ctx.Locale.Tr "settings.twofa_is_enrolled" | SanitizeHTML}}
    {{if .scratch_code}}
    @@ -53,11 +53,11 @@ {{if and .has_two_factor (not .scratch_code)}} - {{ctx.Locale.Tr "auth.use_scratch_code" | Str2html}} + {{ctx.Locale.Tr "auth.use_scratch_code" | SanitizeHTML}} {{end}}
    {{else}} -

    {{ctx.Locale.Tr "auth.invalid_code_forgot_password" (printf "%s/user/forgot_password" AppSubUrl) | Str2html}}

    +

    {{ctx.Locale.Tr "auth.invalid_code_forgot_password" (printf "%s/user/forgot_password" AppSubUrl) | SanitizeHTML}}

    {{end}}
    diff --git a/templates/user/auth/signin_inner.tmpl b/templates/user/auth/signin_inner.tmpl index 40e54ec8f..15733eb9b 100644 --- a/templates/user/auth/signin_inner.tmpl +++ b/templates/user/auth/signin_inner.tmpl @@ -48,7 +48,7 @@ {{if .ShowRegistrationButton}} {{end}} diff --git a/templates/user/auth/twofa.tmpl b/templates/user/auth/twofa.tmpl index d32511415..8a898c7dd 100644 --- a/templates/user/auth/twofa.tmpl +++ b/templates/user/auth/twofa.tmpl @@ -17,7 +17,7 @@ diff --git a/templates/user/dashboard/feeds.tmpl b/templates/user/dashboard/feeds.tmpl index 6dec610e9..0e7371ad8 100644 --- a/templates/user/dashboard/feeds.tmpl +++ b/templates/user/dashboard/feeds.tmpl @@ -7,7 +7,7 @@
    {{if gt .ActUser.ID 0}} - {{.GetDisplayName ctx}} + {{.GetActDisplayName ctx}} {{else}} {{.ShortActUserName ctx}} {{end}} diff --git a/templates/user/dashboard/milestones.tmpl b/templates/user/dashboard/milestones.tmpl index 1829021ff..737a0f7e2 100644 --- a/templates/user/dashboard/milestones.tmpl +++ b/templates/user/dashboard/milestones.tmpl @@ -141,7 +141,7 @@
    {{if .Content}}
    - {{.RenderedContent|Str2html}} + {{.RenderedContent}}
    {{end}} diff --git a/templates/user/notification/notification_subscriptions.tmpl b/templates/user/notification/notification_subscriptions.tmpl index ec40d3afe..a37f0c352 100644 --- a/templates/user/notification/notification_subscriptions.tmpl +++ b/templates/user/notification/notification_subscriptions.tmpl @@ -69,7 +69,7 @@ {{template "shared/issuelist" dict "." . "listType" "dashboard"}} {{end}} {{else}} - {{template "explore/repo_search" .}} + {{template "shared/repo_search" .}} {{template "explore/repo_list" .}} {{template "base/paginate" .}} {{end}} diff --git a/templates/user/profile.tmpl b/templates/user/profile.tmpl index ed3538909..da68d50ab 100644 --- a/templates/user/profile.tmpl +++ b/templates/user/profile.tmpl @@ -21,7 +21,7 @@ {{template "user/dashboard/feeds" .}} {{else if eq .TabName "stars"}}
    - {{template "explore/repo_search" .}} + {{template "shared/repo_search" .}} {{template "explore/repo_list" .}} {{template "base/paginate" .}}
    @@ -30,9 +30,9 @@ {{else if eq .TabName "followers"}} {{template "repo/user_cards" .}} {{else if eq .TabName "overview"}} -
    {{.ProfileReadme | Str2html}}
    +
    {{.ProfileReadme}}
    {{else}} - {{template "explore/repo_search" .}} + {{template "shared/repo_search" .}} {{template "explore/repo_list" .}} {{template "base/paginate" .}} {{end}} diff --git a/templates/user/settings/account.tmpl b/templates/user/settings/account.tmpl index c7bf3c0a4..b9dc3a9ce 100644 --- a/templates/user/settings/account.tmpl +++ b/templates/user/settings/account.tmpl @@ -134,9 +134,9 @@
    -

    {{svg "octicon-alert"}} {{ctx.Locale.Tr "settings.delete_prompt" | Str2html}}

    +

    {{svg "octicon-alert"}} {{ctx.Locale.Tr "settings.delete_prompt" | SanitizeHTML}}

    {{if .UserDeleteWithComments}} -

    {{ctx.Locale.Tr "settings.delete_with_all_comments" .UserDeleteWithCommentsMaxTime | Str2html}}

    +

    {{ctx.Locale.Tr "settings.delete_with_all_comments" .UserDeleteWithCommentsMaxTime | SanitizeHTML}}

    {{end}}
    diff --git a/templates/user/settings/keys.tmpl b/templates/user/settings/keys.tmpl index 93037e7e2..a44bf5004 100644 --- a/templates/user/settings/keys.tmpl +++ b/templates/user/settings/keys.tmpl @@ -2,6 +2,8 @@
    {{template "user/settings/keys_ssh" .}} {{template "user/settings/keys_principal" .}} + {{if not ($.UserDisabledFeatures.Contains "manage_gpg_keys")}} {{template "user/settings/keys_gpg" .}} + {{end}}
    {{template "user/settings/layout_footer" .}} diff --git a/templates/user/settings/keys_gpg.tmpl b/templates/user/settings/keys_gpg.tmpl index 981cfd810..3ab066c95 100644 --- a/templates/user/settings/keys_gpg.tmpl +++ b/templates/user/settings/keys_gpg.tmpl @@ -43,7 +43,7 @@

    {{ctx.Locale.Tr "settings.gpg_desc"}}
    - {{ctx.Locale.Tr "settings.gpg_helper" "https://docs.codeberg.org/security/gpg-key/" | Str2html}} + {{ctx.Locale.Tr "settings.gpg_helper" "https://docs.codeberg.org/security/gpg-key/" | SanitizeHTML}}

    {{range .GPGKeys}} diff --git a/templates/user/settings/keys_ssh.tmpl b/templates/user/settings/keys_ssh.tmpl index dc3179fdd..9045b6c27 100644 --- a/templates/user/settings/keys_ssh.tmpl +++ b/templates/user/settings/keys_ssh.tmpl @@ -31,7 +31,7 @@

    {{ctx.Locale.Tr "settings.ssh_desc"}}
    - {{ctx.Locale.Tr "settings.ssh_helper" "https://docs.codeberg.org/security/ssh-key/" "https://docs.github.com/en/free-pro-team@latest/github/authenticating-to-github/troubleshooting-ssh" | Str2html}} + {{ctx.Locale.Tr "settings.ssh_helper" "https://docs.codeberg.org/security/ssh-key/" "https://docs.github.com/en/free-pro-team@latest/github/authenticating-to-github/troubleshooting-ssh" | SanitizeHTML}}

    {{if .DisableSSH}} diff --git a/templates/user/settings/security/twofa.tmpl b/templates/user/settings/security/twofa.tmpl index 2f15fe13f..87cc90e47 100644 --- a/templates/user/settings/security/twofa.tmpl +++ b/templates/user/settings/security/twofa.tmpl @@ -4,7 +4,7 @@

    {{ctx.Locale.Tr "settings.twofa_desc"}}

    {{if .TOTPEnrolled}} -

    {{ctx.Locale.Tr "settings.twofa_is_enrolled" | Str2html}}

    +

    {{ctx.Locale.Tr "settings.twofa_is_enrolled" | SanitizeHTML}}

    {{.CsrfTokenHtml}}

    {{ctx.Locale.Tr "settings.regenerate_scratch_token_desc"}}

    diff --git a/templates/user/settings/security/webauthn.tmpl b/templates/user/settings/security/webauthn.tmpl index e582b801d..a7fa04a52 100644 --- a/templates/user/settings/security/webauthn.tmpl +++ b/templates/user/settings/security/webauthn.tmpl @@ -1,6 +1,6 @@

    {{ctx.Locale.Tr "settings.webauthn"}}

    -

    {{ctx.Locale.Tr "settings.webauthn_desc" | Str2html}}

    +

    {{ctx.Locale.Tr "settings.webauthn_desc" | SanitizeHTML}}

    {{ctx.Locale.Tr "settings.webauthn_key_loss_warning"}} {{ctx.Locale.Tr "settings.webauthn_alternative_tip"}}

    {{template "user/auth/webauthn_error" .}}
    diff --git a/tests/integration/api_actions_artifact_v4_test.go b/tests/integration/api_actions_artifact_v4_test.go new file mode 100644 index 000000000..f58f87684 --- /dev/null +++ b/tests/integration/api_actions_artifact_v4_test.go @@ -0,0 +1,224 @@ +// Copyright 2024 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package integration + +import ( + "bytes" + "crypto/sha256" + "encoding/hex" + "io" + "net/http" + "strings" + "testing" + "time" + + "code.gitea.io/gitea/routers/api/actions" + actions_service "code.gitea.io/gitea/services/actions" + "code.gitea.io/gitea/tests" + + "github.com/stretchr/testify/assert" + "google.golang.org/protobuf/encoding/protojson" + "google.golang.org/protobuf/reflect/protoreflect" + "google.golang.org/protobuf/types/known/timestamppb" + "google.golang.org/protobuf/types/known/wrapperspb" +) + +func toProtoJSON(m protoreflect.ProtoMessage) io.Reader { + resp, _ := protojson.Marshal(m) + buf := bytes.Buffer{} + buf.Write(resp) + return &buf +} + +func TestActionsArtifactV4UploadSingleFile(t *testing.T) { + defer tests.PrepareTestEnv(t)() + + token, err := actions_service.CreateAuthorizationToken(48, 792, 193) + assert.NoError(t, err) + + // acquire artifact upload url + req := NewRequestWithBody(t, "POST", "/twirp/github.actions.results.api.v1.ArtifactService/CreateArtifact", toProtoJSON(&actions.CreateArtifactRequest{ + Version: 4, + Name: "artifact", + WorkflowRunBackendId: "792", + WorkflowJobRunBackendId: "193", + })).AddTokenAuth(token) + resp := MakeRequest(t, req, http.StatusOK) + var uploadResp actions.CreateArtifactResponse + protojson.Unmarshal(resp.Body.Bytes(), &uploadResp) + assert.True(t, uploadResp.Ok) + assert.Contains(t, uploadResp.SignedUploadUrl, "/twirp/github.actions.results.api.v1.ArtifactService/UploadArtifact") + + // get upload url + idx := strings.Index(uploadResp.SignedUploadUrl, "/twirp/") + url := uploadResp.SignedUploadUrl[idx:] + "&comp=block" + + // upload artifact chunk + body := strings.Repeat("A", 1024) + req = NewRequestWithBody(t, "PUT", url, strings.NewReader(body)) + MakeRequest(t, req, http.StatusCreated) + + t.Logf("Create artifact confirm") + + sha := sha256.Sum256([]byte(body)) + + // confirm artifact upload + req = NewRequestWithBody(t, "POST", "/twirp/github.actions.results.api.v1.ArtifactService/FinalizeArtifact", toProtoJSON(&actions.FinalizeArtifactRequest{ + Name: "artifact", + Size: 1024, + Hash: wrapperspb.String("sha256:" + hex.EncodeToString(sha[:])), + WorkflowRunBackendId: "792", + WorkflowJobRunBackendId: "193", + })). + AddTokenAuth(token) + resp = MakeRequest(t, req, http.StatusOK) + var finalizeResp actions.FinalizeArtifactResponse + protojson.Unmarshal(resp.Body.Bytes(), &finalizeResp) + assert.True(t, finalizeResp.Ok) +} + +func TestActionsArtifactV4UploadSingleFileWrongChecksum(t *testing.T) { + defer tests.PrepareTestEnv(t)() + + token, err := actions_service.CreateAuthorizationToken(48, 792, 193) + assert.NoError(t, err) + + // acquire artifact upload url + req := NewRequestWithBody(t, "POST", "/twirp/github.actions.results.api.v1.ArtifactService/CreateArtifact", toProtoJSON(&actions.CreateArtifactRequest{ + Version: 4, + Name: "artifact-invalid-checksum", + WorkflowRunBackendId: "792", + WorkflowJobRunBackendId: "193", + })).AddTokenAuth(token) + resp := MakeRequest(t, req, http.StatusOK) + var uploadResp actions.CreateArtifactResponse + protojson.Unmarshal(resp.Body.Bytes(), &uploadResp) + assert.True(t, uploadResp.Ok) + assert.Contains(t, uploadResp.SignedUploadUrl, "/twirp/github.actions.results.api.v1.ArtifactService/UploadArtifact") + + // get upload url + idx := strings.Index(uploadResp.SignedUploadUrl, "/twirp/") + url := uploadResp.SignedUploadUrl[idx:] + "&comp=block" + + // upload artifact chunk + body := strings.Repeat("B", 1024) + req = NewRequestWithBody(t, "PUT", url, strings.NewReader(body)) + MakeRequest(t, req, http.StatusCreated) + + t.Logf("Create artifact confirm") + + sha := sha256.Sum256([]byte(strings.Repeat("A", 1024))) + + // confirm artifact upload + req = NewRequestWithBody(t, "POST", "/twirp/github.actions.results.api.v1.ArtifactService/FinalizeArtifact", toProtoJSON(&actions.FinalizeArtifactRequest{ + Name: "artifact-invalid-checksum", + Size: 1024, + Hash: wrapperspb.String("sha256:" + hex.EncodeToString(sha[:])), + WorkflowRunBackendId: "792", + WorkflowJobRunBackendId: "193", + })). + AddTokenAuth(token) + MakeRequest(t, req, http.StatusInternalServerError) +} + +func TestActionsArtifactV4UploadSingleFileWithRetentionDays(t *testing.T) { + defer tests.PrepareTestEnv(t)() + + token, err := actions_service.CreateAuthorizationToken(48, 792, 193) + assert.NoError(t, err) + + // acquire artifact upload url + req := NewRequestWithBody(t, "POST", "/twirp/github.actions.results.api.v1.ArtifactService/CreateArtifact", toProtoJSON(&actions.CreateArtifactRequest{ + Version: 4, + ExpiresAt: timestamppb.New(time.Now().Add(5 * 24 * time.Hour)), + Name: "artifactWithRetentionDays", + WorkflowRunBackendId: "792", + WorkflowJobRunBackendId: "193", + })).AddTokenAuth(token) + resp := MakeRequest(t, req, http.StatusOK) + var uploadResp actions.CreateArtifactResponse + protojson.Unmarshal(resp.Body.Bytes(), &uploadResp) + assert.True(t, uploadResp.Ok) + assert.Contains(t, uploadResp.SignedUploadUrl, "/twirp/github.actions.results.api.v1.ArtifactService/UploadArtifact") + + // get upload url + idx := strings.Index(uploadResp.SignedUploadUrl, "/twirp/") + url := uploadResp.SignedUploadUrl[idx:] + "&comp=block" + + // upload artifact chunk + body := strings.Repeat("A", 1024) + req = NewRequestWithBody(t, "PUT", url, strings.NewReader(body)) + MakeRequest(t, req, http.StatusCreated) + + t.Logf("Create artifact confirm") + + sha := sha256.Sum256([]byte(body)) + + // confirm artifact upload + req = NewRequestWithBody(t, "POST", "/twirp/github.actions.results.api.v1.ArtifactService/FinalizeArtifact", toProtoJSON(&actions.FinalizeArtifactRequest{ + Name: "artifactWithRetentionDays", + Size: 1024, + Hash: wrapperspb.String("sha256:" + hex.EncodeToString(sha[:])), + WorkflowRunBackendId: "792", + WorkflowJobRunBackendId: "193", + })). + AddTokenAuth(token) + resp = MakeRequest(t, req, http.StatusOK) + var finalizeResp actions.FinalizeArtifactResponse + protojson.Unmarshal(resp.Body.Bytes(), &finalizeResp) + assert.True(t, finalizeResp.Ok) +} + +func TestActionsArtifactV4DownloadSingle(t *testing.T) { + defer tests.PrepareTestEnv(t)() + + token, err := actions_service.CreateAuthorizationToken(48, 792, 193) + assert.NoError(t, err) + + // acquire artifact upload url + req := NewRequestWithBody(t, "POST", "/twirp/github.actions.results.api.v1.ArtifactService/ListArtifacts", toProtoJSON(&actions.ListArtifactsRequest{ + NameFilter: wrapperspb.String("artifact"), + WorkflowRunBackendId: "792", + WorkflowJobRunBackendId: "193", + })).AddTokenAuth(token) + resp := MakeRequest(t, req, http.StatusOK) + var listResp actions.ListArtifactsResponse + protojson.Unmarshal(resp.Body.Bytes(), &listResp) + assert.Len(t, listResp.Artifacts, 1) + + // confirm artifact upload + req = NewRequestWithBody(t, "POST", "/twirp/github.actions.results.api.v1.ArtifactService/GetSignedArtifactURL", toProtoJSON(&actions.GetSignedArtifactURLRequest{ + Name: "artifact", + WorkflowRunBackendId: "792", + WorkflowJobRunBackendId: "193", + })). + AddTokenAuth(token) + resp = MakeRequest(t, req, http.StatusOK) + var finalizeResp actions.GetSignedArtifactURLResponse + protojson.Unmarshal(resp.Body.Bytes(), &finalizeResp) + assert.NotEmpty(t, finalizeResp.SignedUrl) + + req = NewRequest(t, "GET", finalizeResp.SignedUrl) + resp = MakeRequest(t, req, http.StatusOK) + body := strings.Repeat("A", 1024) + assert.Equal(t, resp.Body.String(), body) +} + +func TestActionsArtifactV4Delete(t *testing.T) { + defer tests.PrepareTestEnv(t)() + + token, err := actions_service.CreateAuthorizationToken(48, 792, 193) + assert.NoError(t, err) + + // delete artifact by name + req := NewRequestWithBody(t, "POST", "/twirp/github.actions.results.api.v1.ArtifactService/DeleteArtifact", toProtoJSON(&actions.DeleteArtifactRequest{ + Name: "artifact", + WorkflowRunBackendId: "792", + WorkflowJobRunBackendId: "193", + })).AddTokenAuth(token) + resp := MakeRequest(t, req, http.StatusOK) + var deleteResp actions.DeleteArtifactResponse + protojson.Unmarshal(resp.Body.Bytes(), &deleteResp) + assert.True(t, deleteResp.Ok) +} diff --git a/tests/integration/api_releases_test.go b/tests/integration/api_releases_test.go index 5b1ab76ce..49aa4c4e1 100644 --- a/tests/integration/api_releases_test.go +++ b/tests/integration/api_releases_test.go @@ -262,24 +262,60 @@ func TestAPIUploadAssetRelease(t *testing.T) { filename := "image.png" buff := generateImg() - body := &bytes.Buffer{} - writer := multipart.NewWriter(body) - part, err := writer.CreateFormFile("attachment", filename) - assert.NoError(t, err) - _, err = io.Copy(part, &buff) - assert.NoError(t, err) - err = writer.Close() - assert.NoError(t, err) + assetURL := fmt.Sprintf("/api/v1/repos/%s/%s/releases/%d/assets", owner.Name, repo.Name, r.ID) - req := NewRequestWithBody(t, http.MethodPost, fmt.Sprintf("/api/v1/repos/%s/%s/releases/%d/assets?name=test-asset", owner.Name, repo.Name, r.ID), body). - AddTokenAuth(token) - req.Header.Add("Content-Type", writer.FormDataContentType()) - resp := MakeRequest(t, req, http.StatusCreated) + t.Run("multipart/form-data", func(t *testing.T) { + defer tests.PrintCurrentTest(t)() - var attachment *api.Attachment - DecodeJSON(t, resp, &attachment) + body := &bytes.Buffer{} - assert.EqualValues(t, "test-asset", attachment.Name) - assert.EqualValues(t, 104, attachment.Size) + writer := multipart.NewWriter(body) + part, err := writer.CreateFormFile("attachment", filename) + assert.NoError(t, err) + _, err = io.Copy(part, bytes.NewReader(buff.Bytes())) + assert.NoError(t, err) + err = writer.Close() + assert.NoError(t, err) + + req := NewRequestWithBody(t, http.MethodPost, assetURL, bytes.NewReader(body.Bytes())). + AddTokenAuth(token). + SetHeader("Content-Type", writer.FormDataContentType()) + resp := MakeRequest(t, req, http.StatusCreated) + + var attachment *api.Attachment + DecodeJSON(t, resp, &attachment) + + assert.EqualValues(t, filename, attachment.Name) + assert.EqualValues(t, 104, attachment.Size) + + req = NewRequestWithBody(t, http.MethodPost, assetURL+"?name=test-asset", bytes.NewReader(body.Bytes())). + AddTokenAuth(token). + SetHeader("Content-Type", writer.FormDataContentType()) + resp = MakeRequest(t, req, http.StatusCreated) + + var attachment2 *api.Attachment + DecodeJSON(t, resp, &attachment2) + + assert.EqualValues(t, "test-asset", attachment2.Name) + assert.EqualValues(t, 104, attachment2.Size) + }) + + t.Run("application/octet-stream", func(t *testing.T) { + defer tests.PrintCurrentTest(t)() + + req := NewRequestWithBody(t, http.MethodPost, assetURL, bytes.NewReader(buff.Bytes())). + AddTokenAuth(token) + MakeRequest(t, req, http.StatusBadRequest) + + req = NewRequestWithBody(t, http.MethodPost, assetURL+"?name=stream.bin", bytes.NewReader(buff.Bytes())). + AddTokenAuth(token) + resp := MakeRequest(t, req, http.StatusCreated) + + var attachment *api.Attachment + DecodeJSON(t, resp, &attachment) + + assert.EqualValues(t, "stream.bin", attachment.Name) + assert.EqualValues(t, 104, attachment.Size) + }) } diff --git a/tests/integration/api_repo_file_create_test.go b/tests/integration/api_repo_file_create_test.go index 0d192a1fe..41ad7211f 100644 --- a/tests/integration/api_repo_file_create_test.go +++ b/tests/integration/api_repo_file_create_test.go @@ -17,10 +17,10 @@ import ( repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/models/unittest" user_model "code.gitea.io/gitea/models/user" - "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/gitrepo" "code.gitea.io/gitea/modules/setting" api "code.gitea.io/gitea/modules/structs" + "code.gitea.io/gitea/services/context" "github.com/stretchr/testify/assert" ) diff --git a/tests/integration/api_repo_file_update_test.go b/tests/integration/api_repo_file_update_test.go index 195a1090c..ac28e0c0a 100644 --- a/tests/integration/api_repo_file_update_test.go +++ b/tests/integration/api_repo_file_update_test.go @@ -16,10 +16,10 @@ import ( repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/models/unittest" user_model "code.gitea.io/gitea/models/user" - "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/gitrepo" "code.gitea.io/gitea/modules/setting" api "code.gitea.io/gitea/modules/structs" + "code.gitea.io/gitea/services/context" "github.com/stretchr/testify/assert" ) diff --git a/tests/integration/api_repo_files_change_test.go b/tests/integration/api_repo_files_change_test.go index ab5cf19a9..fb3ae5e4d 100644 --- a/tests/integration/api_repo_files_change_test.go +++ b/tests/integration/api_repo_files_change_test.go @@ -15,10 +15,10 @@ import ( repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/models/unittest" user_model "code.gitea.io/gitea/models/user" - "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/gitrepo" "code.gitea.io/gitea/modules/setting" api "code.gitea.io/gitea/modules/structs" + "code.gitea.io/gitea/services/context" "github.com/stretchr/testify/assert" ) diff --git a/tests/integration/block_test.go b/tests/integration/block_test.go index 96e9d5d3e..8f40ed13e 100644 --- a/tests/integration/block_test.go +++ b/tests/integration/block_test.go @@ -17,8 +17,8 @@ import ( repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/models/unittest" user_model "code.gitea.io/gitea/models/user" - forgejo_context "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/translation" + forgejo_context "code.gitea.io/gitea/services/context" "code.gitea.io/gitea/tests" "github.com/stretchr/testify/assert" diff --git a/tests/integration/branches_test.go b/tests/integration/branches_test.go index 26bed8c90..e0482b6f2 100644 --- a/tests/integration/branches_test.go +++ b/tests/integration/branches_test.go @@ -12,7 +12,7 @@ import ( git_model "code.gitea.io/gitea/models/git" repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/models/unittest" - gitea_context "code.gitea.io/gitea/modules/context" + gitea_context "code.gitea.io/gitea/services/context" "github.com/stretchr/testify/assert" ) diff --git a/tests/integration/editor_test.go b/tests/integration/editor_test.go index f2b2716a8..f2f312b8a 100644 --- a/tests/integration/editor_test.go +++ b/tests/integration/editor_test.go @@ -17,10 +17,10 @@ import ( repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/models/unittest" user_model "code.gitea.io/gitea/models/user" - gitea_context "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/json" "code.gitea.io/gitea/modules/translation" + gitea_context "code.gitea.io/gitea/services/context" "code.gitea.io/gitea/tests" "github.com/stretchr/testify/assert" diff --git a/tests/integration/explore_repos_test.go b/tests/integration/explore_repos_test.go index fda376b96..26fd1dde6 100644 --- a/tests/integration/explore_repos_test.go +++ b/tests/integration/explore_repos_test.go @@ -8,7 +8,6 @@ import ( "testing" "code.gitea.io/gitea/tests" - "github.com/stretchr/testify/assert" ) func TestExploreRepos(t *testing.T) { @@ -16,16 +15,4 @@ func TestExploreRepos(t *testing.T) { req := NewRequest(t, "GET", "/explore/repos") MakeRequest(t, req, http.StatusOK) - - t.Run("Persistent parameters", func(t *testing.T) { - defer tests.PrintCurrentTest(t)() - - req := NewRequest(t, "GET", "/explore/repos?topic=1&language=Go&sort=moststars") - resp := MakeRequest(t, req, http.StatusOK) - htmlDoc := NewHTMLParser(t, resp.Body) - - assert.EqualValues(t, "moststars", htmlDoc.Find("input[type='hidden'][name='sort']").AttrOr("value", "not found")) - assert.EqualValues(t, "Go", htmlDoc.Find("input[type='hidden'][name='language']").AttrOr("value", "not found")) - assert.EqualValues(t, "true", htmlDoc.Find("input[type='hidden'][name='topic']").AttrOr("value", "not found")) - }) } diff --git a/tests/integration/explore_user_test.go b/tests/integration/explore_user_test.go new file mode 100644 index 000000000..046caf378 --- /dev/null +++ b/tests/integration/explore_user_test.go @@ -0,0 +1,44 @@ +// Copyright 2024 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package integration + +import ( + "net/http" + "testing" + + "code.gitea.io/gitea/tests" + + "github.com/stretchr/testify/assert" +) + +func TestExploreUser(t *testing.T) { + defer tests.PrepareTestEnv(t)() + + cases := []struct{ sortOrder, expected string }{ + {"", "/explore/users?sort=newest&q="}, + {"newest", "/explore/users?sort=newest&q="}, + {"oldest", "/explore/users?sort=oldest&q="}, + {"alphabetically", "/explore/users?sort=alphabetically&q="}, + {"reversealphabetically", "/explore/users?sort=reversealphabetically&q="}, + } + for _, c := range cases { + req := NewRequest(t, "GET", "/explore/users?sort="+c.sortOrder) + resp := MakeRequest(t, req, http.StatusOK) + h := NewHTMLParser(t, resp.Body) + href, _ := h.Find(`.ui.dropdown .menu a.active.item[href^="/explore/users"]`).Attr("href") + assert.Equal(t, c.expected, href) + } + + // these sort orders shouldn't be supported, to avoid leaking user activity + cases404 := []string{ + "/explore/users?sort=lastlogin", + "/explore/users?sort=reverselastlogin", + "/explore/users?sort=leastupdate", + "/explore/users?sort=reverseleastupdate", + } + for _, c := range cases404 { + req := NewRequest(t, "GET", c).SetHeader("Accept", "text/html") + MakeRequest(t, req, http.StatusNotFound) + } +} diff --git a/tests/integration/forgejo_confirmation_repo_test.go b/tests/integration/forgejo_confirmation_repo_test.go index c63d0ae75..53bd32f1a 100644 --- a/tests/integration/forgejo_confirmation_repo_test.go +++ b/tests/integration/forgejo_confirmation_repo_test.go @@ -8,8 +8,8 @@ import ( "net/http/httptest" "testing" - gitea_context "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/translation" + gitea_context "code.gitea.io/gitea/services/context" "code.gitea.io/gitea/tests" "github.com/stretchr/testify/assert" diff --git a/tests/integration/git_test.go b/tests/integration/git_test.go index ff5421d93..e0a824671 100644 --- a/tests/integration/git_test.go +++ b/tests/integration/git_test.go @@ -25,12 +25,12 @@ import ( repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/models/unittest" user_model "code.gitea.io/gitea/models/user" - gitea_context "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/gitrepo" "code.gitea.io/gitea/modules/lfs" "code.gitea.io/gitea/modules/setting" api "code.gitea.io/gitea/modules/structs" + gitea_context "code.gitea.io/gitea/services/context" files_service "code.gitea.io/gitea/services/repository/files" "code.gitea.io/gitea/tests" diff --git a/tests/integration/integration_test.go b/tests/integration/integration_test.go index 33e507e5c..0a2003447 100644 --- a/tests/integration/integration_test.go +++ b/tests/integration/integration_test.go @@ -30,7 +30,6 @@ import ( unit_model "code.gitea.io/gitea/models/unit" "code.gitea.io/gitea/models/unittest" user_model "code.gitea.io/gitea/models/user" - gitea_context "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/graceful" "code.gitea.io/gitea/modules/json" @@ -40,6 +39,7 @@ import ( "code.gitea.io/gitea/modules/util" "code.gitea.io/gitea/modules/web" "code.gitea.io/gitea/routers" + gitea_context "code.gitea.io/gitea/services/context" repo_service "code.gitea.io/gitea/services/repository" files_service "code.gitea.io/gitea/services/repository/files" user_service "code.gitea.io/gitea/services/user" diff --git a/tests/integration/mirror_push_test.go b/tests/integration/mirror_push_test.go index 4263f12f9..7fb6414b4 100644 --- a/tests/integration/mirror_push_test.go +++ b/tests/integration/mirror_push_test.go @@ -15,10 +15,10 @@ import ( repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/models/unittest" user_model "code.gitea.io/gitea/models/user" - gitea_context "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/gitrepo" "code.gitea.io/gitea/modules/setting" + gitea_context "code.gitea.io/gitea/services/context" doctor "code.gitea.io/gitea/services/doctor" "code.gitea.io/gitea/services/migrations" mirror_service "code.gitea.io/gitea/services/mirror" diff --git a/tests/integration/pull_reopen_test.go b/tests/integration/pull_reopen_test.go index 51f208794..a4be38ab6 100644 --- a/tests/integration/pull_reopen_test.go +++ b/tests/integration/pull_reopen_test.go @@ -18,9 +18,9 @@ import ( unit_model "code.gitea.io/gitea/models/unit" "code.gitea.io/gitea/models/unittest" user_model "code.gitea.io/gitea/models/user" - gitea_context "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/translation" + gitea_context "code.gitea.io/gitea/services/context" issue_service "code.gitea.io/gitea/services/issue" pull_service "code.gitea.io/gitea/services/pull" repo_service "code.gitea.io/gitea/services/repository" diff --git a/tests/integration/repo_settings_test.go b/tests/integration/repo_settings_test.go index 307614815..771aa9ad8 100644 --- a/tests/integration/repo_settings_test.go +++ b/tests/integration/repo_settings_test.go @@ -14,8 +14,8 @@ import ( unit_model "code.gitea.io/gitea/models/unit" "code.gitea.io/gitea/models/unittest" user_model "code.gitea.io/gitea/models/user" - gitea_context "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/setting" + gitea_context "code.gitea.io/gitea/services/context" repo_service "code.gitea.io/gitea/services/repository" "code.gitea.io/gitea/tests" diff --git a/tests/integration/repofiles_change_test.go b/tests/integration/repofiles_change_test.go index 19fbd1754..49abeb83f 100644 --- a/tests/integration/repofiles_change_test.go +++ b/tests/integration/repofiles_change_test.go @@ -12,11 +12,11 @@ import ( repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/models/unittest" - "code.gitea.io/gitea/modules/contexttest" "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/gitrepo" "code.gitea.io/gitea/modules/setting" api "code.gitea.io/gitea/modules/structs" + "code.gitea.io/gitea/services/contexttest" files_service "code.gitea.io/gitea/services/repository/files" "github.com/stretchr/testify/assert" diff --git a/web_src/css/base.css b/web_src/css/base.css index bb45c8d32..976f2f9f3 100644 --- a/web_src/css/base.css +++ b/web_src/css/base.css @@ -1587,7 +1587,7 @@ a.ui.active.label:hover { .lines-commit { vertical-align: top; - color: var(--color-grey); + color: var(--color-text-light-2); padding: 0 !important; background: var(--color-code-sidebar-bg); width: 1%; @@ -1630,6 +1630,10 @@ a.ui.active.label:hover { border-top: 1px solid var(--color-secondary); } +.code-view tr.top-line-blame:first-of-type { + border-top: none; +} + .lines-code .bottom-line, .lines-commit .bottom-line { border-bottom: 1px solid var(--color-secondary); diff --git a/web_src/css/helpers.css b/web_src/css/helpers.css index da94ebb48..3579c193b 100644 --- a/web_src/css/helpers.css +++ b/web_src/css/helpers.css @@ -73,12 +73,6 @@ Gitea's private styles use `g-` prefix. .gt-overflow-x-scroll { overflow-x: scroll !important; } .gt-overflow-y-hidden { overflow-y: hidden !important; } -.gt-h-screen { height: 100vh !important; } -.gt-h-full { height: 100% !important; } -.gt-w-auto { width: auto !important; } -.gt-w-screen { width: 100vw !important; } -.gt-w-full { width: 100% !important; } - .gt-float-left { float: left !important; } .gt-float-right { float: right !important; } .gt-clear-both { clear: both !important; } diff --git a/web_src/css/modules/button.css b/web_src/css/modules/button.css index b772a4c14..3c80eb99c 100644 --- a/web_src/css/modules/button.css +++ b/web_src/css/modules/button.css @@ -87,6 +87,13 @@ It needs some tricks to tweak the left/right borders with active state */ box-shadow: none; } +/* apply the vertical padding of .compact to non-compact buttons when they contain a svg as they + would otherwise appear too large. Seen on "RSS Feed" button on repo releases tab. */ +.ui.small.button:not(.compact):has(.svg) { + padding-top: 0.58928571em; + padding-bottom: 0.58928571em; +} + .ui.labeled.button.disabled > .button, .ui.basic.buttons .button, .ui.basic.button { diff --git a/web_src/css/themes/theme-gitea-dark.css b/web_src/css/themes/theme-gitea-dark.css index bac002e3d..ac77b7bbd 100644 --- a/web_src/css/themes/theme-gitea-dark.css +++ b/web_src/css/themes/theme-gitea-dark.css @@ -3,72 +3,72 @@ :root { --is-dark-theme: true; - --color-primary: #87ab63; + --color-primary: #4183c4; --color-primary-contrast: #ffffff; - --color-primary-dark-1: #93b373; - --color-primary-dark-2: #9fbc82; - --color-primary-dark-3: #abc492; - --color-primary-dark-4: #b7cda1; - --color-primary-dark-5: #cfddc1; - --color-primary-dark-6: #e7eee0; - --color-primary-dark-7: #f8faf6; - --color-primary-light-1: #7a9e55; - --color-primary-light-2: #6c8c4c; - --color-primary-light-3: #5f7b42; - --color-primary-light-4: #516939; - --color-primary-light-5: #364626; - --color-primary-light-6: #1b2313; - --color-primary-light-7: #080b06; - --color-primary-alpha-10: #87ab6319; - --color-primary-alpha-20: #87ab6333; - --color-primary-alpha-30: #87ab634b; - --color-primary-alpha-40: #87ab6366; - --color-primary-alpha-50: #87ab6380; - --color-primary-alpha-60: #87ab6399; - --color-primary-alpha-70: #87ab63b3; - --color-primary-alpha-80: #87ab63cc; - --color-primary-alpha-90: #87ab63e1; + --color-primary-dark-1: #548fca; + --color-primary-dark-2: #679cd0; + --color-primary-dark-3: #7aa8d6; + --color-primary-dark-4: #8db5dc; + --color-primary-dark-5: #b3cde7; + --color-primary-dark-6: #d9e6f3; + --color-primary-dark-7: #f4f8fb; + --color-primary-light-1: #3876b3; + --color-primary-light-2: #31699f; + --color-primary-light-3: #2b5c8b; + --color-primary-light-4: #254f77; + --color-primary-light-5: #193450; + --color-primary-light-6: #0c1a28; + --color-primary-light-7: #04080c; + --color-primary-alpha-10: #4183c419; + --color-primary-alpha-20: #4183c433; + --color-primary-alpha-30: #4183c44b; + --color-primary-alpha-40: #4183c466; + --color-primary-alpha-50: #4183c480; + --color-primary-alpha-60: #4183c499; + --color-primary-alpha-70: #4183c4b3; + --color-primary-alpha-80: #4183c4cc; + --color-primary-alpha-90: #4183c4e1; --color-primary-hover: var(--color-primary-light-1); --color-primary-active: var(--color-primary-light-2); - --color-secondary: #525767; - --color-secondary-dark-1: #5c6374; - --color-secondary-dark-2: #666e81; - --color-secondary-dark-3: #7c8497; - --color-secondary-dark-4: #8990a1; - --color-secondary-dark-5: #959cab; - --color-secondary-dark-6: #a2a8b5; - --color-secondary-dark-7: #afb4c0; - --color-secondary-dark-8: #bcc0ca; - --color-secondary-dark-9: #c9cbd4; - --color-secondary-dark-10: #d6d7de; - --color-secondary-dark-11: #e2e3e8; - --color-secondary-dark-12: #eeeff2; - --color-secondary-dark-13: #fbfbfc; - --color-secondary-light-1: #454a57; - --color-secondary-light-2: #383c47; - --color-secondary-light-3: #2c2f37; - --color-secondary-light-4: #1f2226; - --color-secondary-alpha-10: #52576719; - --color-secondary-alpha-20: #52576733; - --color-secondary-alpha-30: #5257674b; - --color-secondary-alpha-40: #52576766; - --color-secondary-alpha-50: #52576780; - --color-secondary-alpha-60: #52576799; - --color-secondary-alpha-70: #525767b3; - --color-secondary-alpha-80: #525767cc; - --color-secondary-alpha-90: #525767e1; + --color-secondary: #3f4346; + --color-secondary-dark-1: #464a4d; + --color-secondary-dark-2: #4f5356; + --color-secondary-dark-3: #5f6366; + --color-secondary-dark-4: #72767a; + --color-secondary-dark-5: #7f8488; + --color-secondary-dark-6: #8d9297; + --color-secondary-dark-7: #999ea3; + --color-secondary-dark-8: #a6abaf; + --color-secondary-dark-9: #aeb3b8; + --color-secondary-dark-10: #babfc4; + --color-secondary-dark-11: #c5cbd0; + --color-secondary-dark-12: #ced4da; + --color-secondary-dark-13: #d1d7dd; + --color-secondary-light-1: #313538; + --color-secondary-light-2: #272b2e; + --color-secondary-light-3: #1e2225; + --color-secondary-light-4: #171b1e; + --color-secondary-alpha-10: #3f434619; + --color-secondary-alpha-20: #3f434633; + --color-secondary-alpha-30: #3f43464b; + --color-secondary-alpha-40: #3f434666; + --color-secondary-alpha-50: #3f434680; + --color-secondary-alpha-60: #3f434699; + --color-secondary-alpha-70: #3f4346b3; + --color-secondary-alpha-80: #3f4346cc; + --color-secondary-alpha-90: #3f4346e1; --color-secondary-button: var(--color-secondary-dark-4); --color-secondary-hover: var(--color-secondary-dark-3); --color-secondary-active: var(--color-secondary-dark-2); /* console colors - used for actions console and console files */ - --color-console-fg: #eeeff2; - --color-console-fg-subtle: #959cab; - --color-console-bg: #262936; - --color-console-border: #383c47; + --color-console-fg: #d9dde2; + --color-console-fg-subtle: #95989c; + --color-console-bg: #1c2023; + --color-console-border: #272b2e; --color-console-hover-bg: #ffffff16; - --color-console-active-bg: #454a57; - --color-console-menu-bg: #383c47; - --color-console-menu-border: #5c6374; + --color-console-active-bg: #313538; + --color-console-menu-bg: #272b2e; + --color-console-menu-border: #464a4d; /* named colors */ --color-red: #cc4848; --color-orange: #cc580c; @@ -81,7 +81,7 @@ --color-purple: #b259d0; --color-pink: #d22e8b; --color-brown: #a47252; - --color-black: #2e323e; + --color-black: #1f2326; /* light variants - produced via Sass scale-color(color, $lightness: +10%) */ --color-red-light: #d15a5a; --color-orange-light: #f6a066; @@ -94,7 +94,7 @@ --color-purple-light: #ba6ad5; --color-pink-light: #d74397; --color-brown-light: #b08061; - --color-black-light: #3f4555; + --color-black-light: #46494d; /* dark 1 variants - produced via Sass scale-color(color, $lightness: -10%) */ --color-red-dark-1: #c23636; --color-orange-dark-1: #f38236; @@ -107,7 +107,7 @@ --color-purple-dark-1: #a742c9; --color-pink-dark-1: #be297d; --color-brown-dark-1: #94674a; - --color-black-dark-1: #292d38; + --color-black-dark-1: #2c2f35; /* dark 2 variants - produced via Sass scale-color(color, $lightness: -20%) */ --color-red-dark-2: #ad3030; --color-orange-dark-2: #f16e17; @@ -120,7 +120,7 @@ --color-purple-dark-2: #9834b9; --color-pink-dark-2: #a9246f; --color-brown-dark-2: #835b42; - --color-black-dark-2: #252832; + --color-black-dark-2: #292a2e; /* ansi colors used for actions console and console files */ --color-ansi-black: var(--color-black); --color-ansi-red: var(--color-red); @@ -139,8 +139,8 @@ --color-ansi-bright-cyan: var(--color-teal-light); --color-ansi-bright-white: var(--color-console-fg); /* other colors */ - --color-grey: #505665; - --color-grey-light: #a1a6b7; + --color-grey: #3c4043; + --color-grey-light: #898e92; --color-gold: #b1983b; --color-white: #ffffff; --color-diff-removed-word-bg: #6f3333; @@ -151,7 +151,7 @@ --color-diff-removed-row-border: #634343; --color-diff-moved-row-border: #bcca6f; --color-diff-added-row-border: #314a37; - --color-diff-inactive: #353846; + --color-diff-inactive: #24282b; --color-error-border: #a04141; --color-error-bg: #522; --color-error-bg-active: #744; @@ -180,40 +180,40 @@ --color-orange-badge-hover-bg: #f2711c4d; --color-git: #f05133; /* target-based colors */ - --color-body: #2e323e; - --color-box-header: #303340; - --color-box-body: #222733; - --color-box-body-highlight: #262b36; - --color-text-dark: #dbe0ea; - --color-text: #cbd0da; - --color-text-light: #bbbfca; - --color-text-light-1: #aaafb9; - --color-text-light-2: #9a9ea9; - --color-text-light-3: #8a8e99; - --color-footer: #232834; - --color-timeline: #4c525e; - --color-input-text: #dfe3ec; - --color-input-background: #1e252e; - --color-input-toggle-background: #454a57; + --color-body: #1f2326; + --color-box-header: #202427; + --color-box-body: #191d20; + --color-box-body-highlight: #1d2124; + --color-text-dark: #f8f8f9; + --color-text: #ced2d5; + --color-text-light: #bec4c8; + --color-text-light-1: #acb3b8; + --color-text-light-2: #8d969c; + --color-text-light-3: #747f87; + --color-footer: var(--color-nav-bg); + --color-timeline: #383c3f; + --color-input-text: var(--color-text-dark); + --color-input-background: #161a1d; + --color-input-toggle-background: #313538; --color-input-border: var(--color-secondary); --color-input-border-hover: var(--color-secondary-dark-1); - --color-header-wrapper: #202430; + --color-header-wrapper: #191d20; --color-light: #00000028; --color-light-mimic-enabled: rgba(0, 0, 0, calc(40 / 255 * 222 / 255 / var(--opacity-disabled))); --color-light-border: #ffffff28; --color-hover: #ffffff19; --color-active: #ffffff24; - --color-menu: #1e252e; - --color-card: #1e252e; + --color-menu: #161a1d; + --color-card: #161a1d; --color-markup-table-row: #ffffff06; --color-markup-code-block: #ffffff16; - --color-button: #1e252e; - --color-code-bg: #222733; - --color-code-sidebar-bg: #232834; + --color-button: #161a1d; + --color-code-bg: #191d20; + --color-code-sidebar-bg: #1b1f22; --color-shadow: #00000058; - --color-secondary-bg: #2a2e3a; - --color-expand-button: #3c404d; - --color-placeholder-text: #8a8e99; + --color-secondary-bg: #2f3135; + --color-expand-button: #414348; + --color-placeholder-text: var(--color-text-light-3); --color-editor-line-highlight: var(--color-primary-light-5); --color-project-board-bg: var(--color-secondary-light-2); --color-project-board-dark-label: #111111; @@ -224,13 +224,13 @@ --color-reaction-active-bg: var(--color-primary-light-5); --color-tooltip-text: #ffffff; --color-tooltip-bg: #000000f0; - --color-nav-bg: #232834; - --color-nav-hover-bg: #383c47; + --color-nav-bg: #1b1f22; + --color-nav-hover-bg: #272b2e; --color-nav-text: var(--color-text); - --color-label-text: #dfe3ec; - --color-label-bg: #7c84974b; - --color-label-hover-bg: #7c8497a0; - --color-label-active-bg: #7c8497ff; + --color-label-text: var(--color-text); + --color-label-bg: #7a7f834b; + --color-label-hover-bg: #7a7f83a0; + --color-label-active-bg: #7a7f83ff; --color-accent: var(--color-primary-light-1); --color-small-accent: var(--color-primary-light-5); --color-active-line: #534d1b; diff --git a/web_src/css/themes/theme-gitea-light.css b/web_src/css/themes/theme-gitea-light.css index ca5d15cd2..5c375712d 100644 --- a/web_src/css/themes/theme-gitea-light.css +++ b/web_src/css/themes/theme-gitea-light.css @@ -190,9 +190,9 @@ --color-text-light-1: #6a6a6a; --color-text-light-2: #808080; --color-text-light-3: #a0a0a0; - --color-footer: #ffffff; + --color-footer: var(--color-nav-bg); --color-timeline: #ececec; - --color-input-text: #212121; + --color-input-text: var(--color-text-dark); --color-input-background: #fafafa; --color-input-toggle-background: #dedede; --color-input-border: var(--color-secondary); @@ -213,7 +213,7 @@ --color-shadow: #00000026; --color-secondary-bg: #f4f4f4; --color-expand-button: #d8efff; - --color-placeholder-text: #aaa; + --color-placeholder-text: var(--color-text-light-3); --color-editor-line-highlight: var(--color-primary-light-6); --color-project-board-bg: var(--color-secondary-light-4); --color-project-board-dark-label: #111111; @@ -227,7 +227,7 @@ --color-nav-bg: #ffffff; --color-nav-hover-bg: #ebebeb; --color-nav-text: var(--color-text); - --color-label-text: #232323; + --color-label-text: var(--color-text); --color-label-bg: #cacaca5b; --color-label-hover-bg: #cacacaa0; --color-label-active-bg: #cacacaff; diff --git a/web_src/js/bootstrap.js b/web_src/js/bootstrap.js index e46c91e5e..c0047b0ac 100644 --- a/web_src/js/bootstrap.js +++ b/web_src/js/bootstrap.js @@ -1,5 +1,6 @@ // DO NOT IMPORT window.config HERE! -// to make sure the error handler always works, we should never import `window.config`, because some user's custom template breaks it. +// to make sure the error handler always works, we should never import `window.config`, because +// some user's custom template breaks it. // This sets up the URL prefix used in webpack's chunk loading. // This file must be imported before any lazy-loading is being attempted. @@ -26,29 +27,42 @@ export function showGlobalErrorMessage(msg) { } /** - * @param {ErrorEvent} e + * @param {ErrorEvent|PromiseRejectionEvent} event - Event + * @param {string} event.message - Only present on ErrorEvent + * @param {string} event.error - Only present on ErrorEvent + * @param {string} event.type - Only present on ErrorEvent + * @param {string} event.filename - Only present on ErrorEvent + * @param {number} event.lineno - Only present on ErrorEvent + * @param {number} event.colno - Only present on ErrorEvent + * @param {string} event.reason - Only present on PromiseRejectionEvent + * @param {number} event.promise - Only present on PromiseRejectionEvent */ -function processWindowErrorEvent(e) { - const err = e.error ?? e.reason; +function processWindowErrorEvent({error, reason, message, type, filename, lineno, colno}) { + const err = error ?? reason; const assetBaseUrl = String(new URL(__webpack_public_path__, window.location.origin)); + const {runModeIsProd} = window.config ?? {}; - // error is likely from browser extension or inline script. Do not show these in production builds. - if (!err.stack?.includes(assetBaseUrl) && window.config?.runModeIsProd) return; - - let message; - if (e.type === 'unhandledrejection') { - message = `JavaScript promise rejection: ${err.message}.`; - } else { - message = `JavaScript error: ${e.message} (${e.filename} @ ${e.lineno}:${e.colno}).`; + // `error` and `reason` are not guaranteed to be errors. If the value is falsy, it is likly a + // non-critical event from the browser. We log them but don't show them to users. Examples: + // - https://developer.mozilla.org/en-US/docs/Web/API/ResizeObserver#observation_errors + // - https://github.com/mozilla-mobile/firefox-ios/issues/10817 + // - https://github.com/go-gitea/gitea/issues/20240 + if (!err) { + if (message) console.error(new Error(message)); + if (runModeIsProd) return; } - if (!e.error && e.lineno === 0 && e.colno === 0 && e.filename === '' && window.navigator.userAgent.includes('FxiOS/')) { - // At the moment, Firefox (iOS) (10x) has an engine bug. See https://github.com/go-gitea/gitea/issues/20240 - // If a script inserts a newly created (and content changed) element into DOM, there will be a nonsense error event reporting: Script error: line 0, col 0. - return; // ignore such nonsense error event + // If the error stack trace does not include the base URL of our script assets, it likely came + // from a browser extension or inline script. Do not show such errors in production. + if (err instanceof Error && !err.stack?.includes(assetBaseUrl) && runModeIsProd) { + return; } - showGlobalErrorMessage(`${message} Open browser console to see more details.`); + let msg = err?.message ?? message; + if (lineno) msg += ` (${filename} @ ${lineno}:${colno})`; + const dot = msg.endsWith('.') ? '' : '.'; + const renderedType = type === 'unhandledrejection' ? 'promise rejection' : type; + showGlobalErrorMessage(`JavaScript ${renderedType}: ${msg}${dot} Open browser console to see more details.`); } function initGlobalErrorHandler() { @@ -59,13 +73,14 @@ function initGlobalErrorHandler() { if (!window.config) { showGlobalErrorMessage(`Gitea JavaScript code couldn't run correctly, please check your custom templates`); } - // we added an event handler for window error at the very beginning of
    + {{template "repo/latest_commit" .}} {{if .LatestCommit}}{{if .LatestCommit.Committer}}{{TimeSince .LatestCommit.Committer.When ctx.Locale}}{{end}}{{end}}