Compare commits

...

610 Commits

Author SHA1 Message Date
Lunny Xiao
6d3c6741ec Fix notify watch failure when the content is too long (#34233)
Fix #28193

---------

Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2025-04-20 02:49:57 +00:00
Eric Hawicz
166ec1b4c3 Add "--fullname" arg to gitea admin user create (#34241)
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2025-04-19 23:36:30 +08:00
wxiaoguang
c9aa9068b3 Fix various UI problems (#34243)
Also fix #34242
2025-04-19 08:43:22 +00:00
D
eda6d65818 markup: improve code block readability and isolate copy button (#34009)
Fix #33197

Improve the rendering of code blocks in markdown content 
for better readability and UI stability across screen sizes.

Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2025-04-19 05:53:39 +00:00
Kemal Zebari
f0544dbfca Don't assume the default wiki branch is master in the wiki API (#34244)
Resolves #34218.

In the recent past, the default wiki branch was made to be changeable.
This change reflects this.
2025-04-19 03:13:00 +00:00
GiteaBot
8b7c0d8f8d [skip ci] Updated translations via Crowdin 2025-04-19 00:32:56 +00:00
Kerwin Bryant
aeb7005245 Optimize the calling code of queryElems (#34235) 2025-04-19 08:17:07 +08:00
ChristopherHX
21b43fce08 Actions Runner rest api (#33873)
Implements runner apis based on
https://docs.github.com/en/rest/actions/self-hosted-runners?apiVersion=2022-11-28#list-self-hosted-runners-for-an-organization

- Add Post endpoints for registration-token, google/go-github revealed
this as problem
  - We should deprecate Get Endpoints, leaving them for compatibility
- Get endpoint of admin has api path /admin/runners/registration-token
that feels wrong, /admin/actions/runners/registration-token seems more
consistent with user/org/repo api
- Get Runner Api
- List Runner Api
- Delete Runner Api

- Tests admin / user / org / repo level endpoints

Related to #33750 (implements point 1 and 2)
Via needs discovered in #32461, this runner api is needed to allow
cleanup of runners that are deallocated without user interaction.

---------

Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2025-04-18 15:22:41 +00:00
wxiaoguang
ba0deab616 Fix some trivial problems (#34237)
1. Using existing "content" variable in `swift.go`
2. Do not report 500 server error in `GetPullDiffStats` middleware,
otherwise a PR missing ref won't be able to view.
3. Fix the abused "label button" when listing commits, there was too
much padding space, see the screenshot below.
2025-04-18 22:56:50 +08:00
Wolfgang Reithmeier
2683adfcb4 Swift files can be passed either as file or as form value (#34068)
Fix #33990

---------

Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2025-04-18 20:09:56 +08:00
Kerwin Bryant
dd0caf7e16 Fix various misalignments and overflows (#34227)
---------

Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2025-04-17 10:32:41 +00:00
Lunny Xiao
42f45f1489 Update net package (#34228) 2025-04-17 06:06:58 -04:00
Kerwin Bryant
bde014e46d Fix button alignments and remove unnecessary styles (#34206)
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2025-04-16 08:14:10 +00:00
badhezi
a4f22a3e80 Fix project board links to related Pull Requests (#34213)
Resolves https://github.com/go-gitea/gitea/issues/34181
2025-04-16 07:31:33 +00:00
Kerwin Bryant
e8c42ae601 Fix empty repo clone panel border (#34219)
Remove duplicate border

---------

Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2025-04-16 07:05:40 +00:00
Hyungsub (Danny) Kim
dcfa42dd8f Fix: quoted replies incorrectly render user input as part of the quote (#34216)
Updated the quote insertion logic so that it adds one more line break
(`\n`) work like Github. This way, the cursor lands on a new line and
the user's reply is no longer interpreted as part of the quote.

Fixes #34177
2025-04-16 14:32:58 +08:00
GiteaBot
f1cd90d3bd [skip ci] Updated translations via Crowdin 2025-04-16 00:35:25 +00:00
Kerwin Bryant
3a651cfd02 Fix two missed null value checks on the wiki page. (#34205)
before:

![image](https://github.com/user-attachments/assets/83e5513f-a4fa-406d-a010-8ec8cd873203)

after:

![image](https://github.com/user-attachments/assets/6bca76c7-0445-429a-92b1-1a9f96d6daca)
2025-04-15 09:54:29 -07:00
wxiaoguang
d2d381fd4b Improve "lock conversation" UI (#34207)
Fix #34203
2025-04-15 15:01:12 +00:00
Kerwin Bryant
2b99a58f54 Mark parent directory as viewed when all files are viewed (#33958)
Fix #25644 

---------

Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2025-04-15 22:35:22 +08:00
bytedream
18a673bad1 Restore form inputs on organization create error (#34201)
Keeps the entered inputs when the "organization create" request
returns an error.

Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2025-04-15 08:21:51 +00:00
Kerwin Bryant
421d0e5849 Align User Details Page Header Layout with Design Specifications (#34192) 2025-04-15 01:16:33 -04:00
techknowlogick
3b5aaa836e bump vite to 6.2.6 (#34202) 2025-04-15 00:33:07 +00:00
Meng Zhuo
921d3a394d feat: add riscv64 support (#34199) 2025-04-14 16:32:54 +00:00
Kerwin Bryant
33df23c1f0 Update RepoContributors.vue (#34194) 2025-04-14 14:51:49 +00:00
Rowan Bohde
c57304ac3f Add middleware for request prioritization (#33951)
This adds a middleware for overload protection that is intended to help protect against malicious scrapers.
It does this via [`codel`](https://github.com/bohde/codel), which will perform the following:

1. Limit the number of in-flight requests to some user-defined max
2. When in-flight requests have reached their begin queuing requests.
    Logged-in requests having priority above logged-out requests
3. Once a request has been queued for too long,
    it has a probabilistic chance to be rejected based on how overloaded the entire system is.

When a server experiences more traffic than it can handle,
this keeps latency low for logged-in users and rejects just
enough requests from logged-out users to not overload the service.

---------

Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
Co-authored-by: Giteabot <teabot@gitea.io>
2025-04-14 16:25:48 +02:00
Kerwin Bryant
3a9fcac11b Update protected_branch.tmpl (#34193)
Show correct message for new/edit. Add "required" to rule name.

---------

Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2025-04-14 13:41:00 +00:00
wxiaoguang
58a3952458 Fix package upload temp path (#34196)
Fix #34195

The temp dir should be created when it is used.
2025-04-14 18:55:02 +08:00
Lunny Xiao
f6474cf2e9 Fix bug when migrating repository (#34182)
This PR fixed a bug which is a regression from #31035
2025-04-14 04:48:03 +00:00
TheFox0x7
8a6df00c53 fix github migration error when using multiple tokens (#34144)
Git authorization was not taking into account multiple token feature,
leading to auth failures

Closes: https://github.com/go-gitea/gitea/issues/34141

---------

Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2025-04-13 23:20:14 +00:00
KN4CK3R
bec9233c29 Add package version api endpoints (#34173)
Fixes #33544

Adds two new api endpoints to list a versions of a package and to get
the latest version of a package by API.

⚠️ BREAKING ⚠️ 
the `size` field for this endpoint changes from `Size` to `size`.
2025-04-13 20:00:44 +00:00
wxiaoguang
34349c085c Fix incorrect file links (#34189)
Fix #34188

The name "FileName" is ambiguous: sometimes it is "base name without
path", sometimes it is "full name with path".

The ambiguous name causes various problems.

This PR clarifies the usage: `FileTreePath`: the full name with path.
2025-04-13 12:27:31 -07:00
KN4CK3R
a2651c14ce Add cache for common package queries (#22491)
This adds a cache for common package queries in `GetPackageDescriptor`.
Code which needs to process a list of packages benefits from this
change. This skips 350 queries in the package integration tests for
example.

---------

Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2025-04-13 09:40:36 +00:00
Tomeamis
4dca869ed1 Allow admins and org owners to change org member public status (#28294)
Allows admins and org owners to change org member public status.

Before, this would return `Error 403: Cannot publicize another member`
despite the fact that the same user could make the same change through
the GUI.

Fixes #28372

---------

Co-authored-by: Tomáš Ženčák <zencak@ica.cz>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2025-04-13 08:07:29 +00:00
Kerwin Bryant
d0688cb2b3 Fix span svg layout (#34185) 2025-04-13 12:44:57 +08:00
hiifong
aada0370e7 fix webhook url (#34186)
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2025-04-13 02:24:32 +00:00
Kerwin Bryant
f4196a8843 Optimize overflow-menu (#34183)
Optimized the overflow-menu:
1. Close the tippy when a menu item inside the tippy is clicked.
2. When a menu item inside the tippy is selected, move the active state
of the menu to the tippy's button.

---------

Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2025-04-13 01:59:36 +00:00
Lunny Xiao
93a2def96b Move and rename UpdateRepository (#34136) 2025-04-12 18:22:18 +00:00
Kerwin Bryant
5015992db5 Update milestones.tmpl (#34184) 2025-04-12 11:34:42 +08:00
GiteaBot
7a587bc2d3 [skip ci] Updated translations via Crowdin 2025-04-12 00:33:41 +00:00
Lunny Xiao
ae0af8ea5b Refactor Git Attribute & performance optimization (#34154)
This PR moved git attributes related code to `modules/git/attribute` sub
package and moved language stats related code to
`modules/git/languagestats` sub package to make it easier to maintain.

And it also introduced a performance improvement which use the `git
check-attr --source` which can be run in a bare git repository so that
we don't need to create a git index file. The new parameter need a git
version >= 2.40 . If git version less than 2.40, it will fall back to
previous implementation.

---------

Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
Co-authored-by: yp05327 <576951401@qq.com>
2025-04-11 21:41:29 +08:00
GiteaBot
d725b78824 [skip ci] Updated translations via Crowdin 2025-04-11 00:34:55 +00:00
Allen Conlon
4a3ab5a2cd fix(#33711): cross-publish docker images to ghcr.io (#34148)
This PR will cross-publish the release, rc, and nightly images from
`docker.io` to `ghcr.io` as docker hub has imposed rate-limiting

Signed-off-by: Allen Conlon <software@conlon.dev>
2025-04-10 19:39:37 +00:00
Exploding Dragon
4ddf94dee5 refactor organization menu (#33928)
Fix missing items in organization menu.

**Menu**

<details>
<summary>Show</summary>

Before:

![](https://github.com/user-attachments/assets/bcbce97e-84de-44ea-9889-a664979433cd)

After:

![](https://github.com/user-attachments/assets/a169e00f-5212-4733-af9e-e8676ad74376)

</details>

**Packages**

<details>

 keep it consistent with the other pages.

<summary>Show</summary>

Before:

![](https://github.com/user-attachments/assets/170d7b3d-ecac-49b9-8296-44d0b0f2b191)

After:

![](https://github.com/user-attachments/assets/9c3c6915-870c-48cc-8a35-3d615a27d36d)

</details>

---------

Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2025-04-10 12:12:55 -07:00
Thomas E Lackey
fa49cd719f feat: Add sorting by exclusive labels (issue priority) (#33206)
Fix #2616

This PR adds a new sort option for exclusive labels.

For exclusive labels, a new property is exposed called "order", while in
the UI options are populated automatically in the `Sort` column (see
screenshot below) for each exclusive label scope.

---------

Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2025-04-10 17:18:07 +00:00
Kerwin Bryant
02e49a0f47 Fix vertical centering of file tree icons and use entryIcon for submodules/symlinks (#34137)
In the file tree, the icons are not vertically centered, which affects
the overall visual consistency.
Currently, the icons of submodules and symlinks do not adopt the value
of entryIcon, resulting in inconsistent icon display.

before:
![3000-gogitea-gitea-y4ulxr46c4k ws-us118 gitpod io_test_test
gitea_src_branch_main_README md
(3)](https://github.com/user-attachments/assets/d521b89f-909a-43f9-8f39-787b0243b159)

after:
![3000-gogitea-gitea-y4ulxr46c4k ws-us118 gitpod io_test_test
gitea_src_branch_main_README md
(2)](https://github.com/user-attachments/assets/4866807f-c890-4709-b595-7086011e5231)

---------

Co-authored-by: silverwind <me@silverwind.io>
2025-04-09 18:10:16 -07:00
ManInDark
fac6b87dd2 bugfix check for alternate ssh host certificate location (#34146)
fixes #34145

Edited all locations to actually be correct.

---------

Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
Co-authored-by: Giteabot <teabot@gitea.io>
2025-04-09 22:21:54 +03:00
Lunny Xiao
4a5af4edca Cache GPG keys, emails and users when list commits (#34086)
When list commits, some of the commits authors are the same at many
situations. But current logic will always fetch the same GPG keys from
database. This PR will cache the GPG keys, emails and users for the
context so that reducing the database queries.

---------

Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2025-04-09 16:34:38 +00:00
wxiaoguang
f8edc29f5d Set MERMAID_MAX_SOURCE_CHARACTERS to 50000 (#34152)
Fix #32015
2025-04-09 07:52:01 +00:00
Will Kelly
1b2d8df13d remove hardcoded 'code' string in clone_panel.tmpl (#34153)
This commit replaces the hardcoded string "code" in the clone panel
button with the i18n local for repo.code.
2025-04-09 06:34:50 +00:00
GiteaBot
c0898f7ed9 [skip ci] Updated translations via Crowdin 2025-04-09 00:34:55 +00:00
Lunny Xiao
32b97b3ce8 Uniform all temporary directories and allow customizing temp path (#32352)
This PR uniform all temporary directory usage so that it will be easier
to manage.

Relate to #31792 

- [x] Added a new setting to allow users to configure the global
temporary directory.
- [x] Move all temporary files and directories to be placed under
os.Temp()/gitea.
- [x] `setting.Repository.Local.LocalCopyPath` now will be
`setting.TempPath/local-repo` and the customized path is removed.
```diff
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-;[repository.local]
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-;;
-;; Path for local repository copy. Defaults to  TEMP_PATH + `local-repo`, this is deprecated and cannot be changed
-;LOCAL_COPY_PATH = local-repo
```

- [x] `setting.Repository.Upload.TempPath` now will be
`settting.TempPath/uploads` and the customized path is removed.
```diff
;[repository.upload]
-;;
-;; Path for uploads. Defaults to TEMP_PATH + `uploads`
-;TEMP_PATH = uploads
```

- [x] `setting.Packages.ChunkedUploadPath` now will be
`settting.TempPath/package-upload` and the customized path is removed.
```diff
;[packages]
-;;
-;; Path for chunked uploads. Defaults it's `package-upload` under `TEMP_PATH` unless it's an absolute path.
-;CHUNKED_UPLOAD_PATH = package-upload
```

- [x] `setting.SSH.KeyTestPath` now will be
`settting.TempPath/ssh_key_test` and the customized path is removed.
```diff
[server]
-;;
-;; Directory to create temporary files in when testing public keys using ssh-keygen,
-;; default is the system temporary directory.
-;SSH_KEY_TEST_PATH =
```

TODO:
- [ ] setting.PprofDataPath haven't been changed because it may need to
be kept until somebody read it but temp path may be clean up any time.

---------

Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2025-04-08 16:15:28 +00:00
DrMaxNix
fd7c364ca6 Check user/org repo limit instead of doer (#34147)
This PR tries to finally fix the bug mentioned in #30011 and #15504,
where the user repo limit is checked when creating a repo in an
organization.

Fix #30011

---------

Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
Co-authored-by: TheFox0x7 <thefox0x7@gmail.com>
2025-04-07 23:45:31 -07:00
Lunny Xiao
a100ac3306 Rework create/fork/adopt/generate repository to make sure resources will be cleanup once failed (#31035)
Fix #28144 

To make the resources will be cleanup once failed. All repository
operations now follow a consistent pattern:

- 1. Create a database record for the repository with the status
being_migrated.
- 2. Register a deferred cleanup function to delete the repository and
its related data if the operation fails.
- 3.	Perform the actual Git and database operations step by step.
- 4. Upon successful completion, update the repository’s status to
ready.

The adopt operation is a special case — if it fails, the repository on
disk should not be deleted.
2025-04-07 22:12:54 -07:00
silverwind
90b509aafb Update JS and PY deps (#34143)
- Update selected dependencies.
- Ran `make svg && git add --all`.
- Tested mermaid and swagger.
- Mark `fileicon` assets as generated so they don't spam the diff.
- Webpack is not upgraded because it has some regression.
2025-04-07 21:42:32 -07:00
wxiaoguang
07c6087878 Fix team permission (#34128)
The `team.access_mode` should be either `none` or `admin/owner`.
For non-admin team, the real permissions are provided by `team_unit`.
2025-04-08 04:15:15 +00:00
GiteaBot
8ca51abadd [skip ci] Updated translations via Crowdin 2025-04-08 00:34:12 +00:00
Bo-Yi Wu
e45450b744 docs: add Chinese translations for README files (#34132)
- Update README.md to include links to Traditional and Simplified
Chinese translations.
- Add README.zh-cn.md file containing the Simplified Chinese version of
the README.
- Add README.zh-tw.md file containing the Traditional Chinese version of
the README.
- Delete README_ZH.md file.

---------

Signed-off-by: appleboy <appleboy.tw@gmail.com>
2025-04-07 11:11:48 -07:00
Kerwin Bryant
8c9d2bdee3 Keep file tree view icons consistent with icon theme (#33921)
Fix #33914

before:
![3000-gogitea-gitea-y4ulxr46c4k ws-us118 gitpod io_test_test
gitea_src_branch_main_
gitmodules](https://github.com/user-attachments/assets/ca50eeff-cc44-4041-b01f-c0c5bdd3b6aa)

after:
![3000-gogitea-gitea-y4ulxr46c4k ws-us118 gitpod io_test_test
gitea_src_branch_main_README
md](https://github.com/user-attachments/assets/3b87fdbd-81d0-4831-8a74-4dbfcd5b6d91)

---------

Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2025-04-06 19:35:08 +00:00
wxiaoguang
bcc38eb35f Make markdown render match GitHub's behavior (#34129)
For #2246
2025-04-06 17:34:59 +00:00
wxiaoguang
3fe082a5a3 Remove dead code: RepoRef (#34131)
The RepoRef is a no-op since Refactor ref type (#33242) (Jan 14)
2025-04-06 20:08:10 +03:00
wxiaoguang
e94f8d56f1 Correctly handle submodule view and avoid throwing 500 error (#34121)
Auto-redirect for in-site links, and show 404 for external links
(to avoid open redirect or phishing)
2025-04-06 09:38:08 +00:00
wxiaoguang
a62ed19da6 Use overflow-wrap: anywhere to replace word-break: break-all (#34126) 2025-04-06 17:13:02 +08:00
wxiaoguang
e1c2d05bde Fix markdown render behaviors (#34122)
* Fix #27645
* Add config options `MATH_CODE_BLOCK_DETECTION`, problematic syntaxes
are disabled by default
* Fix #33639
    * Add config options `RENDER_OPTIONS_*`, old behaviors are kept
2025-04-05 11:56:48 +08:00
wxiaoguang
ee6929d96b Refactor dropdown ellipsis (#34123)
Remove legacy `truncated-item-container` and `truncated-item-name`.
2025-04-05 03:21:11 +00:00
Lunny Xiao
7a09bc904a Avoid creating unnecessary temporary cat file sub process (#33942)
Extract from #33934 

In the same goroutine, we should reuse the exist cat file sub process
which exist in `git.Repository` to avoid creating a unnecessary
temporary subprocess.

This PR reuse the exist cate file writer and reader in
`getCommitFromBatchReader`.
It also move `prepareLatestCommitInfo` before creating dataRc which will
hold the writer so other git operation will create a temporary cat file
subprocess.
2025-04-04 16:19:19 -07:00
Mopcho
013b2686fe Fix discord webhook 400 status code when description limit is exceeded (#34084)
Fixes [#34027](https://github.com/go-gitea/gitea/issues/34027)

Discord does not allow for description bigger than 2048 bytes. If the
description is bigger than that it will throw 400 and the event won't
appear in discord. To fix that, in the createPayload method we now slice
the description to ensure it doesn’t exceed the limit.

---------

Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2025-04-04 18:09:40 +00:00
wxiaoguang
6cee3bfa96 Refactor markup render to fix various path problems (#34114)
* Fix #33972
    * Use consistent path resolving for links and medias.
* No need to make the markup renders to resolve the paths, instead, the
paths are all correctly resolved in the "post process" step.
* Fix #33274
* Since 1.23, all paths starting with "/" are relative to current render
context (for example: the current repo branch)
* Introduce `/:root/path-relative-to-root`, then the path will be
rendered as relative to "ROOT_URL"
2025-04-04 23:45:23 +08:00
GiteaBot
e8b54d9e44 [skip ci] Updated translations via Crowdin 2025-04-04 00:33:58 +00:00
KN4CK3R
8fed70afdc Fix invalid version in RPM package path (#34112) 2025-04-03 19:00:00 +00:00
ManInDark
f8d549436e also check default ssh-cert location for host (#34099) (#34100) 2025-04-03 14:34:54 -04:00
wxiaoguang
ba921fd903 Fix markdown frontmatter rendering (#34102)
Fix #34101
2025-04-03 05:48:24 +00:00
Zettat123
f94ee4fd3c Get changed files based on merge base when checking pull_request actions trigger (#34106)
Fix #33941
2025-04-03 05:13:16 +00:00
Lunny Xiao
45c45934aa Add last_committer_date and last_author_date for file contents API (#32921)
Fix #32886

Add `last_committer_date` and `last_author_date` in the content API
which is not implemented by Github API v3 at the moment.

Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2025-04-02 21:47:31 -07:00
Lunny Xiao
c27d87a9ac Refactor Branch struct in package modules/git (#33980)
The `Branch` struct in `modules/git` package is unnecessary. We can just
use a `string` to represent a branch
2025-04-02 17:31:32 +00:00
wxiaoguang
285950a222 Support creating relative link to raw path in markdown (#34105)
Fix #34104
2025-04-03 01:05:43 +08:00
Kemal Zebari
55a69ae4c6 Add new CLI flags to set name and scopes when creating a user with access token (#34080)
Resolves #33474.

---------

Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2025-04-02 22:00:54 +08:00
wxiaoguang
6ed1b26c58 Do not show 500 error when default branch doesn't exist (#34096)
Fix #34090
2025-04-01 21:39:00 -07:00
Lunny Xiao
88352e0b25 Return default avatar url when user id is zero rather than updating database (#34094) 2025-04-02 01:03:27 +00:00
GiteaBot
e2ac789b49 [skip ci] Updated translations via Crowdin 2025-04-02 00:35:16 +00:00
Lunny Xiao
0668cce4e8 Fix return bug (#34093)
Fix https://github.com/go-gitea/gitea/pull/34031/files#r2021927997
2025-04-01 17:36:46 -04:00
Lunny Xiao
92dfec704f Move ParseCommitWithSSHSignature to service layer (#34087)
No code change.
2025-04-01 16:30:53 +00:00
Håkon Harnes
dcf94c9e1b fix(i18n): clarify ownership in password change error messages (#34092)
This PR updates the English localization messages
`password_username_disabled` and `password_full_name_disabled` to
replace "their" with "your", making it clear that the messages refer to
the currently signed-in user.
2025-04-01 21:54:13 +08:00
TheFox0x7
ee3c82f874 Enable addtional linters (#34085)
enable mirror, usestdlibbars and perfsprint 
part of: https://github.com/go-gitea/gitea/issues/34083

---------

Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2025-04-01 10:14:01 +00:00
bytedream
56e42be36d Add flat-square action badge style (#34062)
Adds the `flat-square` style to action badges. Styles can be selected by
adding `?style=<style>` to the badge endpoint. If no style query is
given, or if the query is invalid, the style defaults to `flat`.

---------

Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2025-04-01 09:42:10 +00:00
wxiaoguang
86c1a33369 Fix some UI bugs and clean up unused tests (#34088)
1. Make the material icon falls back to basic theme correctly
2. Remove `TestAttributeReader`, the problem has been resolved.
3. Fix `toggleElem` bug and add tests
2025-04-01 07:02:30 +00:00
GiteaBot
d54418a7d3 [skip ci] Updated translations via Crowdin 2025-04-01 00:39:56 +00:00
TheFox0x7
4d2323183d fix users being able bypass limits with repo transfers (#34031)
prevent user from being able to transfer repo to user who cannot have
more repositories
2025-03-31 20:19:32 +00:00
Lunny Xiao
a2e8a289b2 Improve pull request list api (#34052)
The pull request list API is slow, for every pull request, it needs to
open a git repository. Assume it has 30 records, there will be 30 sub
processes back because every repository will open a git cat-file --batch
sub process. This PR use base git repository to get the head commit id
rather than read it from head repository to avoid open any head git
repository.
2025-03-31 12:54:31 -07:00
Simon Priet
342432e52a fix(#34076):replace assgniee translation key (#34077)
Fix the typo on the `filter_assginee_no_assigne` key used in
translations.

The typo itself doesn't produce a bug (as it's there both on the code
and on the locales)

Side Note: Github UI is not the best to bulk change this :/ Squashing
commits on the PR should be adequate.

Closes #34076 .

---------

Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
2025-03-31 19:11:15 +00:00
Kerwin Bryant
741b53eb30 [Fix] Resolve the problem of commit_statuses not being loaded at the top - right when switching files from the file tree (#34079)
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2025-03-31 18:39:08 +00:00
TheFox0x7
0fde8ecd55 Enable testifylint rules (#34075)
enable testifylint rules disabled in:
https://github.com/go-gitea/gitea/pull/34054
2025-03-31 01:53:48 -04:00
Kerwin Bryant
0fd5392087 Fix markup content overflow (#34072)
Fix #34069: use `overflow-wrap: anywhere` to correctly wrap overflowed
content.
2025-03-31 11:56:03 +08:00
GiteaBot
2f43544c01 [skip ci] Updated translations via Crowdin 2025-03-31 00:36:40 +00:00
Kerwin Bryant
2a9c5c9e3d Add toggleClass function in dom.ts (#34063)
This PR adds a toggleClass function in dom.ts, aiming to implement DOM
class toggling functionality.

---------

Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2025-03-30 14:19:54 +08:00
wxiaoguang
b59705fa34 Add a config option to block "expensive" pages for anonymous users (#34024)
Fix #33966

```
;; User must sign in to view anything.
;; It could be set to "expensive" to block anonymous users accessing some pages which consume a lot of resources,
;; for example: block anonymous AI crawlers from accessing repo code pages.
;; The "expensive" mode is experimental and subject to change.
;REQUIRE_SIGNIN_VIEW = false
```
2025-03-30 05:26:19 +00:00
JonRB
d7a6133825 add additional ReplaceAll in pathsep to cater for different pathsep (#34061)
The doctor storage check reconstructs the lfs oid by producing a string
where the path separator is stripped
ab/dc/efg -> abdcefg. Windows however uses a backslash and thus the
ReplaceAll call doesn't produce the correct oid resulting in all lfs
objects being classed as orphaned.
This PR allows this to be more OS agnostic.

Closes #34039

---------

Co-authored-by: Giteabot <teabot@gitea.io>
2025-03-30 12:46:28 +08:00
GiteaBot
0b847f4584 [skip ci] Updated translations via Crowdin 2025-03-30 00:37:48 +00:00
TheFox0x7
2a59dfbd47 enable staticcheck QFxxxx rules (#34064) 2025-03-29 17:32:28 -04:00
TheFox0x7
5564c39105 update to golangci-lint v2 (#34054)
updates config to v2.
config was generated with migrate command.
disable all newly exposed issues because there are too many.
2025-03-29 22:01:06 +08:00
yp05327
5023238088 Add descriptions for private repo public access settings and improve the UI (#34057)
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2025-03-29 21:24:27 +08:00
wxiaoguang
cddd19efc8 Add anonymous access support for private/unlisted repositories (#34051)
Follow #33127

Fix #8649, fix #639

This is a complete solution. A repo unit could be set to:

* Anonymous read (non-signed-in user)
* Everyone read (signed-in user)
* Everyone write (wiki-only)
2025-03-29 13:26:41 +08:00
Lunny Xiao
49899070cd Hide activity contributors, recent commits and code frequrency left tabs if there is no code permission (#34053)
When a team have no code unit permission of a repository, the member of
the team should not view activity contributors, recent commits and code
frequrency.

---------

Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2025-03-28 21:04:40 -07:00
bytedream
bf9500b3f2 Update action status badge layout (#34018)
The current action status badge are looking different from most other
badges renders, which is especially noticeable when using them along
with other badges. This PR updates the action badges to match the
commonly used badges from other providers.

---------

Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2025-03-28 15:12:47 +00:00
wxiaoguang
0d2607a303 Add anonymous access support for private repositories (backend) (#33257)
Follow #33127

This PR add backend logic and test for "anonymous access", it shares the
same logic as "everyone access", so not too much change.

By the way, split `SettingsPost` into small functions to make it easier
to make frontend-related changes in the future.

Next PR will add frontend support for "anonymous access"
2025-03-28 22:42:29 +08:00
silverwind
58d0a3f4c2 Simplify emoji rendering (#34048)
It seems like most of our custom styles around the .emoji class are
useless and we can just make them render like any other text. Rendering
should now match GitHub.

Fixes: https://github.com/go-gitea/gitea/issues/34019

Also see https://github.com/go-gitea/gitea/pull/11541 and
https://github.com/go-gitea/gitea/pull/12317 for some context. I think
browser emoji rendering has improved in recent years so these hacks are
no longer needed.

---------

Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2025-03-28 18:25:13 +08:00
Kerwin Bryant
b542769102 Adjust the layout of the toolbar on the Issues/Projects page (#33667)
On the list page, labels and milestones do not serve as a switch-tab.
Instead, they function as page navigation. The switch-tab is only
appropriate for use on the labels and milestones pages.

And fix projects page layout.

---------

Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2025-03-28 07:55:12 +00:00
Lunny Xiao
321cbcb45a Fix bug on downloading job logs (#34041)
Fix #34038
2025-03-27 17:20:56 -07:00
wxiaoguang
894821d522 Fix git client accessing renamed repo (#34034)
Fix #28460

The `reqGitSignIn` is just copied-pasted code (from githtttp.go) and
causes the regression bug.

Co-authored-by: Giteabot <teabot@gitea.io>
2025-03-28 07:28:58 +08:00
Lunny Xiao
c1b9ecca34 Decouple Batch from git.Repository to simplify usage without requiring the creation of a Repository struct. (#34001)
No logic change
2025-03-27 17:35:48 +00:00
TheFox0x7
053592d847 fix org repo creation being limited by user limits (#34030)
fixes an issue where user is unable to create new repository in
organization via UI if repository limits are in place and user has
exhausted them for their own namespace.

closes: https://github.com/go-gitea/gitea/issues/15504

---------

Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2025-03-27 13:16:17 +00:00
charles
a7594969b6 Fix the issue with error message logging for the check-attr command on Windows OS. (#34035)
Close #34022 , #33550 

This error message always appears when using the `check-attr` command,
even though it works correctly.
The issue occurs when the stdin writer is closed, so I added a special
case to handle and check the error message when the exit code is 1.
2025-03-27 17:25:31 +08:00
wxiaoguang
96e7369515 Try to fix check-attr bug (#34029) 2025-03-27 05:07:17 +00:00
GiteaBot
3c95b0758f [skip ci] Updated translations via Crowdin 2025-03-27 00:33:53 +00:00
Lunny Xiao
0c6957ef8d Download actions job logs from API (#33858)
Related to #33709, #31416

It's similar with
https://docs.github.com/en/rest/actions/workflow-jobs?apiVersion=2022-11-28#download-job-logs-for-a-workflow-run--code-samples.

This use `job_id` as path parameter which is consistent with Github's
APIs.

---------

Co-authored-by: ChristopherHX <christopher.homberger@web.de>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2025-03-26 11:30:52 -07:00
Royce Remer
e0ad72e223 Fail mirroring more gracefully (#34002)
* reuse recoverable error checks across mirror_pull
* add new cases for 'cannot lock ref/not our ref' (race condition in
fetch) and 'Unable to create/lock"
* move lfs sync right after commit graph write, and before other
maintenance which may fail
* try a prune for 'broken reference' as well as 'not our ref'
* always sync LFS right after commit graph write, and before other
maintenance which may fail

This handles a few cases where our very large and very active
repositories could serve mirrored git refs, but be missing lfs files:

## Case 1 (multiple variants): Race condition in git fetch
There was already a check for 'unable to resolve reference' on a failed
git fetch, after which a git prune and then subsequent fetch are
performed. This is to work around a race condition where the git remote
tells Gitea about a ref for some HEAD of a branch, then fails a few
seconds later because the remote branch was deleted, or the ref was
updated (force push).

There are two more variants to the error message you can get, but for
the same kind of race condition. These *may* be related to the git
binary version Gitea has access to (in my case, it was 2.48.1).

## Case 2: githttp.go can serve updated git refs before it's synced lfs
oids

There is probably a more aggressive refactor we could do here to have
the cat-file loop use FETCH_HEAD instead of relying on the commit graphs
to be committed locally (and thus serveable to clients of Gitea), but a
simple reduction in the occurrences of this for me was to move the lfs
sync block immediately after the commit-graph write and before any other
time-consuming (or potentially erroring/exiting) blocks.

---------

Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2025-03-26 18:04:46 +00:00
wxiaoguang
c7b85f7070 Fix dropdown module accessing (#34026)
Follow #34014.
2025-03-26 16:01:43 +00:00
wxiaoguang
d70be9d0fe Polyfill WeakRef (#34025)
Fix #33407
2025-03-26 23:56:25 +08:00
wxiaoguang
d28a7f9fea Fix dropdown delegating and some UI problems (#34014)
The old logic is incomplete. See the comment for the improved logic.

Fix #34011

And more fixes:

1. use empty "alt" for images, otherwise the width is not right when the
image fails to load
2. remove the "dropdown icon" patch, because it has been clearly done in
"dropdown.js" now
3. remove the "dropdown filtered item" patch, added a clear callback,
and improve the logic
4. fix global init when a node is removed and added back gain (eg: the
"cherry pick" dialog with a dropdown)
2025-03-26 02:51:22 +00:00
silverwind
2089401653 Enable color output in govulncheck (#34012)
Make `govulncheck` show color, which by default it doesn't for some
reason.
2025-03-25 18:24:48 +00:00
Rafael de Mattos
20c7392e99 Update Makefile test comments (#34013)
The comments are referring to the wrong project section (backend and
frontend).
2025-03-25 17:54:17 +00:00
Lunny Xiao
d6e94fa4e4 Move duplicated functions (#33977)
Remove duplicated functions `IsExist`, `IsFile` and `IsDir` in package
`modules/git` and use the exists functions in `modules/util`.
2025-03-25 14:40:31 +00:00
Lunny Xiao
356b707dde Git client will follow 301 but 307 (#34005)
Fix #28460

---------

Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2025-03-25 07:20:08 +00:00
wxiaoguang
41c946a66f Prepare common tmpl functions in a middleware (#33957)
Fix the TODO in `routers/web/web.go`, and avoid the unnecessary
`GetActiveStopwatch` SQL query in non-related route handlers.
2025-03-25 06:17:58 +00:00
wxiaoguang
32258e0f22 Update go mod dependencies (#33988)
blevesearch is skipped because it causes errors

---------

Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
Co-authored-by: silverwind <me@silverwind.io>
2025-03-25 05:51:52 +00:00
wxiaoguang
51d86adb6d Fix some migration and repo name problems (#33986)
1. Ignore empty inputs in `UnmarshalHandleDoubleEncode`
2. Ignore non-existing `stateEvent.User` in gitlab migration
3. Enable `release` and `wiki` units when they are selected in migration
4. Sanitize repo name for migration and new repo
2025-03-24 20:26:58 -07:00
GiteaBot
536f4c6de8 [skip ci] Updated translations via Crowdin 2025-03-25 00:34:21 +00:00
Lunny Xiao
3fe449c21a Use filepath.Join instead of path.Join for file system file operations (#33978) 2025-03-24 14:50:28 -07:00
Lunny Xiao
82bc8b8ce6 Add changelog for 1.23.6 (#33975)
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
Co-authored-by: techknowlogick <techknowlogick@gitea.io>
2025-03-24 11:35:02 -07:00
wxiaoguang
8745129c9c Fix incorrect code search indexer options (#33992)
Fix #33798

Co-authored-by: Giteabot <teabot@gitea.io>
2025-03-24 17:18:21 +01:00
wxiaoguang
b1e326d09e Auto expand "New PR" form (#33971)
Follow GitHub's behavior: use `?expand=1` to expand the "New PR" form
2025-03-24 14:28:02 +00:00
Lunny Xiao
25b6f38865 Move ParseBool to optional (#33979) 2025-03-24 03:53:30 +00:00
GiteaBot
08510adefe [skip ci] Updated translations via Crowdin 2025-03-24 00:35:25 +00:00
Lunny Xiao
30ee082e48 Only use prev and next buttons for pagination on user dashboard (#33981)
The pagination on the user dashboard sounds unnecessary, this will
change it to a prev/next buttons. For instances with around `10 million`
records in the action table, this option affects how the user dashboard
is loaded on first visit.

---------

Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
Co-authored-by: Giteabot <teabot@gitea.io>
2025-03-23 19:52:43 +00:00
TheFox0x7
189873719b update jwt and redis packages (#33984) 2025-03-23 10:13:16 -04:00
GiteaBot
0fee4f1392 [skip ci] Updated translations via Crowdin 2025-03-23 00:37:07 +00:00
wxiaoguang
e1bba9c1a2 Improve oauth2 error handling (#33969)
Show the callback error to end users, it should be safe.
Fix #33967
2025-03-22 10:15:45 +08:00
GiteaBot
1c5c13a442 [skip ci] Updated translations via Crowdin 2025-03-22 00:33:13 +00:00
silverwind
d1a755e5b7 Cover go.mod and go.sum in .editorconfig (#33960)
These files were previously set to use spaces for indendation but they
are supposed to use tabs, so set this in editorconfig.
2025-03-21 20:48:06 +00:00
Kai Leonhardt
b5d2e31d6d Drop timeout for requests made to the internal hook api (#33947)
This change targets https://github.com/go-gitea/gitea/issues/32663
We drop the hardcoded timeout of 60 seconds for requests to the internal
hook api. With this change the timeout is completly removed.

---------

Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2025-03-21 12:52:14 -07:00
charles
b956cee06f Fix file name could not be searched if the file was not a text file when using the Bleve indexer (#33959)
Close #33828

---------

Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2025-03-21 19:00:02 +00:00
wxiaoguang
279473f467 Fix oauth2 auth and UI (#33961) 2025-03-21 20:50:39 +08:00
Andreas Svanberg
0da7318cf3 Allow filtering issues by any assignee (#33343)
This is the opposite of the "No assignee" filter, it will match all
issues that have at least one assignee.

Before
![Before
change](https://github.com/user-attachments/assets/4aea194b-9add-4a84-8d6b-61bfd8d9e58e)

After
![After change with any
filter](https://github.com/user-attachments/assets/99f1205d-ba9f-4a0a-a60b-cc1a0c0823fe)

---------

Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2025-03-21 04:25:36 +00:00
Lunny Xiao
a4df01b580 Optimize total count of feed when loading activities in user dashboard. (#33841)
Two SQLs are very slow when `action` table have over 5M records.

```
database duration=1.8881s db.sql="SELECT created_unix DIV 900 * 900 AS timestamp, count(user_id) as contributions FROM `action` WHERE user_id=? AND act_user_id=? AND (created_unix > ?) GROUP BY timestamp ORDER BY timestamp"

database duration=1.5408s db.sql="SELECT count(*) FROM `action` WHERE (user_id = ?) AND (is_deleted = ?)"
```

This will cache the count for the first loading or when the activities
changed.
2025-03-20 10:46:18 -07:00
Lunny Xiao
ef0970506f Extract code to their own functions for push update (#33944) 2025-03-20 16:57:04 +00:00
Lunny Xiao
4a7ab0abf0 Optimize heatmap query (#33853)
When there are over 5M records on `action` table, the heatmap on
dashboard is very slow as below SQL.
```
database duration=1.8881s db.sql="SELECT created_unix DIV 900 * 900 AS timestamp, count(user_id) as contributions FROM `action` WHERE user_id=? AND act_user_id=? AND (created_unix > ?) GROUP BY timestamp ORDER BY timestamp"
```

This PR add a new index for `action` table with columns `user_id`,
`act_user_id` and `created_unix` so that this query will become about 6
times faster than before.
2025-03-20 09:30:45 -07:00
TheFox0x7
5407382b43 Add cli flags LDAP group configuration (#33933)
Add 7 new flags to ldap subcommands corresponding to UI options

Closes CLI part of https://github.com/go-gitea/gitea/issues/20716
2025-03-19 17:29:37 -07:00
Lunny Xiao
a9e8ac0fe0 Don't create duplicated functions for code repositories and wiki repositories (#33924)
Fix
https://github.com/go-gitea/gitea/pull/33910#pullrequestreview-2688913865

This PR changed the Repositroy interface in `gitrepo` package which
makes it only focus the relative path in the disk and abstract whether
it's a wiki repository or not.
2025-03-19 11:17:19 -07:00
YaFou
e25f860735 Fix "toAbsoluteLocaleDate" test when system locale is not en-US (#33939) 2025-03-19 19:49:05 +08:00
GiteaBot
39fc2e7285 [skip ci] Updated translations via Crowdin 2025-03-19 00:33:36 +00:00
Kerwin Bryant
dcbf6c2d13 Optimize Layout Styles of Filelist (#33920)
Align items

---------

Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2025-03-19 00:59:33 +08:00
GiteaBot
1b4adc0255 [skip ci] Updated translations via Crowdin 2025-03-18 00:33:31 +00:00
metiftikci
6e73ecf667 update go version for devcontainers (#33923) 2025-03-17 19:25:27 +00:00
John Smith
8f051d598c Added Description Field for Secrets and Variables (#33526)
Fixes #33484

---------

Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2025-03-17 19:24:54 +00:00
wxiaoguang
9d7c02f9f7 Try to figure out attribute checker problem (#33901)
For #31600
2025-03-17 11:59:34 -07:00
wxiaoguang
fdaf1cca65 Defer captcha script loading (#33919)
Fix #33899
2025-03-17 15:21:04 +00:00
Kerwin Bryant
e1feb438a4 Fix file tree issues (#33916) 2025-03-17 14:55:15 +00:00
wxiaoguang
9d89dfe142 Remove unused or abused styles (#33918)
* `top aligned` => `tw-align-top`
* label list: it was broken, this PR fixes it
* reference link: simplified
* settings/repos: not affected
2025-03-17 22:11:24 +08:00
GiteaBot
9ebae4a2aa [skip ci] Updated translations via Crowdin 2025-03-17 00:35:08 +00:00
silverwind
18bd70054b Update tool dependencies (#33907)
`gopls` is currently excluded because its [new
analyzers](https://github.com/golang/tools/releases/tag/gopls%2Fv0.18.0)
raise many issue, to be fixed before we can upgrade it. And I think the
modernize fixer still has a number of [unresolved/undiscovered
bugs](https://github.com/golang/go/issues/71847).
2025-03-16 18:34:24 +00:00
Lunny Xiao
7fd44a85ca Move hooks function to gitrepo and reduce expose repopath (#33890)
Extract from #28966 
Follow #33874
2025-03-16 16:12:55 +00:00
silverwind
1ea5216f4a Replace text-align classes with tailwind (#33905)
Small refactor to remove these CSS classes in favor of tailwind.

---------

Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2025-03-16 12:08:16 +00:00
silverwind
01c8f092a0 Simplify secure context check (#33906)
As discussed in
https://github.com/go-gitea/gitea/pull/33820/files#r1997532169.
2025-03-16 19:05:26 +08:00
silverwind
52663113d4 Update JS and PY deps, misc tweaks (#33903)
- Update all updateable dependencies
- Add a few more unupgradable ones to updates blocklist
- Adapt to breaking changes
- Update to typescript 5.8, enable `erasableSyntaxOnly` which
necessitated a change because of forbidden syntax
- Misc cleanups
- Tested htmx, easymde, swagger, chart.js
2025-03-16 10:04:18 +01:00
Lunny Xiao
c88e71c1d2 Refactor functions to reduce repopath expose (#33892) 2025-03-16 03:14:56 +00:00
Lunny Xiao
0056fdb942 Move git references checking to gitrepo packages to reduce expose of repository path (#33891) 2025-03-15 19:48:59 -07:00
GiteaBot
f11ac6bf3c [skip ci] Updated translations via Crowdin 2025-03-16 00:36:54 +00:00
Lunny Xiao
10513df1bf Add missing translation (#33900) 2025-03-15 18:55:58 +00:00
Job
30b13942f0 Give organisation members access to organisation feeds (#33508)
Currently the organisation feed only includes items for public
repositories (for non-administrators). This pull requests adds
notifications from private repositories to the organisation-feed (for
accounts that have access to the organisation).

Feed-items only get shown for repositories where the users team(s)
should have access to, this filtering seems to get done by some existing
code.

Needs some tests, but am unsure where/how to add them.

Before:

![image](https://github.com/user-attachments/assets/8b63f430-227a-4b19-ad1a-f6f5175de301)

After:

![image](https://github.com/user-attachments/assets/b439ce0e-4946-421c-a399-421806c7a6d8)

---------

Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2025-03-15 17:49:06 +00:00
Lunny Xiao
3e2e7bf4e5 Add lock for a repository pull mirror (#33876)
Fix #33647

This PR add a global lock for repository pulling mirror.
2025-03-15 10:23:18 -07:00
ChristopherHX
7e8168f555 Fix cannot delete runners via the modal dialog (#33895)
delete-button and show-modal class are conflicting

Closes #33894
2025-03-15 09:45:37 -07:00
Kerwin Bryant
92f997ce6b Add file tree to file view page (#32721)
Resolve #29328

This pull request introduces a file tree on the left side when reviewing
files of a repository.

---------

Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2025-03-15 16:26:49 +08:00
GiteaBot
926f0a19be [skip ci] Updated translations via Crowdin 2025-03-15 00:33:24 +00:00
ChristopherHX
65e2411394 Feature: Ephemeral action runners (#33570)
* This includes a runner mock test for hardend PickTask behavior like
described in my proposal
* Runner register ephemeral flag introduced in
https://gitea.com/gitea/act_runner/pulls/649

Closes #32461
2025-03-14 12:27:24 -07:00
Lunny Xiao
55cc649d3d Add abstraction layer to delete repository from disk (#33879)
Extract from #28966 
Follow #33874
2025-03-14 18:38:55 +00:00
wxiaoguang
a0e0a30d23 Make SearchMode have default value and add comments (#33863)
* Make `SearchMode` have default value if it is empty
* Add some comments for the "match" queries
* Fix a copy-paste mistake in `buildMatchQuery` (`db.go`)
* Add missing `q.Analyzer = repoIndexerAnalyzer`, it is in old code,
although I do not see real difference ....
2025-03-14 18:06:31 +00:00
wxiaoguang
45c4139134 Fix maven panic when no package exists (#33888)
Fix #33886

Restore the old logic from #16510, which was incorrectly removed by
#33678
2025-03-14 10:35:40 -07:00
wxiaoguang
0dfa94edc8 Add old svg class name to git entry icon (#33884)
Fix https://github.com/go-gitea/gitea/pull/33837#discussion_r1995521288
2025-03-14 23:11:29 +08:00
wxiaoguang
cb6b33c9cd Ignore trivial errors when updating push data (#33864)
Fix #23213
2025-03-14 08:36:39 +00:00
wxiaoguang
b094f9b75d Improve repo commit view (#33877)
Fix #24623

Major changes:

1. Redirect `/owner/repo/blob/*` requests to `/owner/repo/src/commit/*`
(like GitHub)
2. Add a "view file diff" link (see screenshot below)
3. Refactor "AssertHTMLElement" to generic, now we can accurately assert
existence or number.
4. Add more tests

---------

Co-authored-by: silverwind <me@silverwind.io>
Co-authored-by: delvh <dev.lh@web.de>
2025-03-14 07:45:11 +00:00
Lunny Xiao
9c673d066c Add abstraction layer to check if the repository exists on disk (#33874)
Extract from #28966 

This PR uses `gitrepo.IsRepositoryExist` instead of `util.IsExist` to
detect whether the repository exist in disk. This will move `RepoPath`
detail behind of package `gitrepo` to make it easier to do possible
changes where storing the repositories.

No code change
2025-03-14 03:00:56 +00:00
Lunny Xiao
1e7248047c Pull request updates will also trigger code owners review requests (#33744)
Fix #33490 

It will only read the changed file on the pushed commits but not all the
files of this PR.

---------

Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2025-03-13 19:36:14 -07:00
GiteaBot
de2d472d90 [skip ci] Updated translations via Crowdin 2025-03-14 00:33:05 +00:00
TheFox0x7
5d65b9060b remove context from retry downloader (#33871)
follow up to https://github.com/go-gitea/gitea/pull/33399 as I
apparently missed this one.
2025-03-14 00:28:57 +00:00
wxiaoguang
d879ec6d92 Fine tune push mirror UI (#33866) 2025-03-14 00:03:21 +00:00
wxiaoguang
8a0f7f0975 Fix markdown render (#33870)
Fix #33869, some code block is moved to make it easier to test.

Added a new test
2025-03-13 12:14:35 -07:00
wxiaoguang
403775e74e Improve issue & code search (#33860)
Each "indexer" should provide the "search modes" they support by
themselves. And we need to remove the "fuzzy" search for code.
2025-03-13 11:07:48 +08:00
GiteaBot
cd10456664 [skip ci] Updated translations via Crowdin 2025-03-13 00:33:50 +00:00
wxiaoguang
3996518ed4 Refactor cache-control (#33861)
And fix #21391
2025-03-13 07:04:50 +08:00
wxiaoguang
91610a987e Fix various Fomantic UI and htmx problems (#33851)
Also fix #31328, fix #33854
2025-03-11 11:35:05 -07:00
ChristopherHX
651ef66966 Add workflow_job webhook (#33694)
Provide external Integration information about the Queue lossly based on
https://docs.github.com/en/webhooks/webhook-events-and-payloads?actionType=completed#workflow_job

Naming conflicts between GitHub & Gitea are here, Blocked => Waiting,
Waiting => Queued

Rationale Enhancement for ephemeral runners management #33570
2025-03-11 10:40:38 -07:00
wxiaoguang
f61f30153b Fix file icon mapping (#33855)
Use the file extension mapping from VSCode's extensions.
Otherwise js/ts/vba/... files won't get correct icons.
2025-03-11 21:06:59 +08:00
wxiaoguang
608ccc32e5 Drop fomantic build (#33845)
We would never update or build fomantic again, we have forked it as a
private library long time ago.

So just put the JS and CSS files in "fomantic/build" into git. And use
"import" to use them.

Remove "form.js", rewrite "tab" component.

All source code is from official Fomantic UI build. Will apply patches
in separate PRs.
2025-03-11 12:44:52 +08:00
ChristopherHX
a92d5f65ce Fix auto concurrency cancellation skips commit status updates (#33764)
* add missing commit status
* conflicts with concurrency support

Closes #33763

Co-authored-by: Giteabot <teabot@gitea.io>
2025-03-10 15:58:48 -07:00
wxiaoguang
e47bba046c Fix test code (#33829)
Do not use onGiteaRun if there is no git operation
2025-03-10 21:45:42 +00:00
wxiaoguang
7fa47de7e9 Remove "noscript" tag from html head (#33846) 2025-03-11 00:52:08 +08:00
wxiaoguang
657239b480 Fix material icon & diff highlight (#33844) 2025-03-10 22:34:48 +08:00
wxiaoguang
c102492e5a Fix LFS URL (#33840)
Fix #33839
2025-03-10 17:36:02 +08:00
wxiaoguang
34e5df6d30 Add material icons for file list (#33837) 2025-03-10 15:57:17 +08:00
Lunny Xiao
ae63568ce3 Move notifywatch to service layer (#33825)
No logic change.
2025-03-10 00:54:25 +00:00
GiteaBot
31ddbe1444 [skip ci] Updated translations via Crowdin 2025-03-10 00:29:01 +00:00
wxiaoguang
7290bfaccb Only keep popular licenses (#33832)
Fix #33467
2025-03-10 06:40:37 +08:00
Vinoth Kumar
3e53b01143 Removing unwanted ui container (#33833)
when the passkey auth and register was disabled
the unwanted ui container was show

Co-authored-by: Vinoth414 <103478407+Vinoth414@users.noreply.github.com>
2025-03-10 00:38:11 +08:00
Dustin Firebaugh
3f1f808b9e Full-file syntax highlighting for diff pages (#33766)
Fix #33358, fix #21970

This adds a step in the `GitDiffForRender` that does syntax highlighting for the
entire file and then only references lines from that syntax highlighted
code. This allows things like multi-line comments to be syntax
highlighted correctly.

---------

Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2025-03-09 12:51:58 +08:00
wxiaoguang
6f13331754 Improve theme display (#30671)
Document: https://gitea.com/gitea/docs/pulls/180

![image](https://github.com/go-gitea/gitea/assets/2114189/68e38573-b911-45d9-b7aa-40d96d836ecb)
2025-03-08 21:38:11 +00:00
TheFox0x7
4c4c56c7cd Decouple context from repository related structs (#33823)
Calls that required context implicitly are made to pass it as argument
2025-03-08 13:12:46 -08:00
wxiaoguang
4ed71eb754 Improve log format (#33814) 2025-03-08 21:47:11 +08:00
wxiaoguang
6422f05a4e Decouple diff stats query from actual diffing (#33810)
The diff stats are no longer part of the diff generation.
Use `GetDiffShortStat` instead to get the total number of changed files,
added lines, and deleted lines.
As such, `gitdiff.GetDiff` can be simplified:
It should not do more than expected.

And do not run "git diff --shortstat" for pull list. Fix #31492
2025-03-08 17:36:08 +08:00
Lunny Xiao
1b2dffff8e Add global lock for migrations to make upgrade more safe with multiple replications (#33706) 2025-03-07 21:08:53 +00:00
wxiaoguang
b8c2afdc5f Do not show passkey on http sites (#33820)
Fix #33615
2025-03-07 19:37:27 +00:00
Alexander McRae
582ad338d7 Use correct start and end commits for GetDiffTree (#33816)
Fixes
https://github.com/go-gitea/gitea/pull/33514#issuecomment-2702814099

Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2025-03-07 02:40:39 +00:00
wxiaoguang
ef18655215 Try to fix ACME (3rd) (#33807)
Fix #33802, fix #32191
2025-03-07 01:00:10 +00:00
TheFox0x7
e7cf62f2f7 remove context from mail struct (#33811)
it can be passed by argument instead
2025-03-06 20:57:00 +00:00
GiteaBot
b0ee340969 [skip ci] Updated translations via Crowdin 2025-03-06 00:32:55 +00:00
Lunny Xiao
0453177b61 Refactor: move part of updating protected branch logic to service layer (#33742) 2025-03-05 19:15:40 +00:00
Lunny Xiao
df7b61ce9a Update changelog for v1.23.5 (#33797)
frontport from #33780
2025-03-05 18:47:13 +00:00
sommerf-lf
7cdde20c73 Email option to embed images as base64 instead of link (#32061)
ref: #15081
ref: #14037

Documentation: https://gitea.com/gitea/docs/pulls/69

# Example
Content:

![image](https://github.com/user-attachments/assets/e73ebfbe-e329-40f6-9c4a-f73832bbb181)
Result in Email:

![image](https://github.com/user-attachments/assets/55b7019f-e17a-46c3-a374-3b4769d5c2d6)
Result with source code:
(first image is external image, 2nd is now embedded)

![image](https://github.com/user-attachments/assets/8e2804a1-580f-4a69-adcb-cc5d16f7da81)

---------

Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2025-03-05 16:29:29 +00:00
Kerwin Bryant
f0f10413ae Update TypeScript types (#33799)
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2025-03-05 08:03:44 -08:00
silverwind
95efc7b35b Disable vet=off again (#33794)
Ref: https://github.com/go-gitea/gitea/issues/33792

To avoid slowing unit-test down.
2025-03-05 17:15:31 +08:00
GiteaBot
b9913d9568 [skip ci] Updated translations via Crowdin 2025-03-05 00:33:24 +00:00
Lunny Xiao
65bb837fa2 Upgrade golang net from 0.35.0 -> 0.36.0 (#33795) 2025-03-04 23:25:09 +01:00
TheFox0x7
ae3a18e01a Remove context from git struct (#33793)
Argument is moved from struct init in command run, which lets us remove
context from struct.
2025-03-04 11:56:11 -08:00
Lunny Xiao
6c8fb8d455 Small refactor to reduce unnecessary database queries and remove duplicated functions (#33779) 2025-03-04 18:25:20 +00:00
wxiaoguang
75e85c25c1 Refactor repo-issue.ts (#33784)
And remove jQuery
2025-03-04 17:58:17 +00:00
wxiaoguang
ca0ce003ab Refactor repo-settings.ts (#33785)
and remove jQuery
2025-03-05 01:19:03 +08:00
wxiaoguang
163bbca0eb Refactor admin/common.ts (#33788)
Only remove jQuery
2025-03-04 23:42:07 +08:00
Denys Konovalov
ffb276578f Adjust appearence of commit status webhook (#33778)
Some visual improvement for the commit status webhook message introduced
by #33320

- use short commit SHA as already done in e. g. commit webhook
- fix spacing, link text
- do not set user link for internal gitea-actions user

Before: 

![grafik](https://github.com/user-attachments/assets/9c460846-c350-444c-89b5-8a0d5e26cb86)

After:

![grafik](https://github.com/user-attachments/assets/05519cd8-6d8f-432b-bd9d-082de558a55a)
2025-03-03 21:23:42 +00:00
Kerwin Bryant
14be462646 Refactor initRepoBranchTagSelector to use new init framework (#33776)
Make "initRepoBranchTagSelector" to use new init framework and fix the
abused "js-branch-tag-selector" styles

---------

Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2025-03-03 20:58:19 +00:00
Kerwin Bryant
ad204f9c5a Refactor buttons to use new init framework (#33774)
Make buttons to use new init framework
* "js-toggle-commit-body"
* "show-panel/hide-panel/show-modal"
* "copy-content"

---------

Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2025-03-03 20:30:55 +00:00
Kerwin Bryant
f0f1737d4d Refactor markup and pdf-viewer to use new init framework (#33772)
1. Add some "render-content" classes to "markup" elements when the
content is rendered
2. Use correct "markup" wrapper for "preview" (but not set that class on
the tab)
3. Remove incorrect "markup" class from LFS file view, because there is
no markup content
    * "edit-diff" is also removed because it does nothing
5. Use "initPdfViewer" for PDF viewer
6. Remove incorrect "content" class from milestone markup
7. Init all ".markup" elements by new init framework

---------

Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2025-03-03 11:49:15 -08:00
silverwind
43c8d85f19 Disable vet as part of go test (#33662)
`go vet` implicitely runs as part of `go test`, but we already have
`make lint-go-vet`, so we were essentially running it twice. This should
hopefully make `go test` slightly faster.

Ref: https://pkg.go.dev/cmd/go#hdr-Test_packages

> As part of building a test binary, go test runs go vet
2025-03-03 06:03:42 +00:00
wxiaoguang
216243eee2 Refactor error system (#33771)
It should not expose `util.SilentWrap` or construct it manually.
2025-03-03 05:36:10 +00:00
Lunny Xiao
dbed39d632 Add migrations and doctor fixes (#33556)
Fix #33535
2025-03-02 21:01:28 -08:00
wxiaoguang
02657e85a4 Refactor mail code (#33768)
`mail.go` contains various different functions, it's time to split it.
2025-03-03 03:31:47 +00:00
wxiaoguang
27bf63ad20 Refactor global init code and add more comments (#33755)
Follow up #33748

Now there are 3 "global" functions:

* registerGlobalSelectorFunc: for all elements matching the selector, eg: `.ui.dropdown`
* registerGlobalInitFunc: for `data-global-init="initInputAutoFocusEnd"`
* registerGlobalEventFunc: for `data-global-click="onCommentReactionButtonClick"`


And introduce `initGlobalInput` to replace old `initAutoFocusEnd` and
`attachDirAuto`, use `data-global-init` to replace fragile
`.js-autofocus-end` selector.

Another benefit is that by the new approach, no matter how many times
`registerGlobalInitFunc` is called, we only need to do one
"querySelectorAll" in the last step, it could slightly improve the
performance.
2025-03-03 10:57:28 +08:00
Lunny Xiao
5cbdf83f70 Use pullrequestlist instead of []*pullrequest (#33765)
Just renames no code changed.
2025-03-02 10:14:49 -08:00
Lunny Xiao
2c8bdd2233 Upgrade act to 0.261.4 and actions-proto-go to v0.4.1 (#33760)
Include https://gitea.com/gitea/act/pulls/129 Fix #33657 
And https://gitea.com/gitea/actions-proto-def/pulls/14
2025-03-01 20:02:58 +00:00
ChristopherHX
b684f51d20 Webhook add X-Gitea-Hook-Installation-Target-Type Header (#33752)
This is a X-GitHub Header port

* repository for repository webhooks (matches GitHub)
* organization for organization webhooks (matches GitHub)
* user for user webhooks (Gitea specific)
* system for system webhooks  (Gitea specific)
* default for default hooks needs testing (Gitea specific)

- `X-Gitea-Hook-Installation-Target-Type`
- `X-GitHub-Hook-Installation-Target-Type`
2025-03-01 06:50:49 +00:00
wxiaoguang
698ae7aa5b Fix dynamic content loading init problem (#33748)
1. Rewrite `dirauto.ts` to `observer.ts`. 
* We have been using MutationObserver for long time, it's proven that it
is quite performant.
    * Now we extend its ability to handle more "init" works.
2. Use `observeAddedElement` to init all non-custom "dropdown".
3. Use `data-global-click` to handle click events from dynamically
loaded elements.
* By this new approach, the old fragile selector-based
(`.comment-reaction-button`) mechanism is removed.
4. By the way, remove unused `.diff-box` selector, it was abused and
never really used.

A lot of FIXMEs in "repo-diff.ts" are completely fixed, newly loaded
contents could work as expected.
2025-03-01 02:02:10 +00:00
GiteaBot
f3ada61097 [skip ci] Updated translations via Crowdin 2025-03-01 00:36:23 +00:00
Lunny Xiao
aca21549f2 Add composor source field (#33502)
Fix #33066
2025-02-28 16:29:21 +00:00
Lunny Xiao
ae4a3d7708 upgrade go-crypto from 1.1.5 to 1.1.6 (#33745)
Fix #33296

---------

Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2025-02-28 14:06:47 +00:00
silverwind
6e475dc7e0 Disable go license generation as part of make tidy (#33747)
It seems something broken `google/go-licenses` (maybe related to go
1.24), and my findings are in
https://github.com/google/go-licenses/issues/128#issuecomment-2689753365.
I think it's best we disable this generation for now until a better
solution is found.

Also, enable showing stderr output so we can actually debug this thing.
For reference, these are the errors that currently apparently break the
tool:

```
E0228 05:15:27.005759   13158 library.go:117] Package text/tabwriter does not have module info. Non go modules projects are no longer supported. For feedback, refer to https://github.com/google/go-licenses/issues/128.
E0228 05:15:27.005776   13158 library.go:117] Package net/http/fcgi does not have module info. Non go modules projects are no longer supported. For feedback, refer to https://github.com/google/go-licenses/issues/128.
F0228 05:15:27.028122   13158 main.go:77] some errors occurred when loading direct and transitive dependency packages
```
2025-02-28 11:26:27 +00:00
wxiaoguang
4e56d5f39f Refactor repo-diff.ts (#33746)
Remove jQuery
2025-02-28 16:37:16 +08:00
Alexander McRae
aba96f65cd Use git diff-tree for DiffFileTree on diff pages (#33514)
Modify Diff View FileTree to show all files

## Changes

* removes Show Status button on diff
* uses `git diff-tree` to generate the file tree for the diff
* doesn't reload the diff tree each time we load more files in the
preview
* selecting and unloaded file will keep loading until that file is
loaded
* removes `DiffFileList.vue` and "Show Stats" in diff options

## Open Questions

* selecting and unloaded file will keep loading until that file is
loaded. Is this behaviour okay? It matches what github does.

### Demo

In this demo I set `git.MAX_GIT_DIFF_FILES=1` in my `app.ini` to
demonstrate a worst case example. In most cases the behaviour isn't
nearly as jarring as we load a bunch of files at a time.


https://github.com/user-attachments/assets/72f29663-d6fc-472d-94fa-7fb5950c2836

---------

Co-authored-by: silverwind <me@silverwind.io>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2025-02-28 00:58:25 +00:00
GiteaBot
7a8eed13b9 [skip ci] Updated translations via Crowdin 2025-02-28 00:32:56 +00:00
Guillaume
303af554c9 Improve "generate new access token" form (#33730)
Fix: https://github.com/go-gitea/gitea/issues/33519

As discussed in [PR
#33614](https://github.com/go-gitea/gitea/pull/33614), the
ScopedAccessTokenSelector Vue component is not particularly useful.

This PR removes the component and reverts to using HTML templates. It
also introduces some (hopefully) useful refactoring.

The Vue component was causing the UX bug reported in the linked issue.
Required form fields are now properly working, as expected (see
screenshot).

![Screenshot from 2025-02-25
22-00-28](https://github.com/user-attachments/assets/41167854-0718-48b0-a3ee-75ca3a7b8b20)

---------

Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2025-02-27 19:40:12 +00:00
silverwind
8362a41559 Remove superflous tw-content-center (#33741) 2025-02-27 19:05:28 +00:00
Quentin
f52e31f5ce Clone repository with Tea CLI (#33725)
This PR adds "Tea CLI" as a clone method.

<img width="350" alt="Capture d’écran 2025-02-25 à 23 38 47"
src="https://github.com/user-attachments/assets/8e86e54a-998b-45d1-9f20-167b449e79b6"
/>

---------

Signed-off-by: Quentin Guidée <quentin.guidee@gmail.com>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2025-02-27 18:18:02 +00:00
Royce Remer
b7aac5ef9a allow filtering /repos/{owner}/{repo}/pulls by target base branch queryparam (#33684)
Co-authored-by: Royce Remer <rremer@salesforce.com>
Co-authored-by: delvh <dev.lh@web.de>
2025-02-27 17:50:44 +00:00
wxiaoguang
01156f9cc4 Show info about maintainers are allowed to edit a PR (#33738)
A simple and clear approach. The existing test
TestPullCompare_EnableAllowEditsFromMaintainer should be good enough.

Fix #21280



![image](https://github.com/user-attachments/assets/b685950b-4095-45ad-b913-425f840f2876)
2025-02-27 16:47:00 +00:00
wxiaoguang
8db8a3b0d1 Improve admin user view page (#33735)
1. show more user types
2. show prohibited state
2025-02-27 17:47:37 +08:00
GiteaBot
0e477b590d [skip ci] Updated translations via Crowdin 2025-02-27 00:32:24 +00:00
Quentin
793c0e1fa6 Align sidebar gears to the right (#33721)
Currently, the issue/pr sidebar is hard to read visually. One of the
reason is that the gear icons make reading difficult because they are
"in the way" when reading, and not aligned together.

This PR proposes to align them on the right.

Actions are also better highlighted this way.

## Screenshots

### Issue

| Before this PR | After this PR |
| --- | --- |
| <img width="322" alt="Capture d’écran 2025-02-25 à 19 59 39"
src="https://github.com/user-attachments/assets/efdd13af-7b22-4f2b-8e65-dd17d6f3ffad"
/> | <img width="322" alt="Capture d’écran 2025-02-25 à 19 58 56"
src="https://github.com/user-attachments/assets/eeacc3f4-5e2c-4558-a4b3-0f1ab4742107"
/> |

### Pull Request


| Before this PR | After this PR |
| --- | --- |
| <img width="322" alt="Capture d’écran 2025-02-25 à 20 16 12"
src="https://github.com/user-attachments/assets/c274b58b-ad50-4ad8-b3da-91dbabd1b120"
/> | <img width="322" alt="Capture d’écran 2025-02-25 à 20 15 54"
src="https://github.com/user-attachments/assets/ecfd6d60-a525-4767-872d-2ef84030d81e"
/> |

Signed-off-by: Quentin Guidée <quentin.guidee@gmail.com>
Co-authored-by: Giteabot <teabot@gitea.io>
2025-02-27 00:03:23 +02:00
GiteaBot
6c5951dabd [skip ci] Updated translations via Crowdin 2025-02-26 00:32:38 +00:00
Lunny Xiao
74c8e95e87 Fix inconsistent closed issue list icon (#33722)
Fixe #33718 

Before 

![image](https://github.com/user-attachments/assets/2c77e249-a118-4471-8c63-ead4fe0f6336)

After 

![image](https://github.com/user-attachments/assets/c082eba8-5b21-4814-b091-c725ca46ccf3)
2025-02-25 15:27:23 -08:00
silverwind
2aa59ba9e5 Update files-changed and labeler globs (#33720)
Few tweaks, should be self-explanatory.
2025-02-25 11:33:23 -08:00
silverwind
b35a9da14c Enable @typescript-eslint/no-use-before-define (#33715)
The [rule](https://typescript-eslint.io/rules/no-use-before-define/) is
a superset of the eslint base rule, and I tested it with
https://github.com/go-gitea/gitea/pull/33514#discussion_r1969795271
where it does not raise an error for cyclic types.
2025-02-25 16:30:31 +01:00
GiteaBot
38ccc8e3e4 [skip ci] Updated translations via Crowdin 2025-02-25 00:35:17 +00:00
techknowlogick
7535af20da bump x/crypto & x/oauth2 (#33704) 2025-02-24 20:15:18 +00:00
Lunny Xiao
76b7f95a27 Optimize user dashboard loading (#33686)
Fix #33582
Fix #31698

When a user login, the dashboard should load all feed belongs to him
with no any conditions. The complicated conditions should be applied
only for another user view this user's profile.
2025-02-24 11:29:32 -08:00
Kerwin Bryant
2cd2ae07a7 Add No Results Prompt Message on Issue List Page (#33699) 2025-02-24 18:24:56 +00:00
wxiaoguang
555d64d024 Always show the "rerun" button for action jobs (#33692)
And improve the mock code.
2025-02-24 08:40:46 +00:00
Arif Er
adf7018bfd Fix OCI image.version annotation for releases to use full semver (#33698)
This commit fixes the docker build workflow such that semver-tagged
releases use the full semver for the OCI
`org.opencontainers.image.version` annotation, instead of using the
major version only.

This is done by changing the order of the tags that the
`docker/metadata-action` action is told to generate. Since the tags that
the action is told to generate are all of the same priority, the first
in the list will be used to set the annotation.

There is no need to fix the other two docker build workflows, i.e., (i)
the nightly releases and (ii) the rc-tagged releases. This is because
(i) the nightly releases do not get tagged with a semver, so the issue
does not exist, and (ii) rc-tagged releases only get built with one tag,
so the issue of needing to set an order of how tags are generated is
irrelevant.

Resolves go-gitea/gitea#33697.
2025-02-24 01:37:37 -05:00
wxiaoguang
56a0a9c750 Fix git empty check and HEAD request (#33690) 2025-02-24 02:11:29 +00:00
wxiaoguang
8ae46d9684 Fix some user name usages (#33689)
1. GetUserOrgsList should "order by" lower_name
2. GetIssuePostersWithSearch should search in-case-sensitive-ly
3. LoginName should not be used as username

By the way, remove unnecessary "onGiteaRun"
2025-02-23 12:33:43 +00:00
wxiaoguang
f991807f7e Try to fix ACME path when renew (#33668)
Try to fix #32191
2025-02-23 13:12:08 +08:00
GiteaBot
9e75c54559 [skip ci] Updated translations via Crowdin 2025-02-23 00:34:45 +00:00
wxiaoguang
ead716d204 Improve Open-with URL encoding (#33666)
Fix #33665
2025-02-21 17:46:05 +00:00
Diana
a61014ea47 Fix for Maven Package Naming Convention Handling (#33678)
Make legacy package names could be listed and add tests

---------

Co-authored-by: diana.strebkova@t-systems.com <diana.strebkova@t-systems.com>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2025-02-22 01:38:49 +08:00
wxiaoguang
4adb7cad8b Improve swagger generation (#33664)
Remove most "sed" tricks

---------

Co-authored-by: silverwind <me@silverwind.io>
2025-02-21 00:04:30 -08:00
Lunny Xiao
f2fbb897f3 Deleting repository should unlink all related packages (#33653)
Fix #33634

---------

Co-authored-by: Giteabot <teabot@gitea.io>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2025-02-21 04:17:56 +00:00
Lunny Xiao
a25081f380 Fix omitempty bug (#33663)
Fix #33660
2025-02-20 12:39:21 -08:00
wxiaoguang
3ee5ee2029 Upgrade golangci-lint to v1.64.5 (#33654)
Use `usetesting` instead of deprecated `tenv`.
1. Follow up #33648
2. Make lint pass and add some comments
2025-02-21 00:05:40 +08:00
wxiaoguang
cd225d7034 Fix mCaptcha bug (#33659)
Fix #33658
2025-02-20 22:53:38 +08:00
wxiaoguang
e6759f356d Update Go dependencies (skip blevesearch, meilisearch) (#33655) 2025-02-20 22:10:54 +08:00
TheFox0x7
cc1fdc84ca Use test context in tests and new loop system in benchmarks (#33648)
Replace all contexts in tests with go1.24 t.Context()

---------

Co-authored-by: Giteabot <teabot@gitea.io>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2025-02-20 09:57:40 +00:00
Lunny Xiao
3bbc482879 Add missed changelogs (#33649)
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2025-02-20 17:31:07 +08:00
GiteaBot
21af8150b7 [skip ci] Updated translations via Crowdin 2025-02-20 00:32:10 +00:00
ericLemanissier
40faa6dc78 git graph: don't show detached commits (#33645)
Current git graph is not usable for mirrors of repos having a lot of
PRs, as can be seen at
https://demo.gitea.com/ericLemanissier/conan-center-index/graph

![image](https://github.com/user-attachments/assets/ace40dd2-3eea-4d69-8e19-10fb7224e326)


Manually running `git log --graph --date-order --all` on such a repo
indeed shows:
```
*   commit c4a34bd39d7977c8630177c5f88507000ea3e943
|\  Merge: a4bbd3ad6b 35a102c77c
| | Author: toge <toge.mail@gmail.com>
| | Date:   Wed Feb 19 08:36:41 2025 +0000
| |
| |     Merge 35a102c77cbc38d84baca0ca63466fb410336ea8 into a4bbd3ad6bb5a0f8e5117a897d8c55941f533d98
| |
| * commit 35a102c77cbc38d84baca0ca63466fb410336ea8
| | Author: toge <toge.mail@gmail.com>
| | Date:   Wed Feb 19 17:36:35 2025 +0900
| |
| |     update 4.4.2
| |
| | * commit 5d610f4fd3c0428731e402a2f618fad9ce055875
| |/| Merge: a4bbd3ad6b fe916fb70a
|/| | Author: Antony Peacock <ant.peacock@gmail.com>
| | | Date:   Wed Feb 19 08:31:30 2025 +0000
| | |
| | |     Merge fe916fb70a8bf49503cce70a5c7124bcc4314ddc into a4bbd3ad6bb5a0f8e5117a897d8c55941f533d98
| | |
| | * commit fe916fb70a8bf49503cce70a5c7124bcc4314ddc
| | | Author: Antony Peacock <ant.peacock@gmail.com>
| | | Date:   Wed Feb 19 08:31:18 2025 +0000
| | |
| | |     Remove parquet cmakelist patch
| | |
| | | * commit 9f6d2759d650ec3c86d01bb940e829e7e14220c2
| |_|/| Merge: a4bbd3ad6b f0963429b0
|/| | | Author: Thomas Sedlmair <thomas.sedlmair@googlemail.com>
| | | | Date:   Wed Feb 19 08:03:08 2025 +0100
| | | |
| | | |     Merge f0963429b0952499da0da7e559f8d53387097307 into a4bbd3ad6bb5a0f8e5117a897d8c55941f533d98
| | | |
| | | * commit f0963429b0952499da0da7e559f8d53387097307
| |_|/  Author: Thomas Sedlmair <thomas.sedlmair@googlemail.com>
|/| |   Date:   Wed Feb 19 08:01:43 2025 +0100
| | |
| | |       added cwt-cucumber 2.5
| | |
```

On the other hand, running `git log --graph --date-order --branches
--tags` returns the expected:
```
* commit a4bbd3ad6bb5a0f8e5117a897d8c55941f533d98 (HEAD -> master)
| Author: Dan <mstr.danila@gmail.com>
| Date:   Fri Feb 14 18:46:11 2025 +0200
|
|     grpc: add version 1.69.0 (#26446)
|
|     * grpc: add version 1.69.0
|
|     * add cmake tool requires
|
|     ---------
|
|     Co-authored-by: Luis Caro Campos <3535649+jcar87@users.noreply.github.com>
|
* commit a7868807cb2e21206ebf95278cb588f29a3e2205
| Author: Guillaume Egles <gegles@users.noreply.github.com>
| Date:   Thu Feb 13 05:44:35 2025 -0800
|
|     openssl: add versions `3.0.16`, `3.1.8`, `3.2.4`, `3.3.3`, `3.4.1`, stop publishing revisions for version `3.0.15` (#26578)
|
* commit 86057d3e63ac71e2fe48c07bb301f2d54187044d
| Author: Luis Caro Campos <3535649+jcar87@users.noreply.github.com>
| Date:   Thu Feb 13 13:34:41 2025 +0000
|
|     android-ndk: dont set LD and AS variables (#26581)
|
|     * android-ndk: dont set LD and AS variables
|
|     * android-ndk: refactor test package
|
* commit 123e382fafd2f5e811e10faac02efc275c45ec2a
| Author: Nikita <root.kidik@gmail.com>
| Date:   Thu Feb 13 12:29:39 2025 +0300
|
|     libffi: fix conditionals when building on Windows (#26500)
|
|     * fix: add missing or `clang`
|
|     * fix: libffi - always require as tool `automake`
```
2025-02-19 10:35:08 -08:00
wxiaoguang
c2e23d3301 Fix PR web route permission check (#33636)
See the FIXME comment in code. Otherwise, if a repo's issue unit is
disabled, then the PRs can't be edited anymore.

By the way, make the permission log output look slightly better.

---------

Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
Co-authored-by: metiftikci <metiftikci@hotmail.com>
2025-02-19 00:55:19 +00:00
metiftikci
84d2159ef6 fix: add missing locale (#33641)
this removed in #23113 but still using in `head_navbar.tmpl`
2025-02-18 16:29:17 -08:00
Kerwin Bryant
ce65613690 Fix Untranslated Text on Actions Page (#33635)
Fix the problem of untranslated text on the actions page

Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2025-02-18 11:29:08 +00:00
Guillaume
748b731612 Improve button layout on small screens (#33633)
Fix #33160 

Better "New Repository" & "New Migration" buttons on home page.

---------

Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2025-02-18 11:02:40 +00:00
yp05327
241f799edf Update README screenshots (#33347)
@lunny @techknowlogick
Wait for the update of https://dl.gitea.com/screenshots
Can you move all old screenshots into
https://dl.gitea.com/screenshots/old ?
Then run the action to upload new screenshots to
https://dl.gitea.com/screenshots

Follow #33149.
As I mentioned here:
https://github.com/go-gitea/gitea/pull/33149#issuecomment-2581787057,
the prepare process is almost finished.
The backend technical is using newly added `workflow_dispatch` feature
for Gitea Action to take the screenshots automatically.
Then we can easily sync the screenshots to the latest version without
annoying manual work.
Get more information from https://gitea.com/gitea/deployment
2025-02-18 00:10:30 -08:00
Lunny Xiao
9f560d47c9 Make actions URL in commit status webhooks absolute (#33620)
Gitea Actions generated target url doesn't contain host and port. So we
need to include them for external webhook visiting.

Fix #33603

---------

Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2025-02-18 02:20:18 +00:00
wxiaoguang
15e020eec8 Refactor error system (#33626) 2025-02-17 12:41:03 -08:00
Lunny Xiao
7df09e31fa Move issue pin to an standalone table for querying performance (#33452)
Noticed a SQL in gitea.com has a bigger load. It seems both `is_pull`
and `pin_order` are not indexed columns in the database.

```SQL
SELECT `id`, `repo_id`, `index`, `poster_id`, `original_author`, `original_author_id`, `name`, `content`, `content_version`, `milestone_id`, `priority`, `is_closed`, `is_pull`, `num_comments`, `ref`, `pin_order`, `deadline_unix`, `created_unix`, `updated_unix`, `closed_unix`, `is_locked`, `time_estimate` FROM `issue` WHERE (repo_id =?) AND (is_pull = 0) AND (pin_order > 0) ORDER BY pin_order
```

I came across a comment
https://github.com/go-gitea/gitea/pull/24406#issuecomment-1527747296
from @delvh , which presents a more reasonable approach. Based on this,
this PR will migrate all issue and pull request pin data from the
`issue` table to the `issue_pin` table. This change benefits larger
Gitea instances by improving scalability and performance.

---------

Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2025-02-17 11:28:37 -08:00
silverwind
f5a81f9636 Run spellcheck on tools directory (#33627)
Add `tools` files to spellcheck and fixed one issue.
2025-02-17 18:39:12 +01:00
wxiaoguang
f35850f48e Refactor error system (#33610) 2025-02-16 22:13:17 -08:00
Lunny Xiao
69de5a65c2 Fix project issues list and counting (#33594)
Co-authored-by: delvh <dev.lh@web.de>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2025-02-17 05:14:56 +00:00
Lunny Xiao
5df9fd3e9c Add API to support link package to repository and unlink it (#33481)
Fix #21062

---------

Co-authored-by: Zettat123 <zettat123@gmail.com>
2025-02-16 19:18:00 -08:00
GiteaBot
50a5d6bf5d [skip ci] Updated translations via Crowdin 2025-02-17 00:33:47 +00:00
silverwind
3bbacac62c Update JS and PY dependencies (#33587)
- Update all dependencies excluding `tailwindcss` and `idiomorph`
- Tested citation, asciinema, pdf, swagger

---------

Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2025-02-16 14:14:23 +01:00
Sandro Santilli
37c4f3760c [chore] add git mailmap for proper attribution of authorship (#33612) 2025-02-16 20:49:28 +08:00
Lunny Xiao
58c124cc4f Move commits signature and verify functions to service layers (#33605)
No logic change, just move functions.
2025-02-16 12:24:07 +00:00
Sveinn Thorarinsson
62389dd08b add spacing between sign in button's icon and text (#33609)
This pull request edits the head_navbar template and adds spacing
between the icon and the text inside the sign in button of the navbar
(button which displays at the top right of Gitea's pages when the user
is not signed in).

It bugged me that there was no spacing between the button's contents so
I test ran this change quickly on my server and thought it looked a lot
better, so decided to make this pull request. Up to you to decide if you
agree that it looks better :)
2025-02-16 11:27:31 +00:00
Darren Hoo
950abfe8ee enable literal string for code search (#33590)
Close: #33588

---------

Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
Co-authored-by: Giteabot <teabot@gitea.io>
2025-02-16 11:28:06 +01:00
GiteaBot
fc1b383da9 [skip ci] Updated translations via Crowdin 2025-02-16 00:34:48 +00:00
ChristopherHX
2b8cfb557d Artifacts download api for artifact actions v4 (#33510)
* download endpoint has to use 302 redirect
* fake blob download used if direct download not possible
* downloading v3 artifacts not possible

New repo apis based on GitHub Rest V3
- GET /runs/{run}/artifacts (Cannot use run index of url due to not
being unique)
- GET /artifacts
- GET + DELETE /artifacts/{artifact_id}
- GET /artifacts/{artifact_id}/zip
- (GET /artifacts/{artifact_id}/zip/raw this is a workaround for a http
302 assertion in actions/toolkit)
- api docs removed this is protected by a signed url like the internal
artifacts api and no longer usable with any token or swagger
  - returns http 401 if the signature is invalid
    - or change the artifact id
    - or expired after 1 hour

Closes #33353
Closes #32124

---------

Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2025-02-16 08:32:54 +08:00
Lunny Xiao
01bf8da02e Fix bug when get commit (#33602)
Fix #33595
2025-02-15 15:16:19 -08:00
ericLemanissier
57997f1518 Fix mirror bug (#33597)
follows-up be4e961240883778c44d9651eaaf9ab8723bbbb0

Fix https://github.com/go-gitea/gitea/issues/33200

---------

Co-authored-by: Giteabot <teabot@gitea.io>
2025-02-15 18:29:44 +08:00
silverwind
1ba7cbbfd6 Fix typo in HTML attribute (#33599) 2025-02-14 10:59:37 -05:00
Zettat123
8aede14b1d Use default Git timeout when checking repo health (#33593) 2025-02-14 15:13:56 +00:00
Lunny Xiao
70327d6a92 Improve commits list performance to reduce unnecessary database queries (#33528)
When listing commits, Gitea attempts to retrieve the actual user based
on the commit email. Querying users one by one from the database is
inefficient. This PR optimizes the process by batch querying users by
email, reducing the number of database queries.
2025-02-14 00:05:55 -08:00
Lunny Xiao
f232d8f530 Performance optimization for pull request files loading comments attachments (#33585) 2025-02-14 06:49:58 +00:00
wxiaoguang
b426e383fe Fix PR's target branch dropdown (#33589)
Fix #33586

It only moves `PrepareBranchList` and `retrieveAssigneesData` to before
the `CanModifyIssueOrPull` check, and adds more comments
2025-02-14 05:21:31 +00:00
techknowlogick
d88b012525 go1.24 (#33562)
update to use go1.24

---------

Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2025-02-13 18:00:00 +08:00
Exploding Dragon
fba365b425 Only show the latest version in the Arch index (#33262)
Only show the latest version of the package in the arch repo.

closes #33534

---------

Co-authored-by: Giteabot <teabot@gitea.io>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2025-02-13 01:24:44 +00:00
GiteaBot
42d817e814 [skip ci] Updated translations via Crowdin 2025-02-13 00:31:39 +00:00
silverwind
3e39583bb5 Enable eslint for commonjs (#33575) 2025-02-12 22:47:54 +00:00
wxiaoguang
e741448a14 Fix various problems (artifact order, api empty slice, assignee check, fuzzy prompt, mirror proxy, adopt git) (#33569)
* Make artifact list output a stable order
* Fix #33506
* Fix #33521
* Fix #33288
* Fix #33196
* Fix #33561
2025-02-13 03:26:27 +08:00
silverwind
bcd1317d17 Switch to @vitest/eslint-plugin (#33573)
Package has been renamed and now also provides the globals so we can
replace two dependencies with one.

Ref: https://github.com/vitest-dev/eslint-plugin-vitest/issues/537
2025-02-12 11:08:34 -05:00
wxiaoguang
f58f5bb3d8 Avoid duplicate SetContextValue call (#33564)
And fix FIXME and TODO
2025-02-12 14:25:46 +08:00
Zettat123
06f1065636 Add a transaction to pickTask (#33543)
In the old `pickTask`, when getting secrets or variables failed, the
task could get stuck in the `running` status (task status is `running`
but the runner did not fetch the task). To fix this issue, these steps
should be in one transaction.

---------

Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2025-02-12 00:09:43 +08:00
wxiaoguang
245ac321c3 Fix context usage (#33554)
Some old code use direct type-casting to get context, it causes
problems.

This PR fixes all legacy problems and use correct `ctx.Value` to get
low-level contexts.

Fix #33518
2025-02-11 16:46:03 +08:00
Jason Song
e9b98aef44 Enhance routers for the Actions runner operations (#33549)
- Find the runner before deleting
- Move the main logic from `routers/web/repo/setting/runners.go` to
`routers/web/shared/actions/runners.go`.

---------

Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2025-02-11 01:39:10 +00:00
GiteaBot
217ffe5492 [skip ci] Updated translations via Crowdin 2025-02-11 00:32:23 +00:00
silverwind
b3302748fa Run yamllint with strict mode, fix issue (#33551)
Previously yamllint would issue warnings for certain things, while still
exiting with zero. Now warnings are treated like errors and will cause
non-zero exit:

```
  -s, --strict          return non-zero exit code on warnings as well as errors
```
2025-02-10 22:33:40 +00:00
Jason Song
c422f179dd Enhance routers for the Actions variable operations (#33547)
- Find the variable before updating or deleting
- Move the main logic from `routers/web/repo/setting/variables.go` to
`routers/web/shared/actions/variables.go`.

---------

Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
Co-authored-by: Giteabot <teabot@gitea.io>
2025-02-11 04:44:04 +08:00
jason19970210
e3adb686bb enhancement: add additional command hints for PowerShell & CMD (#33548)
- resolving wrong signature calculations for SSH key verification

Fixed #22693

---------

Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
Co-authored-by: Giteabot <teabot@gitea.io>
2025-02-11 04:14:37 +08:00
wxiaoguang
30993e9508 Feature: Support workflow event dispatch via API (#33545)
Fix: https://github.com/go-gitea/gitea/issues/31765 (Re-open #32059)

---------

Co-authored-by: Bence Santha <git@santha.eu>
Co-authored-by: Bence Sántha <7604637+bencurio@users.noreply.github.com>
Co-authored-by: Christopher Homberger <christopher.homberger@web.de>
2025-02-11 03:05:42 +08:00
Kerwin Bryant
085f273d19 Optimize the dashboard (#32990)
before:

![image](https://github.com/user-attachments/assets/d0b432e4-a521-4540-a489-d18b9c265674)

after:

![image](https://github.com/user-attachments/assets/dbb8b387-d150-41e2-b12b-f9d8450e36d7)
-----

![image](https://github.com/user-attachments/assets/40dcd71e-344b-4043-9811-77227c71aed9)
-----

Optimize the dashboard by adding welcoming messages or quick action
entry points (such as adding a new repository or organization) to ensure
that new users are not greeted by a blank page upon logging in.

---------

Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2025-02-11 01:24:34 +08:00
Lunny Xiao
72518a8dab Rework suggestion backend (#33538)
Fix #33522 

The suggestion backend logic now is

- If the keyword is empty, returned the latest 5 issues/prs with index
desc order
- If the keyword is digital, find all issues/prs which `index` has a
prefix with that, with index asc order
- If the keyword is non-digital or if the queried records less than 5,
searching issues/prs title with a `like`, with index desc order

## Empty keyword
<img width="310" alt="image"
src="https://github.com/user-attachments/assets/1912c634-0d98-4eeb-8542-d54240901f77"
/>

## Digital
<img width="479" alt="image"
src="https://github.com/user-attachments/assets/0356a936-7110-4a24-b21e-7400201bf9b8"
/>

## Digital and title contains the digital
<img width="363" alt="image"
src="https://github.com/user-attachments/assets/6e12f908-28fe-48de-8ccc-09cbeab024d4"
/>

## non-Digital
<img width="435" alt="image"
src="https://github.com/user-attachments/assets/2722bb53-baa2-4d67-a224-522a65f73856"
/>
<img width="477" alt="image"
src="https://github.com/user-attachments/assets/06708dd9-80d1-4a88-b32b-d29072dd1ba6"
/>

---------

Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2025-02-10 16:24:05 +00:00
wxiaoguang
704b65e012 Revert "Feature: Support workflow event dispatch via API (#32059)" (#33541)
This reverts commit 523751dc82bbb9d3f8d413f232e23ab0476eb4d4.
2025-02-10 17:44:42 +08:00
Bence Sántha
523751dc82 Feature: Support workflow event dispatch via API (#32059)
ref: https://github.com/go-gitea/gitea/issues/31765

---------

Signed-off-by: Bence Santha <git@santha.eu>
Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
Co-authored-by: Christopher Homberger <christopher.homberger@web.de>
2025-02-10 05:23:57 +08:00
wxiaoguang
06088ec672 Remove "class-name" from svg icon (#33540)
Only use "class" attribute
2025-02-09 22:39:54 +02:00
Kerwin Bryant
a52720b5b4 Add "No data available" display when list is empty (#33517)
Add a "No data available" message to be displayed when the list has no
data. This improves the user experience by providing clear feedback in
an empty state.

---------

Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2025-02-09 00:13:41 +08:00
mscherer
063c23e1bc Add a option "--user-type bot" to admin user create, improve role display (#27885)
Partially solve #13044

Fix #33295

---------

Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2025-02-07 08:41:55 +00:00
TheFox0x7
1ec8d80fa3 refactor: decouple context from migration structs (#33399)
Use context as much as possible.

---------

Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2025-02-07 05:37:32 +00:00
Lunny Xiao
466cc725bc Move gitgraph from modules to services layer (#33527)
Just move, no code change.
2025-02-07 03:05:25 +00:00
Alexander McRae
a1f1bccd7a Add go wrapper around git diff-tree --raw -r -M (#33369)
* Implemented calling git diff-tree
 * Ensures wrapper function is called with valid arguments
 * Parses output into go struct, using strong typing when possible
2025-02-07 00:58:28 +00:00
GiteaBot
dbc18f400a [skip ci] Updated translations via Crowdin 2025-02-07 00:31:35 +00:00
ChristopherHX
0070ffe560 Update MAINTAINERS (#33529)
* Add myself to the maintainers file
2025-02-07 08:10:49 +08:00
Kerwin Bryant
40426addfa Add cropping support when modifying the user/org/repo avatar (#33498)
Fixed #33321

---------

Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2025-02-06 21:07:44 +08:00
GiteaBot
943cc4f989 [skip ci] Updated translations via Crowdin 2025-02-06 00:31:49 +00:00
John Smith
a025fa70ab Add alphabetical project sorting (#33504)
Fixes #33500
2025-02-05 19:09:43 +00:00
wxiaoguang
fa0c8ae50f Refactor gitdiff test (#33507) 2025-02-05 16:09:58 +00:00
techknowlogick
7e596bd7a9 add timetzdata build tag to binary releases (#33463)
`timetzdata` is already used in the docker images, this includes them
for the binary release files too.

Related to #33235 (I don't have a windows machine setup to test this
though)

---------

Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2025-02-05 04:17:08 +00:00
Lunny Xiao
6999651b6d Fix unnecessary comment when moving issue on the same project column (#33496)
Fix #33482
2025-02-05 11:51:10 +08:00
GiteaBot
a6819570be [skip ci] Updated translations via Crowdin 2025-02-05 00:32:05 +00:00
wxiaoguang
09a3b07f10 Refactor web route handler (#33488) 2025-02-05 02:14:03 +08:00
Henrique Corrêa
d0f4e92563 Reject star-related requests if stars are disabled (#33208)
This PR fixes #33205.

If stars are disabled:
* The `.../repo/stars` page returns a 403 Forbidden error
* Star-related API endpoints return a 403 Forbidden error saying `Stars are disabled.`
* Same for action endpoints

---------

Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2025-02-04 13:21:23 +08:00
Lunny Xiao
a4676db7dd Fix commit status events (#33320)
Fix #32873 
Fix #33201 
~Fix #33244~
~Fix #33302~

depends on ~#33396~

A part of this PR should be backported to v1.23 manually.
2025-02-04 03:25:59 +00:00
GiteaBot
3c46cd6aae [skip ci] Updated translations via Crowdin 2025-02-04 00:31:03 +00:00
Lunny Xiao
3ebfc77e83 Disable cron task to update license (#33486)
Help #33467
The file can be changed or removed after that issue is resolved.
2025-02-03 22:52:20 +02:00
GiteaBot
ed84f3737a [skip ci] Updated licenses and gitignores 2025-02-03 00:32:15 +00:00
Typed SIGTERM
50873c1925 Correct bot label vertical-align (#33477) 2025-02-02 18:42:30 +00:00
wxiaoguang
5dddcc1773 chore: fix some trivial problems and TODOs (#33473)
1. Fix incorrect `MentionCount` (actually it seems to be deadcode,
affects nothing)
2. Remove fallback sha1 support for time limit token
3. Use route middleware `reqRepoActionsWriter` for `ArtifactsDeleteView`
4. Use clearer message "Failed to authenticate user" instead of "Verify"
when auth fails
5. `tests/integration/benchmarks_test.go` is not quite right, actually
it is never used, so delete it.
6. Remove or update TODO comments
2025-02-02 18:16:56 +00:00
K Kovacs
34692a20b1 Worktime tracking for the organization level (#19808)
Dear Gitea team,

first of all, thanks for the great work you're doing with this project.

I'm planning to introduce Gitea at a client site, and noticed that while
there is time recording, there are no project-manager-friendly reports
to actually make use of that data, as were also mentioned by others in
#4870 #8684 and #13531.

Since I had a little time last weekend, I had put together something
that I hope to be a useful contribution to this great project (while of
course useful for me too).

This PR adds a new "Worktime" tab to the Organisation level. There is a
date range selector (by default set to the current month), and there are
three possible views:

- by repository,
- by milestone, and
- by team member.

Happy to receive any feedback!

There are several possible future improvements of course (predefined
date ranges, charts, a member time sheet, matrix of repos/members, etc)
but I hope that even in this relatively simple state this would be
useful to lots of people.

<img width="1161" alt="Screen Shot 2022-05-25 at 22 12 58"
src="https://user-images.githubusercontent.com/118010/170366976-af00c7af-c4f3-4117-86d7-00356d6797a5.png">

Keep up the good work!

Kristof

---------

Co-authored-by: user <user@kk-git1>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2025-02-03 01:51:12 +08:00
wxiaoguang
869f8fdbe4 Skip deletion error for action artifacts (#33476) 2025-02-02 09:48:19 -05:00
Lunny Xiao
aec0b7ec34 Update .changelog file to add performance label group (#33472) 2025-02-02 06:40:39 +00:00
6543
fcfe1fb0fc actions view: move loading of task attributes etc... into own func (#31494)
just a smal refactor to make the function length smaler ... and code
more reusable in the future
2025-02-02 03:39:01 +00:00
GiteaBot
9cd88ef8c7 [skip ci] Updated translations via Crowdin 2025-02-02 00:33:31 +00:00
Typed SIGTERM
47bf836310 Update feishu icon (#33470) 2025-02-01 14:08:32 +00:00
Bruno Sofiato
040c830dec Inclusion of rename organization api (#33303)
This adds an endpoint (`/orgs/{org}/rename`) to rename organizations.

I've modeled the endpoint using the rename user endpoint --
`/admin/users/{username}/rename` -- as base.

It is the 1st time I wrote a new API endpoint (I've tried to follow the
rename users endpoint code while writing it). So feel free to ping me if
there is something wrong or missing.

Resolves #32995

---------

Signed-off-by: Bruno Sofiato <bruno.sofiato@gmail.com>
Co-authored-by: delvh <dev.lh@web.de>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2025-02-01 00:59:49 +00:00
GiteaBot
5b83203f37 [skip ci] Updated translations via Crowdin 2025-02-01 00:33:46 +00:00
wxiaoguang
1ab5938e82 Hide/disable unusable UI elements when a repository is archived (#33459)
And by the way, remove some jQuery code
2025-01-31 20:47:31 +08:00
wxiaoguang
0e8738b4b6 Fix SSH LFS memory usage (#33455)
Fix #33448
2025-01-31 19:05:48 +08:00
wxiaoguang
4f3cc26b4e Revert empty lfs ref name (#33454)
Fix #33453
2025-01-31 18:03:11 +08:00
silverwind
05e9063013 Update @github/text-expander-element, adapt type imports (#33449)
Followup to https://github.com/go-gitea/gitea/pull/33435, upstream issue
is fixed so the imports are clean now.
2025-01-31 02:50:18 +00:00
wxiaoguang
5a7b42dac7 Support choose email when creating a commit via web UI (more) (#33445)
Follow #33432
2025-01-31 02:36:18 +00:00
wxiaoguang
b57d9f41d4 Fix issue sidebar dropdown keyboard support (#33447)
Just a quick fix, fix #33444
2025-01-30 22:54:50 +00:00
wxiaoguang
f24d73ab5f Fix "redirect link" handling (#33440)
`a%2fb` should not redirect to `a/b`

---------

Co-authored-by: delvh <dev.lh@web.de>
2025-01-31 04:12:14 +08:00
Lunny Xiao
f88dbf86b3 Refactor repository transfer (#33211)
- Both have `RejectTransfer` and `CancelTransfer` because the permission
checks are not the same. `CancelTransfer` can be done by the doer or
those who have admin permission to access this repository.
`RejectTransfer` can be done by the receiver user if it's an individual
or those who can create repositories if it's an organization.

- Some tests are wrong, this PR corrects them.

---------

Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2025-01-30 05:40:44 +00:00
silverwind
48183d2b05 Enable two more strict options in tsconfig (#33438)
These have no violations so are safe to enable

- https://www.typescriptlang.org/tsconfig/#strictBindCallApply
- https://www.typescriptlang.org/tsconfig/#strictBuiltinIteratorReturn
2025-01-30 05:15:35 +00:00
Lunny Xiao
75940a0191 Add tests for webhook and fix some webhook bugs (#33396)
This PR created a mock webhook server in the tests and added integration
tests for generic webhooks.
It also fixes bugs in package webhooks and pull request comment
webhooks.
2025-01-30 03:09:48 +00:00
wxiaoguang
256b94e9e9 Support choose email when creating a commit via web UI (#33432)
Initial PR for #24469
2025-01-30 01:24:57 +00:00
Rowan Bohde
ac2d97cb61 Link to tree views of submodules if possible (#33424)
This is a follow-up to https://github.com/go-gitea/gitea/pull/33097. 

When linking a submodule at a commit in either the repo view, or a diff
when adding a new submodule, link to the tree view of that submodules
intead of the individual commit. This shows the user the full tree,
instead of the diff of the commit.

This makes the assumption that the tree for a given SHA is at
`<repo_url>/tree/<sha>`. This URL format is supported by both Github &
Gitlab, but not Gitea. To fix this, add a redirect from
`<username>/<repo>/tree/<ref>` to `<username>/<repo>/src/<ref>`, so that
Gitea can support this URL structure.
2025-01-30 00:09:52 +00:00
silverwind
dc7ddaee2a Update @github/text-expander-element to 2.9.0 (#33435)
Update and use their newly exported types. Tested, works.

The import path is a bit suboptimal, to be fixed once
https://github.com/github/text-expander-element/pull/75 is merged and
released.

Co-authored-by: Giteabot <teabot@gitea.io>
2025-01-29 23:38:53 +00:00
wxiaoguang
4ffc54f59a Refactor user & avatar (#33433)
1. better GetPossibleUserByID logic
2. fix some function name & comment typos
3. do not re-generate avatar if one exists
2025-01-30 07:33:50 +08:00
GiteaBot
a89c735303 [skip ci] Updated translations via Crowdin 2025-01-29 00:31:19 +00:00
wxiaoguang
8c4f0f02ef Refactor user package (#33423)
and avoid global variables
2025-01-29 01:14:35 +02:00
Zettat123
a9577e0808 Fix GetCommitBranchStart bug (#33298)
Fix #33265
Fix #33370

This PR also fixes some bugs in `TestGitGeneral`.
2025-01-28 02:59:15 +00:00
silverwind
8f433132e1 Update stylelint config (#33419)
- Inherit stylelint config from
[`stylelint-config-recommended`](https://github.com/stylelint/stylelint-config-recommended),
removed all stylelint core rule options that were either already in
their config or disabled.
- `no-descending-specificity` diverges from their config, seems to much
work currently.
- Tweaked a few rules.
- Added
[`stylelint-define-config`](https://github.com/stylelint-types/stylelint-define-config)
so that typescript can validate the config.
2025-01-28 02:34:01 +00:00
GiteaBot
121e4c9624 [skip ci] Updated translations via Crowdin 2025-01-28 00:31:19 +00:00
silverwind
8cd10f7f3b Updates for poetry 2.0 (#33415)
- Remove removed
[`no-setuptools`](https://github.com/python-poetry/poetry/pull/9331)
option, it's the default now
- Ran `make update-py` under poetry 2.0.1 which updated the lockfile

Also see https://github.com/python-poetry/poetry/releases/tag/2.0.0
2025-01-27 21:57:14 +00:00
wxiaoguang
182e3896bf Fix flex width (#33414)
Fix #33409
2025-01-27 17:09:20 +00:00
Lunny Xiao
77d14fb6d3 Fix system admin cannot fork or get private fork with API (#33401)
Fix #33368
2025-01-27 16:25:14 +00:00
Lunny Xiao
dcd3014567 Add pubdate for repository rss and add some tests (#33411)
Fix #33291
2025-01-27 23:58:46 +08:00
TheFox0x7
6ca91f555a User facing messages for AGit errors (#33012)
Adds user facing messages to errors when submitting agit pull request
Tries to highlight the returned error more and fixes agit suggestion to
create PR on first submission.

Closes: https://github.com/go-gitea/gitea/issues/32965

---------

Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2025-01-27 02:33:39 +00:00
Wesley van Tilburg
c79adf00b8 Add basic auth support to rss/atom feeds (#33371)
Allows RSS readers to access private feeds using their basic auth
capabilities. Not all clients feature the ability to add cookies or
headers.

fixes #32458 

Tested with miniflux

no credentials:

![image](https://github.com/user-attachments/assets/8c3369f2-1cf6-4ce3-ac6e-84447e454928)


basic auth entered:

![image](https://github.com/user-attachments/assets/c93ff22c-1429-4a80-898f-91d9f35c7c61)

![image](https://github.com/user-attachments/assets/60d83afd-9dde-4973-a440-ff8138799e87)

---------

Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2025-01-27 02:07:39 +00:00
hiifong
26b51aa032 Optimize makefile help information generation (#33390)
Get help information from the target's comments.

![image](https://github.com/user-attachments/assets/ee259545-99b7-4163-a8da-011159f8301b)
2025-01-27 01:44:09 +00:00
wxiaoguang
517a367abe Use ProtonMail/go-crypto to replace keybase/go-crypto (#33402)
Fix #33400

The keybase/go-crypto is no longer maintained and it generates malformed
signatures, ProtonMail/go-crypto is the actively maintained fork.
2025-01-27 09:14:08 +08:00
GiteaBot
fae69bc6d4 [skip ci] Updated translations via Crowdin 2025-01-27 00:32:12 +00:00
Lunny Xiao
3e7ec826d3 Add missed auto merge feed message on dashboard (#33309) 2025-01-26 18:33:05 +00:00
silverwind
9875f9b9b8 Clone button enhancements (#33362)
- Add box-shadow to default tippy theme
- Make colors for tabs match the ones from `.ui.tabular.menu`
- Remove tippy arrow and slightly offset tooltip closer to the button
- Fix setting of `aria-haspopup` when default role is used with tippy

---------

Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2025-01-27 02:07:29 +08:00
wxiaoguang
e663c4a7f0 Fix issue suggestion bug (#33389)
Fix #33388
2025-01-26 13:13:32 +00:00
GiteaBot
2cc65e356e [skip ci] Updated translations via Crowdin 2025-01-26 00:32:05 +00:00
silverwind
078ef6db89 Update tool dependencies (#33392)
Update all tool dependencies to latest versions.
2025-01-25 20:14:09 +00:00
wxiaoguang
2c1ff8701a Refactor context flash msg and global variables (#33375)
1. add `GetSiteCookieFlashMessage` to help to parse flash message
2. clarify `handleRepoHomeFeed` logic
3. remove unnecessary global variables, use `sync.OnceValue` instead
4. add some tests for `IsUsableUsername` and `IsUsableRepoName`
2025-01-25 14:36:47 +00:00
wxiaoguang
6a516a0d14 Do not show unnecessary commit sign lock icon (#33387)
Fix #33385
2025-01-25 19:32:35 +08:00
wxiaoguang
7da8a01d39 Fix js error when edit issue (#33384) 2025-01-25 09:37:25 +08:00
wxiaoguang
06ff9b6256 Do not access GitRepo when a repo is being created (#33380) 2025-01-24 18:27:36 +00:00
silverwind
642e8c1122 Repo homepage styling tweaks (#33289)
Reduce it to a value that results in `.repo-home-sidebar-top` and
`.repo-home-sidebar-bottom` having 240px content width, the same as
GitHub.

Before:
<img width="1333" alt="Screenshot 2025-01-15 at 18 28 34"
src="https://github.com/user-attachments/assets/cf0fa21b-87be-40e3-a6cd-26d146bce9cc"
/>

After:
<img width="1330" alt="Screenshot 2025-01-15 at 18 28 27"
src="https://github.com/user-attachments/assets/28acd837-10f4-4176-b8a0-510cd28c8b8d"
/>
2025-01-24 17:35:28 +00:00
Typed SIGTERM
9e028d8d57 Fix comment header padding (#33377) 2025-01-25 01:09:57 +08:00
GiteaBot
3e1b63f75b [skip ci] Updated translations via Crowdin 2025-01-24 00:31:03 +00:00
Lunny Xiao
e94f37f95e Refactor webhook events (#33337)
Extract from #33320

This PR uses a map instead of a struct to store webhook event
information. It removes many duplicated functions and makes the logic
clearer.
2025-01-23 18:53:06 +00:00
yp05327
594b8350b1 Add missing POPULATE_SQUASH_COMMENT_WITH_COMMIT_MESSAGES in app.example.ini (#33363)
Ref:
https://docs.gitea.com/next/administration/config-cheat-sheet?_highlight=populate_squash_comment_with_commit_messages#repository---pull-request-repositorypull-request
2025-01-23 18:26:39 +00:00
GiteaBot
340d9ec42d [skip ci] Updated translations via Crowdin 2025-01-23 00:31:02 +00:00
yp05327
a0b3d9add0 Support disable passkey auth (#33348)
Fix #33314

---------

Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2025-01-22 22:58:36 +00:00
silverwind
d64c849d16 Update JS dependencies (#33359)
Fixes: https://github.com/go-gitea/gitea/security/dependabot/88
Fixes: https://github.com/go-gitea/gitea/security/dependabot/87

Tested Katex, works as expected.
2025-01-22 23:33:02 +01:00
silverwind
c7f4ca2653 Enable Typescript noImplicitAny (#33322)
Enable `noImplicitAny` and fix all issues.

---------

Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2025-01-22 15:11:51 +08:00
wxiaoguang
6fe4d1c038 Remove duplicate "ResponseWriter.Status" method (#33346) 2025-01-22 06:37:52 +00:00
silverwind
abe743df79 Fix code button alignment (#33345)
Fixes: https://github.com/go-gitea/gitea/issues/33344

Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2025-01-22 02:24:27 +00:00
GiteaBot
3682231f17 [skip ci] Updated translations via Crowdin 2025-01-22 00:31:50 +00:00
wxiaoguang
7069369e03 Support performance trace (#32973)
1. Add a OpenTelemetry-like shim-layer to collect traces
2. Add a simple builtin trace collector and exporter, end users could
download the diagnosis report to get the traces.

This PR's design is quite lightweight, no hard-dependency, and it is
easy to improve or remove. We can try it on gitea.com first to see
whether it works well, and fine tune the details.

---------

Co-authored-by: silverwind <me@silverwind.io>
2025-01-21 18:57:07 +00:00
wxiaoguang
2cb3946496 Make issue suggestion work for all editors (#33340)
And do not handle special keys when the text-expander popup exists
2025-01-21 19:33:45 +08:00
wxiaoguang
46d1e91aed Fix issue count (#33338)
Fix #33336
2025-01-21 18:53:44 +08:00
GiteaBot
2e42e96ce2 [skip ci] Updated translations via Crowdin 2025-01-21 00:31:12 +00:00
wxiaoguang
6cc1067884 Fix incorrect ref commit ID usage (#33331)
After the RefName refactoring, the `ctx.Repo.CommitID` is only set when
there is a `RepoRefByType` middleware.

Many handlers do not use that middleware and they only use "default
branch"
2025-01-20 07:43:49 +00:00
wxiaoguang
39de2955fd Improve sync fork behavior (#33319)
Fix #33271

Suppose there is a `branch-a` in fork repo:

1. if `branch-a` exists in base repo: try to sync `base:branch-a` to `fork:branch-a`
2. if `branch-a` doesn't exist in base repo: try to sync `base:main` to `fork:branch-a`
2025-01-20 15:17:47 +08:00
wxiaoguang
6073e2f1bb Refactor response writer & access logger (#33323)
And add comments & tests
2025-01-20 06:25:17 +00:00
GiteaBot
13dbd260b7 [skip ci] Updated licenses and gitignores 2025-01-20 00:31:52 +00:00
Michael Vetter
076d122f34 Fix typo in documentation of GetBranchNames() (#33330) 2025-01-19 18:41:15 -05:00
CrimsonEdgeHope
1928918c35 Fix Account linking page (#33325)
Fix password form missing whilst linking account even with
`ENABLE_PASSWORD_SIGNIN_FORM = true`.

Remove redundant empty box in account linking sign up page when
`LinkAccountMode` is true.

---------

Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2025-01-19 20:37:22 +08:00
hiifong
b7614e2d2f Fix parentCommit invalid memory address or nil pointer dereference. (#33204)
When the parent Commit does not exist on gitea, an error will be
reported when opening the Commit details page: invalid memory address or
nil pointer dereference.

![image](https://github.com/user-attachments/assets/4c2a9802-935f-41e9-b5b9-a4f0d745f709)

![image](https://github.com/user-attachments/assets/7b0bc15e-7f5f-4d58-8d24-fee667a799fa)
2025-01-19 02:51:43 +00:00
Vladimir Sysoev
dc2308a959 Make tracked time representation display as hours (#33315)
Estimated time represented in hours it might be convenient to
have tracked time represented in the same way to be compared and
managed.

---------

Co-authored-by: Sysoev, Vladimir <i@vsysoev.ru>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2025-01-19 09:30:44 +08:00
GiteaBot
f250ee6360 [skip ci] Updated translations via Crowdin 2025-01-19 00:33:43 +00:00
GiteaBot
fffc8550ab [skip ci] Updated translations via Crowdin 2025-01-18 00:30:24 +00:00
Chai-Shi
55e0756c68 Fix push message behavior (#33215)
Fixes #32769 by the logic from pr #33192

---------

Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2025-01-17 19:37:17 +00:00
6543
1342d48433 Add golang back to nix dev environment and pin v1.23 (#33275) 2025-01-17 12:25:33 -05:00
wxiaoguang
3b839f8dc0 Trivial fixes (#33304)
1. the error check was added for go-git, it was caused by the empty `.keep` file in the test fixtures.
2. use `PostFormValue` instead of `PostForm.Get` (`Get` needs to parse the form ahead)
3. fix incorrect container text (it should show "Images" in the header but not "OS/Arch")
4. align maven xml
5. fix closed PR color&icon
2025-01-17 08:55:02 +00:00
GiteaBot
7582eb0419 [skip ci] Updated translations via Crowdin 2025-01-17 00:31:11 +00:00
wxiaoguang
cfc6e21f06 Fix incorrect ref usages (#33301)
Fix #33297

By the way, improve some locales
2025-01-16 13:52:21 +00:00
silverwind
ab347fd0f7 Update JS and PY dependencies (#33249)
- Update all JS and PY dependencies
- Tested affected dependencies
- Disabled `async-preventdefault` lint rule because it brought up new
false-positives.
2025-01-16 09:56:41 +00:00
Kemal Zebari
2483a93fbc Only allow admins to rename default/protected branches (#33276)
Currently, anyone with write permissions to a repo are able to rename
default or protected branches.

This change follows
[GitHub's](https://docs.github.com/en/repositories/configuring-branches-and-merges-in-your-repository/managing-branches-in-your-repository/renaming-a-branch)
design by only allowing repo/site admins to change these branches.
However, it also follows are current design for protected branches and
only allows admins to modify branch names == branch protection rule
names. Glob-based rules cannot be renamed by anyone (as was already the
case, but we now catch `ErrBranchIsProtected` which we previously did
not catch, throwing a 500).
2025-01-15 20:51:49 +00:00
silverwind
4b21a6c792 Enable Typescript noImplicitThis (#33250)
- Enable https://www.typescriptlang.org/tsconfig/#noImplicitThis
- Wrap Vue Template-Syntax SFCs in
[`defineComponent`](https://vuejs.org/api/general#definecomponent) which
makes type inference and linter work better
- Move `createApp` calls outside the SFCs into separate files
- Use [`PropType`](https://vuejs.org/api/utility-types#proptype-t) where
appropriate
- Some top-level component properties changed order as dictated by the
linter
- Fix all tsc and lint issues that popped up during these refactors
2025-01-16 04:26:17 +08:00
wxiaoguang
b15d01b0ce Prepare for support performance trace (#33286)
For #32973
2025-01-15 20:05:18 +00:00
wxiaoguang
6659a381ea Fix closed dependency title (#33285)
Fix #33283
2025-01-15 23:38:03 +08:00
Zettat123
d0962ce3da Move some Actions related functions from routers to services (#33280)
Move the main logic of `generateTaskContext` and `findTaskNeeds` to the
`services` layer.

This is a part of #32751, since we need the git context and `needs` to
parse the concurrency expressions.

---------

Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2025-01-15 21:34:30 +08:00
wxiaoguang
f6dbf0e7b3 Fix incorrect TagName/BranchName usages (#33279)
Add add a new test
2025-01-15 17:34:55 +08:00
wxiaoguang
fcd096231a Simplify context ref name (#33267) 2025-01-15 11:15:47 +08:00
GiteaBot
cbf933eb4e [skip ci] Updated translations via Crowdin 2025-01-15 00:31:44 +00:00
wxiaoguang
4d399e717d Fix some broken route handlers (#33268)
Some mistakes introduced by recent refactoring PRs (some sidebar
dropdowns doesn't work)
2025-01-14 19:03:02 +00:00
wxiaoguang
1299fdb084 Add a confirm dialog for "sync fork" (#33270)
Try to quickly fix #33264
2025-01-14 18:30:43 +00:00
wxiaoguang
5eff19a77a Fix sidebar milestone link (#33269)
Fix  #33266
2025-01-14 13:01:53 -05:00
Lunny Xiao
6410c34b7f Refactor ref type (#33242)
Major changes:

1. do not sync ".keep" file during tests
2. fix incorrect route handler and empty repo handling (backported as #33253 with tests)
3. do not use `RepoRef`: most of the calls are abuses.
4. Use `git.RefType` instead of a new type definition `RepoRefType` on `context`.

---------

Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2025-01-14 15:35:34 +08:00
yp05327
3a749fc816 Fix 500 error when error occurred in migration page (#33256)
The template should be `repo/migrate/{service type}`
But input element `service` is not in the form.

Related: #33081

---------

Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2025-01-14 06:29:44 +00:00
yp05327
4672ddcdd7 Fix missing license when sync mirror (#33255)
Fix #33222
2025-01-14 05:44:12 +00:00
wxiaoguang
a98a836e76 Support public code/issue access for private repositories (#33127)
Close #8649, close #639 (will add "anonymous access" in following PRs)
2025-01-14 01:53:34 +00:00
Kemal Zebari
ecd463c2f1 Validate that the tag doesn't exist when creating a tag via the web (#33241)
Found while investigating #33210.

This line no longer makes sense because the form field "TagName" is
required, so this would mean that this code path would never be covered.
Because it isn't covered, we end up going down the "update release"
logic where we eventually set `Release.IsTag` to false (meaning it will
now be treated as a release instead of a tag).

This snapshot rewrites the condition to ensure that we aren't trying to
create a tag that already exists.

---------

Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2025-01-14 09:27:35 +08:00
GiteaBot
58ac17c005 [skip ci] Updated translations via Crowdin 2025-01-14 00:31:05 +00:00
silverwind
98d7e04767 Switch back to vue-tsc (#33248)
It supports Typescript 5.7 now, so we can switch back to the official
version.
2025-01-13 21:57:52 +01:00
Michael B.
a90af22003 Let API create and edit system webhooks, attempt 2 (#33180)
This PR fixes inconsistencies between system and default webhooks in the
Gitea API. (See also #26418)
- A system webhook is a webhook that captures events for all
repositories.
- A default webhook is copied to a new repository when it is created. 

Before this PR `POST /api/v1/admin/hooks/` creates default webhooks (if
not configured otherwise) and `GET /api/v1/admin/hooks/` returns system
webhooks.

The PR introduces an optional query parameter to `GET
/api/v1/admin/hooks/` to enable selecting if either default, system or
both kind of webhooks should be retrieved. By default the flag is set to
return system webhooks keep current behaviour.

## Examples

### System Webhooks

#### Create

```
POST /api/v1/admin/hooks/

{
  "type": "gitea",
  "active": false,
  "branch_filter": "*",
  "events": [ "create", "..." ],
  "config": {
    "url": "http://...",
    "content_type": "json",
    "secret": "secret",
    "is_system_webhook": true // <-- controls hook type
  }
}
```

#### List
```
GET/api/v1/admin/hooks?type=system //type argument is optional here since it's the default
```

#### Others
The other relevant endpoints work as expected by referencing the hook by
id
```
GET /api/v1/admin/hooks/:id
PATCH /api/v1/admin/hooks/:id
DELETE /api/v1/admin/hooks/:id
```


### Default Webhooks

#### Create
```
POST /api/v1/admin/hooks/

{
  "type": "gitea",
  "active": false,
  "branch_filter": "*",
  "events": [ "create", "..." ],
  "config": {
    "url": "http://...",
    "content_type": "json",
    "secret": "secret",
    "is_system_webhook": false // optional, as false is the default value
  }
}
```

#### List
```
GET/api/v1/admin/hooks?type=default
```

#### Others
The other relevant endpoints work as expected by referencing the hook by
id
```
GET /api/v1/admin/hooks/:id
PATCH /api/v1/admin/hooks/:id
DELETE /api/v1/admin/hooks/:id
```
2025-01-13 17:17:39 +00:00
wxiaoguang
348b7074c8 Fix incorrect ref "blob" (#33240)
1. "blob" is not a "ref", it shouldn't (and not unable to) be handled by
`RepoRefByType`
2. the `/blob/{sha}` handle should use the path param "sha" directly
2025-01-13 16:27:11 +08:00
wxiaoguang
2ea929a952 Refactor RefName (#33234)
And fix some FIXMEs
2025-01-13 14:01:53 +08:00
wxiaoguang
81352542fd Refactor context RefName and RepoAssignment (#33226)
The `ctx.Repo.RefName` was used to be a "short name", it causes a lot of
ambiguity.

This PR does some refactoring and use `RefFullName` to replace the
legacy `RefName`, and simplify RepoAssignment
2025-01-13 01:07:05 +00:00
GiteaBot
604365efd7 [skip ci] Updated translations via Crowdin 2025-01-13 00:34:26 +00:00
wxiaoguang
c0751ef116 Fix upload file form (#33230)
Fix #33228
2025-01-13 03:39:15 +08:00
Lunny Xiao
be4e961240 Fix mirror bug (#33224)
Fix #33200

Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2025-01-12 18:46:37 +08:00
wxiaoguang
9024b79933 Remove unused CSS styles and move some styles to proper files (#33217) 2025-01-12 05:16:22 +00:00
wxiaoguang
a068462ac0 Refactor context repository (#33202) 2025-01-12 03:39:46 +00:00
GiteaBot
a7e750414c [skip ci] Updated translations via Crowdin 2025-01-12 00:35:53 +00:00
Lunny Xiao
fd7d393c67 Fix unpin hint on the pinned pull requests (#33207) 2025-01-12 00:05:33 +00:00
TheFox0x7
8c6d7076b7 fix(cache): cache test triggered by non memory cache (#33220)
Change SlowCacheThreshold to 30 milliseconds so it doesn't trigger on
non memory cache

Closes: https://github.com/go-gitea/gitea/issues/33190
Closes: https://github.com/go-gitea/gitea/issues/32657
2025-01-12 04:33:43 +08:00
yp05327
5c150ce9b0 Update README.md (#33149)
~~Waiting for the upload of screenshots~~
I have a good idea about the screenshots. I will do it later.

---------

Co-authored-by: Gary Wang <git@blumia.net>
2025-01-10 16:03:07 +08:00
Harry Vince
d7ec23febf Fix editor markdown not incrementing in a numbered list (#33187)
Amended the logic for newPrefix in the MarkdownEditor to resolve
incorrect number ordering.

Fixes #33184

Attached screenshot of fixed input similar to issue 
<img width="175" alt="Screenshot 2025-01-09 at 23 59 24"
src="https://github.com/user-attachments/assets/dfa23cf1-f3db-4b5e-99d2-a71bbcb289a8"
/>

---------

Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2025-01-10 07:28:38 +00:00
Lunny Xiao
d3083d2198 Some small refactors (#33144) 2025-01-10 06:00:06 +00:00
Chai-Shi
e5f3c16587 Fix sync fork for consistency (#33147)
Fixes #33145

An integration test could be added.

---------

Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2025-01-10 05:29:55 +00:00
techknowlogick
189e7409b7 Use updated path to s6-svscan after alpine upgrade (#33185)
Fix #33163

Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2025-01-10 10:16:37 +08:00
wxiaoguang
65aae0912a Fix raw file API ref handling (#33172)
Fix #33164 and add more tests
2025-01-10 01:31:49 +00:00
GiteaBot
8f8ad8e272 [skip ci] Updated translations via Crowdin 2025-01-10 00:32:29 +00:00
wxiaoguang
5b31077b68 Fix ACME panic (#33178)
Fix #33177, Manually tested:

````
1.7364311850484018e+09	info	maintenance	started background certificate maintenance	{"cache": "0x1400ca64180"}
1.736431185054049e+09	info	obtain	acquiring lock	{"identifier": "example.com"}
1.736431185058073e+09	info	obtain	lock acquired	{"identifier": "example.com"}
1.736431185058133e+09	info	obtain	obtaining certificate	{"identifier": "example.com"}
````
2025-01-09 23:53:50 +00:00
Lunny Xiao
39d51e7c82 Automerge supports deleting branch automatically after merging (#32343)
Resolve #32341 
~Depends on #27151~

- [x] It will display a checkbox of deleting the head branch on the pull
request view page when starting an auto-merge task.
- [x] Add permission check before deleting the branch
- [x] Add delete branch comment for those closing pull requests because
of head branch or base branch was deleted.
- [x] Merge `RetargetChildrenOnMerge` and `AddDeletePRBranchComment`
into `service.DeleteBranch`.
2025-01-10 03:51:03 +08:00
yp05327
2298ff2152 Fix branch dropdown not display ref name (#33159)
Before:

![image](https://github.com/user-attachments/assets/899d25a9-80e9-48d5-a820-79c911c858e9)
After:

![image](https://github.com/user-attachments/assets/cf2a7407-909a-41db-9957-19d9214af57e)

---------

Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2025-01-09 18:43:49 +00:00
hiifong
5f679c1c59 Add .run to gitignore (#33175)
![image](https://github.com/user-attachments/assets/340a6c2a-8575-4ef9-be75-84af8af82b93)
2025-01-09 18:11:35 +00:00
wxiaoguang
a5043af8ea Fix assignee list overlapping in Issue sidebar (#33176)
Fix  #33170

![image](https://github.com/user-attachments/assets/714cebdc-ee76-43e3-9ece-a189f8ecb17a)

![image](https://github.com/user-attachments/assets/cbb58425-42b4-41ee-ba3c-7efbd24607dc)
2025-01-10 01:58:37 +08:00
TheFox0x7
68ca73b716 Fix pam auth test regression (#33169)
fixes: https://github.com/go-gitea/gitea/issues/33168
2025-01-09 21:09:11 +08:00
yp05327
88366f280e Move repo size to sidebar (#33155)
![image](https://github.com/user-attachments/assets/8b14dbb7-ec36-4596-a6aa-72c14d93309d)
2025-01-09 07:45:51 +00:00
Lunny Xiao
ba5e3a5161 Fix fuzz test (#33156) 2025-01-09 15:15:47 +08:00
TheFox0x7
2a02734f93 Refactor older tests to use testify (#33140)
Refactor checks to use assert/require
Use require.Eventually for waiting in elastic and meilisearch tests
Use require to exit early instead of assert
2025-01-09 09:21:47 +08:00
GiteaBot
fa9191b7b9 [skip ci] Updated translations via Crowdin 2025-01-09 00:32:21 +00:00
yp05327
e177239529 Fix typo in gitea downloader test and add missing codebase in ToGitServiceType (#33146) 2025-01-08 18:34:53 +00:00
wxiaoguang
9c00e065a1 Fix form width (#33151)
Fix #33150
2025-01-08 23:57:18 +08:00
yp05327
124079871b Convert github.com/xanzy/go-gitlab into gitlab.com/gitlab-org/api/client-go (#33126)
Fix #32985
2025-01-08 13:10:43 +08:00
wxiaoguang
386c1ed908 Refactor HTMLFormat, update chroma render, fix js error (#33136)
A small refactor to improve HTMLFormat, to help to prevent low-level
mistakes.

And fix #33141, fix #33139
2025-01-08 03:44:32 +00:00
Lunny Xiao
67aeb1f896 Add missed transaction on setmerged (#33079)
Follow #33045. There are two updates on `Set Merged`, which should be in
one transaction.
This also introduced some refactors for changeissuestatus to make it
more clear.
2025-01-08 03:16:56 +00:00
Rowan Bohde
a8e7caedfa add submodule diff links (#33097)
This adds links to submodules in diffs, similar to the existing link
when viewing a repo at a specific commit. It does this by expanding diff
parsing to recognize changes to submodules, and find the specific refs
that are added, deleted or changed.

Related #25888

---------

Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2025-01-08 01:38:30 +00:00
GiteaBot
ec84687df9 [skip ci] Updated translations via Crowdin 2025-01-08 00:32:07 +00:00
yp05327
32d45ee069 Update status check for all supported on.pull_request.types in Gitea (#33117)
Thanks @Zettat123
Follow #33116
Fix #33051

on.pull_request.types doc:

https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#pull_request

on.pull_request.types added in this PR:
```
assigned, unassigned, review_requested, review_request_removed, milestoned, demilestoned, labeled, unlabeled
```

unsupported types in Gitea:
```
// Unsupported activity types:
// converted_to_draft, ready_for_review, locked, unlocked, auto_merge_enabled, auto_merge_disabled, enqueued, dequeued
```

TODO:
- [x] add test
2025-01-08 01:58:47 +08:00
yp05327
0d7d2ed39d Support the new exit code for git remote subcommands for git version >=2.30.0 (#33129)
Fix #32889

---------

Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2025-01-07 20:42:45 +08:00
wxiaoguang
34dfc25b83 Make git clone URL could use current signed-in user (#33091)
close #33086

* Add a special value for "SSH_USER" setting: `(DOER_USERNAME)`
* Improve parseRepositoryURL and add tests (now it doesn't have hard
dependency on some setting values)

Many changes are just adding "ctx" and "doer" argument to functions.

By the way, improve app.example.ini, remove all `%(key)s` syntax, it
only makes messy and no user really cares about it.

Document: https://gitea.com/gitea/docs/pulls/138
2025-01-07 13:17:44 +08:00
Lunny Xiao
98637fe76e Filter reviews of one pull request in memory instead of database to reduce slow response because of lacking database index (#33106)
This PR fixes a performance problem when reviewing a pull request in a
big instance which have many records in the `review` table.
Traditionally, we should add more indexes in that table. But since
dismissed reviews of 1 pull request will not be too many as expected in
a common repository. Filtering reviews in the memory should be more
quick .

---------

Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2025-01-07 10:50:09 +08:00
GiteaBot
485d184a5c [skip ci] Updated translations via Crowdin 2025-01-07 00:32:09 +00:00
TheFox0x7
4a18c72262 Remove extended glob pattern from branch protection UI (#33125)
Underlying go library has no support for it

Fixes: https://github.com/go-gitea/gitea/issues/33121

---

I never touched frontend tests so pointers how to write them are
welcome.

This can be either fix or workaround, depending if this is something
gitea should support in the future or not. The golang side is unlikely
to get updates though.
2025-01-07 01:23:50 +02:00
Chai-Shi
1a95d9d6a1 fix empty repo updated time (#33120)
fixes #33119 

routers/web/repo/view_home.go

![image](https://github.com/user-attachments/assets/b0d6c5f5-7abc-478a-8d41-4b44dbd460aa)

Calling `updateContextRepoEmptyAndStatus` will always ask the DB to
update the updated Unix attributes.
When revisiting the repo's home page, the timestamp will be updated
unexpectedly, so I added the needsUpdate variable to check whether, in
the end, the commitment to db update is necessary if columns have not
changed at all.

---------

Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2025-01-07 01:54:06 +08:00
wxiaoguang
80e4f4c4eb Refactor package (routes and error handling, npm peer dependency) (#33111) 2025-01-06 22:45:20 +08:00
wxiaoguang
ef736b7e27 Refactor legacy JS (#33115) 2025-01-06 17:38:42 +08:00
wxiaoguang
40765b5d45 Fix repo empty guide (#33114) 2025-01-06 12:07:52 +08:00
GiteaBot
3c1c508421 [skip ci] Updated translations via Crowdin 2025-01-06 00:34:05 +00:00
wxiaoguang
cf60734a4d Fix dropdown menu header and mobile view (#33108)
![image](https://github.com/user-attachments/assets/3f831c8c-ef87-4282-880a-c2738f3e1d17)

----

![image](https://github.com/user-attachments/assets/c4c0519b-cfa6-42b4-bd28-205ee514eb34)

----

![image](https://github.com/user-attachments/assets/8624a605-9f2b-4905-9cbc-0af073972874)
2025-01-05 21:20:22 +00:00
ChristopherHX
4237736029 workflow_dispatch use workflow from trigger branch (#33098)
* htmx updates the input form on branch switch
* add workflow warning to dispatch modal
* use name if description of input is empty
* show error if workflow_dispatch not available on branch

Closes #33073
Closes #33099

---------

Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2025-01-05 21:47:18 +08:00
GiteaBot
3078826d01 [skip ci] Updated translations via Crowdin 2025-01-05 00:35:35 +00:00
wxiaoguang
df9d1fe8c5 Trivial fixes (#33103)
1. remove `gock` dependency, it is not needed
2. fix a regression from org private profile readme
2025-01-04 22:25:50 +00:00
wxiaoguang
3d544a3ad3 Fix empty git repo handling logic (#33101)
Fix #33092
2025-01-04 18:47:24 +08:00
wxiaoguang
2b064b8637 Refactor legacy line-number and scroll code (#33094)
1. remove jquery
2. rewrite the "line number selection", fix various edge cases
3. fix the scroll
2025-01-04 10:56:07 +08:00
Kemal Zebari
188e0ee8e4 Use Project-URL metadata field to get a PyPI package's homepage URL (#33089)
Resolves #33085.
2025-01-03 21:09:47 +00:00
wxiaoguang
68972a9947 Clean up legacy form CSS styles (#33081) 2025-01-03 04:01:19 +00:00
GiteaBot
a739c784d9 [skip ci] Updated translations via Crowdin 2025-01-03 00:31:40 +00:00
metiftikci
83b7e12d4c add myself to maintainers (#33088) 2025-01-02 18:00:26 -05:00
wxiaoguang
e709cc76da Make Gitea always use its internal config, ignore /etc/gitconfig (#33076)
In history, Gitea could use the system config `/etc/gitconfig` because
some users said that "they might put certNonceSeed in it"

Actually, we shouldn't not use it, because it also causes conflicts
(there are already some fixes like #28848)

To make the system clear, I think it's worth to introduce the breaking
change: add `GIT_CONFIG_NOSYSTEM=1` to all git commands.


## ⚠️ BREAKING ⚠️

 For most users, nothing need to do.

If you have made changes to `/etc/gitconfig` to affect Gitea's behavior,
you need to move these config options to Gitea's internal git config
file, it is usually in Gitea's `{AppDataPath}/home/.git` directory.
2025-01-02 20:26:48 +00:00
wxiaoguang
9ac536a904 Fix "stop time tracking button" on navbar (#33084)
Fix #33083

By the way (something I was working on):

1. relax color/background-color for more markup elements
2. fix a command line sentence error
2025-01-03 04:01:05 +08:00
wxiaoguang
45973a100b Fix bleve fuzziness search (#33078)
Close #31565
2025-01-03 00:32:02 +08:00
wxiaoguang
9882917bce Try to fix ACME directory problem (#33072) 2025-01-02 04:38:27 +00:00
wxiaoguang
4f386e2c5e Refactor env var related code (#33075)
And add more comments
2025-01-02 11:36:50 +08:00
GiteaBot
2852708fdf [skip ci] Updated translations via Crowdin 2025-01-02 00:31:55 +00:00
JonRB
233b7959e0 unset XDG_HOME_CONFIG as gitea manages configuration locations (#33067)
unset XDG_CONFIG_HOME early to enable gitea to manage git configuration.
simple error checking to satisfy the linting. Closes #33039

---------

Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2025-01-02 06:37:35 +08:00
wxiaoguang
c1167709ed Refactor repo-new.ts (#33070)
1. merge `repo-template.ts` into `repo-new.ts` (they are all for "/repo/create")
2. remove jquery
3. fix an anonying fomantic dropdown bug, see the comment of `onResponseKeepSelectedItem`
2025-01-01 17:21:13 +00:00
wxiaoguang
85c756e279 Refactor pull-request compare&create page (#33071)
The old code is unnecessarily complex.
2025-01-02 01:16:09 +08:00
lonix1
d030cace1a feat: link to nuget dependencies (#26554)
Add links to dependencies and their versions, as done in nuget site.
Makes it easier to use.

Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2025-01-01 19:07:10 +08:00
wxiaoguang
2564c15cb0 Remove some unnecessary template helpers (#33069)
DisableGitHooks and DisableImportLocal are only used when editing a
user, so only set them in `editUserCommon`
2025-01-01 18:02:34 +08:00
Steffen Schröter
57eb9d0b64 Inherit submodules from template repository content (#16237)
Fix #10316

---------

Signed-off-by: Steffen Schröter <steffen@vexar.de>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2025-01-01 02:55:13 +00:00
GiteaBot
92a2900a2d [skip ci] Updated translations via Crowdin 2025-01-01 00:35:43 +00:00
Bo-Yi Wu
6c89de494a feat(action): issue change title notifications (#33050)
- Add `IssueChangeTitle` method to handle issue title changes
- Add `notifyIssueChangeWithTitleOrContent` method to generalize
notification handling for issue title or content changes

action file as below:

```yaml
name: Semantic Pull Request

on:
  pull_request_target:
    types: [edited]
```

---------

Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>
Co-authored-by: Giteabot <teabot@gitea.io>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2024-12-31 12:08:36 +00:00
Lunny Xiao
20c7fba601 Use project's redirect url instead of composing url (#33058)
Fix #32992

---------

Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2024-12-31 19:19:53 +08:00
wxiaoguang
a0853e2278 Fix unittest and repo create bug (#33061)
1. `StatDir` was not right, fix the FIXME
2. Clarify the test cases for `IsUsableRepoName`
3. Fix regression bug in `repo-new.ts`

Fix #33060
2024-12-31 18:45:05 +08:00
wxiaoguang
58c092cfea Fix locale type (#33059)
Follow #32872
2024-12-31 06:37:37 +00:00
wxiaoguang
e5c576e92b Refactor maven package registry (#33049)
Close #33036
2024-12-31 05:30:52 +00:00
Kerwin Bryant
54bd220520 Optimize the installation page (#32994)
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2024-12-31 04:49:26 +00:00
Chai-Shi
0387195abb [Feature] Private README.md for organization (#32872)
Implemented #29503

---------

Co-authored-by: Ben Chang <ben_chang@htc.com>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2024-12-31 04:22:09 +00:00
wxiaoguang
c09656e0e0 Make issue suggestion work for new PR page (#33035)
Fix #33026
2024-12-31 03:50:55 +00:00
hiifong
4a254856b3 Add IntelliJ Gateway's .uuid to gitignore (#33052) 2024-12-30 21:42:29 -05:00
Lunny Xiao
a54cc05d2a Fix issue comment number (#30556) 2024-12-30 14:35:46 -08:00
hiifong
a87168869a Fix duplicate co-author in squashed merge commit messages (#33020)
Fix: #31980

---------

Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2024-12-30 19:03:21 +00:00
Lunny Xiao
fe32ffe181 Merge updatecommentattachment functions (#33044)
Extract from #32178
2024-12-30 18:21:57 +00:00
Lunny Xiao
d45456b1b5 Move SetMerged to service layer (#33045)
No code change.
Extract from #32178
2024-12-30 07:04:03 +00:00
Lunny Xiao
8eecca3478 Remove aws go sdk package dependency (#33029)
This PR removed the dependency of `github.com/aws/aws-sdk-go/aws`

Patially fix for #33023
2024-12-30 06:30:28 +00:00
cassio zareck
1e2c8eb494 Fix settings not being loaded at CLI (#26402)
Closes #25898
The problem was that the default settings weren't being loaded

---------

Signed-off-by: cassiozareck <cassiomilczareck@gmail.com>
Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2024-12-30 05:54:20 +00:00
wxiaoguang
dafadf0028 Refactor fixture loading for testing (#33024)
To help binary size and testing performance
2024-12-30 04:06:57 +00:00
Lunny Xiao
f4ccbd38dc Use gitrepo.GetTreePathLatestCommit to get file lastest commit instead from latest commit cache (#32987)
The latest commit cache is currently used only for listing tree files.
However, a cold start may take longer than directly invoking the Git
command. This PR addresses the issue of slow response times when
accessing raw files, improving performance in such scenarios.

```log
gitea.log:105521:2024/12/23 08:22:18 ...eb/routing/logger.go:68:func1() [W] router: slow      GET /xxxx/xxxxxx/raw/commit/xxxxxxxxxxxxxxxxxxxxxxxxxxx/.editorconfig for 172.18.0.5:53252, elapsed 3526.8ms @ repo/download.go:117(repo.SingleDownload)
```
2024-12-30 03:30:01 +00:00
Lunny Xiao
344c89ea34 Fix bug automerge cannot be chosed when there is only 1 merge style (#33040)
This is a quick bug fix. Even if there is only 1 merge style, the
dropdown menu will still be displayed to allow users to choose
auto-merge.

Fix #32448
2024-12-30 03:04:22 +00:00
techknowlogick
232867cff6 use -s -w ldflags for release artifacts (#33041)
fix #33030
2024-12-30 02:37:59 +00:00
wxiaoguang
cd1b5488a3 Refactor pagination (#33037)
I am sure the simple approach should work, let's try it in 1.24

Follow #29834 and #29841
2024-12-30 01:57:38 +00:00
wxiaoguang
1dbf0d7f08 Test webhook email (#33033)
Close #27918
2024-12-30 01:25:49 +08:00
Henry Goodman
a96776b3cb Fix review code comment avatar alignment (#33031)
Fixes #33017

Avatar should only have offset if the `Comment` has `Content` or
`Attachment` to align with the speech bubble.

---------

Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2024-12-29 11:04:13 +00:00
TheFox0x7
ff96873e3e Fix templating in pull request comparison (#33025)
Adds test for expected behavior

Closes: https://github.com/go-gitea/gitea/issues/33013
2024-12-29 01:32:19 +00:00
wxiaoguang
0ed160ffea Refactor tests (#33021)
1. fix incorrect tests, for example: BeanExists doesn't do assert and
shouldn't be used
2. remove unnecessary test functions
3. introduce DumpQueryResult to help to see the database rows during
test (at least I need it)

```
====== DumpQueryResult: SELECT * FROM action_runner_token ======
- # row[0]
  id: 1
  token: xeiWBL5kuTYxGPynHCqQdoeYmJAeG3IzGXCYTrDX
  owner_id: 0
...
```
2024-12-29 01:05:56 +00:00
GiteaBot
e95b946f6d [skip ci] Updated translations via Crowdin 2024-12-29 00:36:47 +00:00
metiftikci
64bebc9402 always show assignees on right (#33006)
### Before

![old_issue_list](https://github.com/user-attachments/assets/c7a6631d-9330-4e29-9e01-c1bcb2a0387f)

### After

![new_issue_list](https://github.com/user-attachments/assets/5a13c413-b58e-40bb-888b-9edfe3c94e0c)
2024-12-29 00:30:06 +00:00
metiftikci
94048f3035 fix toggle commit body button ui when latest commit message is long (#32997)
#### Before


![before](https://github.com/user-attachments/assets/fe36bdb3-10e8-4fe7-9106-0897f49bedb3)

#### After


![after](https://github.com/user-attachments/assets/745bd164-5f25-41ca-b340-36cb695551db)


## Edit:

I found an issue on mobile view and changed the code as using flex gap


![small](https://github.com/user-attachments/assets/dd7c2093-6860-4800-a2bc-676a03e764c8)


![large](https://github.com/user-attachments/assets/5c933779-8281-4d48-9fd0-4d7b245bf4ac)

---------

Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2024-12-29 08:04:56 +08:00
wxiaoguang
a92f5057ae Fix and/or comment some legacy CSS problems (#33015) 2024-12-28 11:51:38 +00:00
wxiaoguang
3d3ece36d2 Refactor comment history and fix content edit (#33018)
And fix a regression bug for comment content editing.

Now 11 "import jquery" files left
2024-12-28 19:26:16 +08:00
Lunny Xiao
e69da2cd07 Fix bug on activities (#33008)
A repository with no issue will display a random number on activities
page. This is caused by wrong usage of `And` and `Or`.

![9cdbbf81d50aa5d9bd16604e0dab5eb0](https://github.com/user-attachments/assets/828cebdc-bd35-4716-a58c-c1b43ddf8bf0)
2024-12-28 04:04:07 +00:00
wxiaoguang
e435b1900a Refactor arch route handlers (#32993) 2024-12-28 03:31:46 +00:00
metiftikci
254314be5f fix scoped label ui when contains emoji (#33007)
### Before

![old_label](https://github.com/user-attachments/assets/2211f711-613a-4ed4-90fd-8ff6ab0700f5)

### After

![new_label](https://github.com/user-attachments/assets/ecbc89da-7f77-44d0-8ce9-ba51b67421e5)
2024-12-28 00:58:19 +00:00
GiteaBot
14ed553fae [skip ci] Updated translations via Crowdin 2024-12-28 00:30:57 +00:00
Blender Defender
079a1ffe8f De-emphasize signed commits (#31160)
The new code structure is easier to make more improvements or
refactor, for example: change the colors to de-emphasize more, or design
some new layouts.

---------

Co-authored-by: silverwind <me@silverwind.io>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2024-12-28 04:18:30 +08:00
wxiaoguang
ea198f9ea8 Fix eslint (#33002)
Fix  #32982
Related #32869

* eslint-plugin-github 5.1.x doesn't work well with eslint8
* no-undef is still needed
2024-12-27 19:34:39 +00:00
a1012112796
a7b2707be9 Fix Agit pull request permission check (#32999)
user with read permission should also can create agit flow pull request.
looks this logic was broken in
https://github.com/go-gitea/gitea/pull/31033 this pull request try fix
it and add test code.

---------

Signed-off-by: a1012112796 <1012112796@qq.com>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2024-12-27 18:17:01 +00:00
Zettat123
2d1a171dc7 Support for email addresses containing uppercase characters when activating user account (#32998)
Fix #32807

---------

Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2024-12-27 19:16:23 +08:00
GiteaBot
3c00e89129 [skip ci] Updated translations via Crowdin 2024-12-27 00:32:06 +00:00
Zettat123
df98452c0d Improve Actions test (#32883)
This PR adds a mock runner to test more actions features.
2024-12-26 22:10:30 +00:00
Zettat123
44b4fb21a4 Support org labels when adding labels by label names (#32988)
Fix #32891
2024-12-26 19:14:49 +00:00
yp05327
7bb7ba1b5b Add show more organizations icon in user's profile (#32986)
Close #32952

# ⚠️ Doc update is required


![image](https://github.com/user-attachments/assets/296c5109-8fc1-43ea-b7dc-e79919cc1f9a)

![image](https://github.com/user-attachments/assets/d30980f6-22e4-4b97-9143-c750dc399da6)


------
⚠️This PR refuses to be cherry-picked by any forked projects without any
mentions.

---------

Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2024-12-27 02:49:50 +08:00
wxiaoguang
550abdbc24 Improve "ellipsis string" (#32989) 2024-12-26 14:19:35 +08:00
wxiaoguang
9bfa9f450d Refactor "string truncate" (#32984) 2024-12-26 11:56:03 +08:00
wxiaoguang
594edad213 Do not render truncated links in markdown (#32980)
Fixes #31780
2024-12-26 00:33:55 +08:00
Lunny Xiao
5feb1a6bff Use CloseIssue and ReopenIssue instead of ChangeStatus (#32467)
The behaviors of closing issues and reopening issues are very different.
So splitting it into two different functions makes it easier to
maintain.

- [x] Split ChangeIssueStatus into CloseIssue and ReopenIssue both at
the service layer and model layer
- [x] Rename `isClosed` to `CloseOrReopen` to make it more readable.
- [x] Add transactions for ReopenIssue and CloseIssue

---------

Co-authored-by: Zettat123 <zettat123@gmail.com>
2024-12-25 07:38:30 +00:00
Lunny Xiao
f44712f22b demilestone should not include milestone (#32923)
Fix #32887
2024-12-25 05:52:46 +00:00
metiftikci
1a7591d7f9 fix textarea newline handle (#32966)
- Fix cursor position if input newline on middle of lines
- ~Increment number if numbered list~


![image](https://github.com/user-attachments/assets/bcfe2625-11a8-4ea4-9a71-b7ecfe81b2e0)

---------

Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2024-12-25 13:03:43 +08:00
Zettat123
abaeae0b9c Fix Azure blob object Seek (#32974)
This bug was found in a
[test](https://github.com/go-gitea/gitea/actions/runs/12464294025/job/34788152194?pr=32883#step:9:105)
of #32883

---------

Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2024-12-25 04:54:52 +00:00
wxiaoguang
973363fec3 Fix maven pom inheritance (#32943)
Fix  #30568
2024-12-25 04:28:37 +00:00
wxiaoguang
ca31d478ee Refactor arch route handlers (#32972) 2024-12-25 04:03:14 +00:00
GiteaBot
65e45fdcfd [skip ci] Updated translations via Crowdin 2024-12-25 00:31:17 +00:00
wxiaoguang
b7260400f8 Refactor tmpl and blob_excerpt (#32967)
1. do not use `{{/* */}}` to remove spaces, use `{{- -}}`
2. fix "blob_excerpt" endpoint, remove the legacy fragile code: have
tested commit diff and wiki diff
2024-12-25 00:51:13 +08:00
wxiaoguang
2a828e2798 Clarify path param naming (#32969)
In history (from some legacy frameworks), both `:name` and `name` are
supported as path path name, `:name` is an alias to `name`.

To make code consistent, now we should only use `name` but not `:name`.

Also added panic check in related functions to make sure the name won't
be abused in case some downstreams still use them.
2024-12-24 13:47:45 +00:00
Lunny Xiao
b8b690feb9 Refactor getpatch/getdiff functions and remove unnecessary fallback (#32817)
Extract from #32786 

`git diff a..b` is equal to `git diff a b` which is different from `git
diff a...b`. For pull request, we should always 

---------

Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2024-12-24 14:29:34 +08:00
wxiaoguang
6d5aa9218e Refactor request context (#32956)
Introduce RequestContext: is a short-lived context that is used to store
request-specific data.

RequestContext could be used to clean form tmp files, close context git
repo, and do some tracing in the future.

Then a lot of legacy code could be removed or improved. For example:
most `ctx.Repo.GitRepo.Close()` could be removed because the git repo
could be closed when the request is done.
2024-12-24 11:43:57 +08:00
wxiaoguang
781c6df40f Add sub issue list support (#32940)
Just like GitHub, show issue icon/title when the issue number is in a list
2024-12-24 01:54:19 +00:00
GiteaBot
02c64e48b7 [skip ci] Updated translations via Crowdin 2024-12-24 00:31:53 +00:00
wxiaoguang
7553ae1a57 Use env GITEA_RUNNER_REGISTRATION_TOKEN as global runner token (#32946)
Fix #23703

When Gitea starts, it reads GITEA_RUNNER_REGISTRATION_TOKEN
or GITEA_RUNNER_REGISTRATION_TOKEN_FILE to add registration token.
2024-12-23 09:59:16 +00:00
wxiaoguang
bd5d1341d4 Fix commit range paging (#32944) 2024-12-23 07:07:12 +00:00
wxiaoguang
89f31f79fd Fix outdated tmpl code (#32953)
Some PRs were before tmpl ctx refactoring and used outdated code
2024-12-23 11:21:11 +08:00
wxiaoguang
462ce31530 Fix repo avatar conflict (#32958)
Continue even if the avatar deleting fails
2024-12-23 02:52:25 +00:00
GiteaBot
b5f9a2d7c0 [skip ci] Updated licenses and gitignores 2024-12-23 00:32:58 +00:00
katsu
fb75151fb1 fix trailing comma not matched in the case of alphanumeric issue (#32945)
Fix #32428.

Patch the regex to match `,`besides `.` `"` `'` `:` and space.
2024-12-22 21:32:28 +00:00
bytedream
6279646ee4 Add auto-expanding running actions step (#30058)
Auto-expands the currently running action step.

---------

Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2024-12-22 18:57:17 +00:00
Illya Marchenko
daf2776db7 Fix #32954 (#32955)
`/bin/s6-svscan` is actuall located at `/usr/bin/s6-svscan`
2024-12-23 02:31:53 +08:00
techknowlogick
a09ea2f483 Use Alpine 3.21 for the docker images (#32924) 2024-12-22 15:44:50 +00:00
wxiaoguang
a163c53a60 Refactor template & test related code (#32938)
Move some legacy code from "base" package to proper packages.
2024-12-22 15:33:19 +00:00
wxiaoguang
afe314fa77 Use primary as button color (#32949)
* Fix #32871
* Fix #32948
2024-12-22 23:03:39 +08:00
GiteaBot
35c86af164 [skip ci] Updated translations via Crowdin 2024-12-22 00:35:14 +00:00
bytedream
5d6d62493b Add action auto-scroll (#30057)
Adds an auto-scroll/follow feature to running actions (fix #25186, fix
#28535).

When new log lines are appended and the bottom of the logs container
(`.action-view-right`) is visible at this time, the page automatically
scrolls down to the bottom of the logs.

---------

Co-authored-by: silverwind <me@silverwind.io>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2024-12-21 14:49:26 -08:00
wxiaoguang
143946834a Fix locale (#32937)
Fix #32936
2024-12-21 19:24:43 +00:00
silverwind
c0e80dbe26 Enable Typescript strictFunctionTypes (#32911)
1. Enable
[strictFunctionTypes](https://www.typescriptlang.org/tsconfig/#strictFunctionTypes)
2. Introduce `DOMEvent` helper type which sets `e.target`. Surely not
totally correct with that `Partial` but seems to work.
3. Various type-related refactors, change objects in
`eventsource.sharedworker.ts` to `Map`.
2024-12-22 02:59:25 +08:00
wxiaoguang
09a0041965 Fix areYouSure confirm (#32941)
See the comment
2024-12-21 12:11:22 -05:00
Aindriú Mac Giolla Eoin
23687a0a71 Update i18n.go - Language Picker (#32933) 2024-12-21 04:56:08 +00:00
Lunny Xiao
751fe8b714 Move some errors to their own sub packages (#32880) 2024-12-20 18:05:29 +00:00
wxiaoguang
4774151e53 Improve navbar: add "admin" tip, add "active" style (#32927)
By the way, remove all "tw-" patches and unused styles.
2024-12-20 16:38:56 +00:00
wxiaoguang
1c9b022c4d Refactor db package and remove unnecessary DumpTables (#32930) 2024-12-20 16:11:38 +00:00
Tim
7580bd98c1 show warning on navigation if currently editing comment or title (#32920)
This PR fixes the issue https://github.com/go-gitea/gitea/issues/32223

Make the browser to show the confirm popup, as it does with other forms.

---------

Co-authored-by: Tim Wundenberg <tim@wundenbergs.de>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2024-12-20 23:39:19 +08:00
wxiaoguang
52b319bc00 Refactor pprof labels and process desc (#32909)
* Deprecate "gopid" in log, it is not useful and requires very hacky
approach
* Remove "git.Command.SetDescription" because it is not useful and only
makes the logs too flexible
2024-12-20 12:17:14 +08:00
GiteaBot
c66de245c4 [skip ci] Updated translations via Crowdin 2024-12-20 00:31:51 +00:00
silverwind
f47fb4fbaf Update JS dependencies (#32914)
Result of `make update-js`. Tested Monaco and Math.
2024-12-19 20:05:16 +00:00
silverwind
626b27bea5 Update go tool dependencies (#32916)
Update all go tool dependencies to latest version. WIP because I think
there are new gopls errors, would like to confirm them on CI first. Here
is from a local run:

```
modules/markup/markdown/goldmark.go:115:37-53: unnecessary type arguments
modules/markup/html.go:45:32-49: unnecessary type arguments
modules/markup/internal/renderinternal.go:20:33-49: unnecessary type arguments
modules/markup/common/linkify.go:27:32-49: unnecessary type arguments
modules/util/time_str.go:28:39-63: unnecessary type arguments
routers/web/repo/pull.go:704:19: impossible condition: non-nil == nil
modules/util/util_test.go:248:14-23: unused parameter: other
```

~~Backport because the `gxz` update might have security benefits.~~
2024-12-19 19:17:55 +01:00
Exploding Dragon
581e52b3e7 Relax the version checking for Arch packages (#32908)
It is mentioned in https://man.archlinux.org/man/PKGBUILD.5: 'The
variable is not allowed to contain colons, forward slashes, hyphens, or
whitespace.'

`_` is also an allowed character, and some software in the Arch Linux
AUR uses this naming convention.

---------

Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2024-12-19 09:41:23 +00:00
silverwind
141d782c1a Refactor repo-projects.ts (#32892)
- Remove jQuery
- Add types to all functions
- Tested all modified functionality

---------

Co-authored-by: Giteabot <teabot@gitea.io>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2024-12-19 08:37:12 +00:00
Lunny Xiao
dc8f59baa5 Add more load functions to make sure the reference object loaded (#32901)
Fix #32897
2024-12-19 14:10:08 +08:00
GiteaBot
5ec8df02f6 [skip ci] Updated translations via Crowdin 2024-12-19 00:33:27 +00:00
techknowlogick
420cda18e6 bump x/net (#32896) 2024-12-18 22:40:04 +00:00
silverwind
857abed3a9 Move RepoBranchTagSelector init outside the SFC (#32890)
SFCs shouldn't export anything besides their component, and this
eliminates one issue with tsc, while apparently also solving a hack. It
seems to work as before, also when multiples are on the same page.
2024-12-18 21:26:17 +01:00
Exploding Dragon
2beaedc417 Fix Arch package metadata introduced incorrect field (#32881)
Incorrect content was introduced while generating the index, which has
now been removed, and the missing fields have been added.

![](https://github.com/user-attachments/assets/4fbb8884-337e-43b1-939f-a5ba687f7ffd)
2024-12-18 15:25:05 +08:00
Lunny Xiao
f9f62b4c4c Move delete deploy keys into service layer (#32201) 2024-12-18 04:10:38 +00:00
Lunny Xiao
e4c4629465 Move RepoTransfer from models to models/repo sub package (#32506)
`RepoTransfer` now is at models, but if we want to move it into `repo`
model, it will depend on `Team`. So this PR also makes repo model depend
on org model to make it possible. Just refactor, no code change.

- [x] Move `DeleteOrganization` from `models/organization` to service
layer
- [x] Move `AccessibleTeamReposEnv` to `models/repo`
- [x] Move `RepoTransfer` from `models` to `models/repo`
- [x] Merge `getUserTeamIDs` and `GetUserTeamIDs`, Merge `GetUserTeams`
and `getUserTeams`.
- [x] Remove `Team`'s `Repos []*repo_model.Repository` to avoid dependency recycle.
2024-12-18 11:44:16 +08:00
TheFox0x7
b945742293 Change pprof labels to be prometheus compatible (#32865)
Enables scrapping pprof endpoint for continuous profiling

Closes: https://github.com/go-gitea/gitea/issues/32854
2024-12-18 11:08:04 +08:00
silverwind
195fccd617 Move eslint config to javascript (#32869)
In preparation for migrating to eslint flat config, move the config file
to javascript. Additional changes:

- `no-undef` is now disabled as it's no longer needed with typescript
- `no-restricted-globals` config is simplified
2024-12-18 00:51:11 +00:00
GiteaBot
e6186bc447 [skip ci] Updated translations via Crowdin 2024-12-18 00:33:18 +00:00
wxiaoguang
2d7e6e9482 Fix various trivial problems (#32861)
1. add/improve comments to help future readers could understand the
problem more easily.
2. add an error log to LDAP with username fallback
3. use `or` instead of `Iif` for "repo/branch_dropdown" (`Iif` was a
mistake, but it doesn't really affect the UI)
4. add `tw-font-mono` style to container digest to match dockerhub
5. fix a bug in RepoBranchTagSelector: the form is not updated when
there is no click to an item

---------

Co-authored-by: delvh <dev.lh@web.de>
2024-12-17 01:15:18 +00:00
GiteaBot
9f9bff0f04 [skip ci] Updated translations via Crowdin 2024-12-17 00:45:49 +00:00
2764 changed files with 84101 additions and 105699 deletions

View File

@ -22,20 +22,25 @@ groups:
name: FEATURES name: FEATURES
labels: labels:
- type/feature - type/feature
-
name: API
labels:
- modifies/api
- -
name: ENHANCEMENTS name: ENHANCEMENTS
labels: labels:
- type/enhancement - type/enhancement
- type/refactoring -
- topic/ui name: PERFORMANCE
labels:
- performance/memory
- performance/speed
- performance/bigrepo
- performance/cpu
- -
name: BUGFIXES name: BUGFIXES
labels: labels:
- type/bug - type/bug
-
name: API
labels:
- modifies/api
- -
name: TESTING name: TESTING
labels: labels:

View File

@ -1,6 +1,6 @@
{ {
"name": "Gitea DevContainer", "name": "Gitea DevContainer",
"image": "mcr.microsoft.com/devcontainers/go:1.23-bookworm", "image": "mcr.microsoft.com/devcontainers/go:1.24-bookworm",
"features": { "features": {
// installs nodejs into container // installs nodejs into container
"ghcr.io/devcontainers/features/node:1": { "ghcr.io/devcontainers/features/node:1": {

View File

@ -79,18 +79,6 @@ cpu.out
/public/assets/fonts /public/assets/fonts
/public/assets/img/avatar /public/assets/img/avatar
/vendor /vendor
/web_src/fomantic/node_modules
/web_src/fomantic/build/*
!/web_src/fomantic/build/semantic.js
!/web_src/fomantic/build/semantic.css
!/web_src/fomantic/build/themes
/web_src/fomantic/build/themes/*
!/web_src/fomantic/build/themes/default
/web_src/fomantic/build/themes/default/assets/*
!/web_src/fomantic/build/themes/default/assets/fonts
/web_src/fomantic/build/themes/default/assets/fonts/*
!/web_src/fomantic/build/themes/default/assets/fonts/icons.woff2
!/web_src/fomantic/build/themes/default/assets/fonts/outline-icons.woff2
/VERSION /VERSION
/.air /.air
/.go-licenses /.go-licenses

View File

@ -12,11 +12,15 @@ insert_final_newline = true
[*.{go,tmpl,html}] [*.{go,tmpl,html}]
indent_style = tab indent_style = tab
[go.*]
indent_style = tab
[templates/custom/*.tmpl] [templates/custom/*.tmpl]
insert_final_newline = false insert_final_newline = false
[templates/swagger/v1_json.tmpl] [templates/swagger/v1_json.tmpl]
indent_style = space indent_style = space
insert_final_newline = false
[templates/user/auth/oidc_wellknown.tmpl] [templates/user/auth/oidc_wellknown.tmpl]
indent_style = space indent_style = space

1004
.eslintrc.cjs Normal file

File diff suppressed because it is too large Load Diff

View File

@ -1,967 +0,0 @@
root: true
reportUnusedDisableDirectives: true
ignorePatterns:
- /web_src/js/vendor
- /web_src/fomantic
- /public/assets/js
parser: "@typescript-eslint/parser"
parserOptions:
sourceType: module
ecmaVersion: latest
project: true
extraFileExtensions: [".vue"]
parser: "@typescript-eslint/parser" # for vue plugin - https://eslint.vuejs.org/user-guide/#how-to-use-a-custom-parser
settings:
import-x/extensions: [".js", ".ts"]
import-x/parsers:
"@typescript-eslint/parser": [".js", ".ts"]
import-x/resolver:
typescript: true
plugins:
- "@eslint-community/eslint-plugin-eslint-comments"
- "@stylistic/eslint-plugin-js"
- "@typescript-eslint/eslint-plugin"
- eslint-plugin-array-func
- eslint-plugin-github
- eslint-plugin-import-x
- eslint-plugin-no-jquery
- eslint-plugin-no-use-extend-native
- eslint-plugin-regexp
- eslint-plugin-sonarjs
- eslint-plugin-unicorn
- eslint-plugin-vitest
- eslint-plugin-vitest-globals
- eslint-plugin-wc
env:
es2024: true
node: true
overrides:
- files: ["web_src/**/*"]
globals:
__webpack_public_path__: true
process: false # https://github.com/webpack/webpack/issues/15833
- files: ["web_src/**/*", "docs/**/*"]
env:
browser: true
node: false
- files: ["web_src/**/*worker.*"]
env:
worker: true
rules:
no-restricted-globals: [2, addEventListener, blur, close, closed, confirm, defaultStatus, defaultstatus, error, event, external, find, focus, frameElement, frames, history, innerHeight, innerWidth, isFinite, isNaN, length, locationbar, menubar, moveBy, moveTo, name, onblur, onerror, onfocus, onload, onresize, onunload, open, opener, opera, outerHeight, outerWidth, pageXOffset, pageYOffset, parent, print, removeEventListener, resizeBy, resizeTo, screen, screenLeft, screenTop, screenX, screenY, scroll, scrollbars, scrollBy, scrollTo, scrollX, scrollY, status, statusbar, stop, toolbar, top]
- files: ["*.config.*"]
rules:
import-x/no-unused-modules: [0]
- files: ["**/*.d.ts"]
rules:
import-x/no-unused-modules: [0]
"@typescript-eslint/consistent-type-definitions": [0]
"@typescript-eslint/consistent-type-imports": [0]
- files: ["web_src/js/types.ts"]
rules:
import-x/no-unused-modules: [0]
- files: ["**/*.test.*", "web_src/js/test/setup.ts"]
env:
vitest-globals/env: true
rules:
vitest/consistent-test-filename: [0]
vitest/consistent-test-it: [0]
vitest/expect-expect: [0]
vitest/max-expects: [0]
vitest/max-nested-describe: [0]
vitest/no-alias-methods: [0]
vitest/no-commented-out-tests: [0]
vitest/no-conditional-expect: [0]
vitest/no-conditional-in-test: [0]
vitest/no-conditional-tests: [0]
vitest/no-disabled-tests: [0]
vitest/no-done-callback: [0]
vitest/no-duplicate-hooks: [0]
vitest/no-focused-tests: [0]
vitest/no-hooks: [0]
vitest/no-identical-title: [2]
vitest/no-interpolation-in-snapshots: [0]
vitest/no-large-snapshots: [0]
vitest/no-mocks-import: [0]
vitest/no-restricted-matchers: [0]
vitest/no-restricted-vi-methods: [0]
vitest/no-standalone-expect: [0]
vitest/no-test-prefixes: [0]
vitest/no-test-return-statement: [0]
vitest/prefer-called-with: [0]
vitest/prefer-comparison-matcher: [0]
vitest/prefer-each: [0]
vitest/prefer-equality-matcher: [0]
vitest/prefer-expect-resolves: [0]
vitest/prefer-hooks-in-order: [0]
vitest/prefer-hooks-on-top: [2]
vitest/prefer-lowercase-title: [0]
vitest/prefer-mock-promise-shorthand: [0]
vitest/prefer-snapshot-hint: [0]
vitest/prefer-spy-on: [0]
vitest/prefer-strict-equal: [0]
vitest/prefer-to-be: [0]
vitest/prefer-to-be-falsy: [0]
vitest/prefer-to-be-object: [0]
vitest/prefer-to-be-truthy: [0]
vitest/prefer-to-contain: [0]
vitest/prefer-to-have-length: [0]
vitest/prefer-todo: [0]
vitest/require-hook: [0]
vitest/require-to-throw-message: [0]
vitest/require-top-level-describe: [0]
vitest/valid-describe-callback: [2]
vitest/valid-expect: [2]
vitest/valid-title: [2]
- files: ["web_src/js/modules/fetch.ts", "web_src/js/standalone/**/*"]
rules:
no-restricted-syntax: [2, WithStatement, ForInStatement, LabeledStatement, SequenceExpression]
- files: ["**/*.vue"]
plugins:
- eslint-plugin-vue
- eslint-plugin-vue-scoped-css
extends:
- plugin:vue/vue3-recommended
- plugin:vue-scoped-css/vue3-recommended
rules:
vue/attributes-order: [0]
vue/html-closing-bracket-spacing: [2, {startTag: never, endTag: never, selfClosingTag: never}]
vue/max-attributes-per-line: [0]
vue/singleline-html-element-content-newline: [0]
- files: ["tests/e2e/**"]
plugins:
- eslint-plugin-playwright
extends: plugin:playwright/recommended
rules:
"@eslint-community/eslint-comments/disable-enable-pair": [2]
"@eslint-community/eslint-comments/no-aggregating-enable": [2]
"@eslint-community/eslint-comments/no-duplicate-disable": [2]
"@eslint-community/eslint-comments/no-restricted-disable": [0]
"@eslint-community/eslint-comments/no-unlimited-disable": [2]
"@eslint-community/eslint-comments/no-unused-disable": [2]
"@eslint-community/eslint-comments/no-unused-enable": [2]
"@eslint-community/eslint-comments/no-use": [0]
"@eslint-community/eslint-comments/require-description": [0]
"@stylistic/js/array-bracket-newline": [0]
"@stylistic/js/array-bracket-spacing": [2, never]
"@stylistic/js/array-element-newline": [0]
"@stylistic/js/arrow-parens": [2, always]
"@stylistic/js/arrow-spacing": [2, {before: true, after: true}]
"@stylistic/js/block-spacing": [0]
"@stylistic/js/brace-style": [2, 1tbs, {allowSingleLine: true}]
"@stylistic/js/comma-dangle": [2, always-multiline]
"@stylistic/js/comma-spacing": [2, {before: false, after: true}]
"@stylistic/js/comma-style": [2, last]
"@stylistic/js/computed-property-spacing": [2, never]
"@stylistic/js/dot-location": [2, property]
"@stylistic/js/eol-last": [2]
"@stylistic/js/function-call-argument-newline": [0]
"@stylistic/js/function-call-spacing": [2, never]
"@stylistic/js/function-paren-newline": [0]
"@stylistic/js/generator-star-spacing": [0]
"@stylistic/js/implicit-arrow-linebreak": [0]
"@stylistic/js/indent": [2, 2, {ignoreComments: true, SwitchCase: 1}]
"@stylistic/js/key-spacing": [2]
"@stylistic/js/keyword-spacing": [2]
"@stylistic/js/line-comment-position": [0]
"@stylistic/js/linebreak-style": [2, unix]
"@stylistic/js/lines-around-comment": [0]
"@stylistic/js/lines-between-class-members": [0]
"@stylistic/js/max-len": [0]
"@stylistic/js/max-statements-per-line": [0]
"@stylistic/js/multiline-comment-style": [0]
"@stylistic/js/multiline-ternary": [0]
"@stylistic/js/new-parens": [2]
"@stylistic/js/newline-per-chained-call": [0]
"@stylistic/js/no-confusing-arrow": [0]
"@stylistic/js/no-extra-parens": [0]
"@stylistic/js/no-extra-semi": [2]
"@stylistic/js/no-floating-decimal": [0]
"@stylistic/js/no-mixed-operators": [0]
"@stylistic/js/no-mixed-spaces-and-tabs": [2]
"@stylistic/js/no-multi-spaces": [2, {ignoreEOLComments: true, exceptions: {Property: true}}]
"@stylistic/js/no-multiple-empty-lines": [2, {max: 1, maxEOF: 0, maxBOF: 0}]
"@stylistic/js/no-tabs": [2]
"@stylistic/js/no-trailing-spaces": [2]
"@stylistic/js/no-whitespace-before-property": [2]
"@stylistic/js/nonblock-statement-body-position": [2]
"@stylistic/js/object-curly-newline": [0]
"@stylistic/js/object-curly-spacing": [2, never]
"@stylistic/js/object-property-newline": [0]
"@stylistic/js/one-var-declaration-per-line": [0]
"@stylistic/js/operator-linebreak": [2, after]
"@stylistic/js/padded-blocks": [2, never]
"@stylistic/js/padding-line-between-statements": [0]
"@stylistic/js/quote-props": [0]
"@stylistic/js/quotes": [2, single, {avoidEscape: true, allowTemplateLiterals: true}]
"@stylistic/js/rest-spread-spacing": [2, never]
"@stylistic/js/semi": [2, always, {omitLastInOneLineBlock: true}]
"@stylistic/js/semi-spacing": [2, {before: false, after: true}]
"@stylistic/js/semi-style": [2, last]
"@stylistic/js/space-before-blocks": [2, always]
"@stylistic/js/space-before-function-paren": [2, {anonymous: ignore, named: never, asyncArrow: always}]
"@stylistic/js/space-in-parens": [2, never]
"@stylistic/js/space-infix-ops": [2]
"@stylistic/js/space-unary-ops": [2]
"@stylistic/js/spaced-comment": [2, always]
"@stylistic/js/switch-colon-spacing": [2]
"@stylistic/js/template-curly-spacing": [2, never]
"@stylistic/js/template-tag-spacing": [2, never]
"@stylistic/js/wrap-iife": [2, inside]
"@stylistic/js/wrap-regex": [0]
"@stylistic/js/yield-star-spacing": [2, after]
"@typescript-eslint/adjacent-overload-signatures": [0]
"@typescript-eslint/array-type": [0]
"@typescript-eslint/await-thenable": [2]
"@typescript-eslint/ban-ts-comment": [2, {'ts-expect-error': false, 'ts-ignore': true, 'ts-nocheck': false, 'ts-check': false}]
"@typescript-eslint/ban-tslint-comment": [0]
"@typescript-eslint/class-literal-property-style": [0]
"@typescript-eslint/class-methods-use-this": [0]
"@typescript-eslint/consistent-generic-constructors": [0]
"@typescript-eslint/consistent-indexed-object-style": [0]
"@typescript-eslint/consistent-return": [0]
"@typescript-eslint/consistent-type-assertions": [2, {assertionStyle: as, objectLiteralTypeAssertions: allow}]
"@typescript-eslint/consistent-type-definitions": [2, type]
"@typescript-eslint/consistent-type-exports": [2, {fixMixedExportsWithInlineTypeSpecifier: false}]
"@typescript-eslint/consistent-type-imports": [2, {prefer: type-imports, fixStyle: separate-type-imports, disallowTypeAnnotations: true}]
"@typescript-eslint/default-param-last": [0]
"@typescript-eslint/dot-notation": [0]
"@typescript-eslint/explicit-function-return-type": [0]
"@typescript-eslint/explicit-member-accessibility": [0]
"@typescript-eslint/explicit-module-boundary-types": [0]
"@typescript-eslint/init-declarations": [0]
"@typescript-eslint/max-params": [0]
"@typescript-eslint/member-ordering": [0]
"@typescript-eslint/method-signature-style": [0]
"@typescript-eslint/naming-convention": [0]
"@typescript-eslint/no-array-constructor": [2]
"@typescript-eslint/no-array-delete": [2]
"@typescript-eslint/no-base-to-string": [0]
"@typescript-eslint/no-confusing-non-null-assertion": [2]
"@typescript-eslint/no-confusing-void-expression": [0]
"@typescript-eslint/no-deprecated": [2]
"@typescript-eslint/no-dupe-class-members": [0]
"@typescript-eslint/no-duplicate-enum-values": [2]
"@typescript-eslint/no-duplicate-type-constituents": [2, {ignoreUnions: true}]
"@typescript-eslint/no-dynamic-delete": [0]
"@typescript-eslint/no-empty-function": [0]
"@typescript-eslint/no-empty-interface": [0]
"@typescript-eslint/no-empty-object-type": [2]
"@typescript-eslint/no-explicit-any": [0]
"@typescript-eslint/no-extra-non-null-assertion": [2]
"@typescript-eslint/no-extraneous-class": [0]
"@typescript-eslint/no-floating-promises": [0]
"@typescript-eslint/no-for-in-array": [2]
"@typescript-eslint/no-implied-eval": [2]
"@typescript-eslint/no-import-type-side-effects": [0] # dupe with consistent-type-imports
"@typescript-eslint/no-inferrable-types": [0]
"@typescript-eslint/no-invalid-this": [0]
"@typescript-eslint/no-invalid-void-type": [0]
"@typescript-eslint/no-loop-func": [0]
"@typescript-eslint/no-loss-of-precision": [0]
"@typescript-eslint/no-magic-numbers": [0]
"@typescript-eslint/no-meaningless-void-operator": [0]
"@typescript-eslint/no-misused-new": [2]
"@typescript-eslint/no-misused-promises": [2, {checksVoidReturn: {attributes: false, arguments: false}}]
"@typescript-eslint/no-mixed-enums": [0]
"@typescript-eslint/no-namespace": [2]
"@typescript-eslint/no-non-null-asserted-nullish-coalescing": [0]
"@typescript-eslint/no-non-null-asserted-optional-chain": [2]
"@typescript-eslint/no-non-null-assertion": [0]
"@typescript-eslint/no-redeclare": [0]
"@typescript-eslint/no-redundant-type-constituents": [2]
"@typescript-eslint/no-require-imports": [2]
"@typescript-eslint/no-restricted-imports": [0]
"@typescript-eslint/no-restricted-types": [0]
"@typescript-eslint/no-shadow": [0]
"@typescript-eslint/no-this-alias": [0] # handled by unicorn/no-this-assignment
"@typescript-eslint/no-unnecessary-boolean-literal-compare": [0]
"@typescript-eslint/no-unnecessary-condition": [0]
"@typescript-eslint/no-unnecessary-qualifier": [0]
"@typescript-eslint/no-unnecessary-template-expression": [0]
"@typescript-eslint/no-unnecessary-type-arguments": [0]
"@typescript-eslint/no-unnecessary-type-assertion": [2]
"@typescript-eslint/no-unnecessary-type-constraint": [2]
"@typescript-eslint/no-unsafe-argument": [0]
"@typescript-eslint/no-unsafe-assignment": [0]
"@typescript-eslint/no-unsafe-call": [0]
"@typescript-eslint/no-unsafe-declaration-merging": [2]
"@typescript-eslint/no-unsafe-enum-comparison": [2]
"@typescript-eslint/no-unsafe-function-type": [2]
"@typescript-eslint/no-unsafe-member-access": [0]
"@typescript-eslint/no-unsafe-return": [0]
"@typescript-eslint/no-unsafe-unary-minus": [2]
"@typescript-eslint/no-unused-expressions": [0]
"@typescript-eslint/no-unused-vars": [2, {vars: all, args: all, caughtErrors: all, ignoreRestSiblings: false, argsIgnorePattern: ^_, varsIgnorePattern: ^_, caughtErrorsIgnorePattern: ^_, destructuredArrayIgnorePattern: ^_}]
"@typescript-eslint/no-use-before-define": [0]
"@typescript-eslint/no-useless-constructor": [0]
"@typescript-eslint/no-useless-empty-export": [0]
"@typescript-eslint/no-wrapper-object-types": [2]
"@typescript-eslint/non-nullable-type-assertion-style": [0]
"@typescript-eslint/only-throw-error": [2]
"@typescript-eslint/parameter-properties": [0]
"@typescript-eslint/prefer-as-const": [2]
"@typescript-eslint/prefer-destructuring": [0]
"@typescript-eslint/prefer-enum-initializers": [0]
"@typescript-eslint/prefer-find": [2]
"@typescript-eslint/prefer-for-of": [2]
"@typescript-eslint/prefer-function-type": [2]
"@typescript-eslint/prefer-includes": [2]
"@typescript-eslint/prefer-literal-enum-member": [0]
"@typescript-eslint/prefer-namespace-keyword": [0]
"@typescript-eslint/prefer-nullish-coalescing": [0]
"@typescript-eslint/prefer-optional-chain": [2, {requireNullish: true}]
"@typescript-eslint/prefer-promise-reject-errors": [0]
"@typescript-eslint/prefer-readonly": [0]
"@typescript-eslint/prefer-readonly-parameter-types": [0]
"@typescript-eslint/prefer-reduce-type-parameter": [0]
"@typescript-eslint/prefer-regexp-exec": [0]
"@typescript-eslint/prefer-return-this-type": [0]
"@typescript-eslint/prefer-string-starts-ends-with": [2, {allowSingleElementEquality: always}]
"@typescript-eslint/promise-function-async": [0]
"@typescript-eslint/require-array-sort-compare": [0]
"@typescript-eslint/require-await": [0]
"@typescript-eslint/restrict-plus-operands": [2]
"@typescript-eslint/restrict-template-expressions": [0]
"@typescript-eslint/return-await": [0]
"@typescript-eslint/strict-boolean-expressions": [0]
"@typescript-eslint/switch-exhaustiveness-check": [0]
"@typescript-eslint/triple-slash-reference": [2]
"@typescript-eslint/typedef": [0]
"@typescript-eslint/unbound-method": [0] # too many false-positives
"@typescript-eslint/unified-signatures": [2]
accessor-pairs: [2]
array-callback-return: [2, {checkForEach: true}]
array-func/avoid-reverse: [2]
array-func/from-map: [2]
array-func/no-unnecessary-this-arg: [2]
array-func/prefer-array-from: [2]
array-func/prefer-flat-map: [0] # handled by unicorn/prefer-array-flat-map
array-func/prefer-flat: [0] # handled by unicorn/prefer-array-flat
arrow-body-style: [0]
block-scoped-var: [2]
camelcase: [0]
capitalized-comments: [0]
class-methods-use-this: [0]
complexity: [0]
consistent-return: [0]
consistent-this: [0]
constructor-super: [2]
curly: [0]
default-case-last: [2]
default-case: [0]
default-param-last: [0]
dot-notation: [0]
eqeqeq: [2]
for-direction: [2]
func-name-matching: [2]
func-names: [0]
func-style: [0]
getter-return: [2]
github/a11y-aria-label-is-well-formatted: [0]
github/a11y-no-title-attribute: [0]
github/a11y-no-visually-hidden-interactive-element: [0]
github/a11y-role-supports-aria-props: [0]
github/a11y-svg-has-accessible-name: [0]
github/array-foreach: [0]
github/async-currenttarget: [2]
github/async-preventdefault: [2]
github/authenticity-token: [0]
github/get-attribute: [0]
github/js-class-name: [0]
github/no-blur: [0]
github/no-d-none: [0]
github/no-dataset: [2]
github/no-dynamic-script-tag: [2]
github/no-implicit-buggy-globals: [2]
github/no-inner-html: [0]
github/no-innerText: [2]
github/no-then: [2]
github/no-useless-passive: [2]
github/prefer-observers: [2]
github/require-passive-events: [2]
github/unescaped-html-literal: [0]
grouped-accessor-pairs: [2]
guard-for-in: [0]
id-blacklist: [0]
id-length: [0]
id-match: [0]
import-x/consistent-type-specifier-style: [0]
import-x/default: [0]
import-x/dynamic-import-chunkname: [0]
import-x/export: [2]
import-x/exports-last: [0]
import-x/extensions: [2, always, {ignorePackages: true}]
import-x/first: [2]
import-x/group-exports: [0]
import-x/max-dependencies: [0]
import-x/named: [2]
import-x/namespace: [0]
import-x/newline-after-import: [0]
import-x/no-absolute-path: [0]
import-x/no-amd: [2]
import-x/no-anonymous-default-export: [0]
import-x/no-commonjs: [2]
import-x/no-cycle: [2, {ignoreExternal: true, maxDepth: 1}]
import-x/no-default-export: [0]
import-x/no-deprecated: [0]
import-x/no-dynamic-require: [0]
import-x/no-empty-named-blocks: [2]
import-x/no-extraneous-dependencies: [2]
import-x/no-import-module-exports: [0]
import-x/no-internal-modules: [0]
import-x/no-mutable-exports: [0]
import-x/no-named-as-default-member: [0]
import-x/no-named-as-default: [0]
import-x/no-named-default: [0]
import-x/no-named-export: [0]
import-x/no-namespace: [0]
import-x/no-nodejs-modules: [0]
import-x/no-relative-packages: [0]
import-x/no-relative-parent-imports: [0]
import-x/no-restricted-paths: [0]
import-x/no-self-import: [2]
import-x/no-unassigned-import: [0]
import-x/no-unresolved: [2, {commonjs: true, ignore: ["\\?.+$"]}]
import-x/no-unused-modules: [2, {unusedExports: true}]
import-x/no-useless-path-segments: [2, {commonjs: true}]
import-x/no-webpack-loader-syntax: [2]
import-x/order: [0]
import-x/prefer-default-export: [0]
import-x/unambiguous: [0]
init-declarations: [0]
line-comment-position: [0]
logical-assignment-operators: [0]
max-classes-per-file: [0]
max-depth: [0]
max-lines-per-function: [0]
max-lines: [0]
max-nested-callbacks: [0]
max-params: [0]
max-statements: [0]
multiline-comment-style: [2, separate-lines]
new-cap: [0]
no-alert: [0]
no-array-constructor: [0] # handled by @typescript-eslint/no-array-constructor
no-async-promise-executor: [0]
no-await-in-loop: [0]
no-bitwise: [0]
no-buffer-constructor: [0]
no-caller: [2]
no-case-declarations: [2]
no-class-assign: [2]
no-compare-neg-zero: [2]
no-cond-assign: [2, except-parens]
no-console: [1, {allow: [debug, info, warn, error]}]
no-const-assign: [2]
no-constant-binary-expression: [2]
no-constant-condition: [0]
no-constructor-return: [2]
no-continue: [0]
no-control-regex: [0]
no-debugger: [1]
no-delete-var: [2]
no-div-regex: [0]
no-dupe-args: [2]
no-dupe-class-members: [2]
no-dupe-else-if: [2]
no-dupe-keys: [2]
no-duplicate-case: [2]
no-duplicate-imports: [0]
no-else-return: [2]
no-empty-character-class: [2]
no-empty-function: [0]
no-empty-pattern: [2]
no-empty-static-block: [2]
no-empty: [2, {allowEmptyCatch: true}]
no-eq-null: [2]
no-eval: [2]
no-ex-assign: [2]
no-extend-native: [2]
no-extra-bind: [2]
no-extra-boolean-cast: [2]
no-extra-label: [0]
no-fallthrough: [2]
no-func-assign: [2]
no-global-assign: [2]
no-implicit-coercion: [2]
no-implicit-globals: [0]
no-implied-eval: [0] # handled by @typescript-eslint/no-implied-eval
no-import-assign: [2]
no-inline-comments: [0]
no-inner-declarations: [2]
no-invalid-regexp: [2]
no-invalid-this: [0]
no-irregular-whitespace: [2]
no-iterator: [2]
no-jquery/no-ajax-events: [2]
no-jquery/no-ajax: [2]
no-jquery/no-and-self: [2]
no-jquery/no-animate-toggle: [2]
no-jquery/no-animate: [2]
no-jquery/no-append-html: [2]
no-jquery/no-attr: [2]
no-jquery/no-bind: [2]
no-jquery/no-box-model: [2]
no-jquery/no-browser: [2]
no-jquery/no-camel-case: [2]
no-jquery/no-class-state: [2]
no-jquery/no-class: [0]
no-jquery/no-clone: [2]
no-jquery/no-closest: [0]
no-jquery/no-constructor-attributes: [2]
no-jquery/no-contains: [2]
no-jquery/no-context-prop: [2]
no-jquery/no-css: [2]
no-jquery/no-data: [0]
no-jquery/no-deferred: [2]
no-jquery/no-delegate: [2]
no-jquery/no-done-fail: [2]
no-jquery/no-each-collection: [0]
no-jquery/no-each-util: [0]
no-jquery/no-each: [0]
no-jquery/no-error-shorthand: [2]
no-jquery/no-error: [2]
no-jquery/no-escape-selector: [2]
no-jquery/no-event-shorthand: [2]
no-jquery/no-extend: [2]
no-jquery/no-fade: [2]
no-jquery/no-filter: [0]
no-jquery/no-find-collection: [0]
no-jquery/no-find-util: [2]
no-jquery/no-find: [0]
no-jquery/no-fx-interval: [2]
no-jquery/no-fx: [2]
no-jquery/no-global-eval: [2]
no-jquery/no-global-selector: [0]
no-jquery/no-grep: [2]
no-jquery/no-has: [2]
no-jquery/no-hold-ready: [2]
no-jquery/no-html: [0]
no-jquery/no-in-array: [2]
no-jquery/no-is-array: [2]
no-jquery/no-is-empty-object: [2]
no-jquery/no-is-function: [2]
no-jquery/no-is-numeric: [2]
no-jquery/no-is-plain-object: [2]
no-jquery/no-is-window: [2]
no-jquery/no-is: [2]
no-jquery/no-jquery-constructor: [0]
no-jquery/no-live: [2]
no-jquery/no-load-shorthand: [2]
no-jquery/no-load: [2]
no-jquery/no-map-collection: [0]
no-jquery/no-map-util: [2]
no-jquery/no-map: [2]
no-jquery/no-merge: [2]
no-jquery/no-node-name: [2]
no-jquery/no-noop: [2]
no-jquery/no-now: [2]
no-jquery/no-on-ready: [2]
no-jquery/no-other-methods: [0]
no-jquery/no-other-utils: [2]
no-jquery/no-param: [2]
no-jquery/no-parent: [0]
no-jquery/no-parents: [2]
no-jquery/no-parse-html-literal: [2]
no-jquery/no-parse-html: [2]
no-jquery/no-parse-json: [2]
no-jquery/no-parse-xml: [2]
no-jquery/no-prop: [2]
no-jquery/no-proxy: [2]
no-jquery/no-ready-shorthand: [2]
no-jquery/no-ready: [2]
no-jquery/no-selector-prop: [2]
no-jquery/no-serialize: [2]
no-jquery/no-size: [2]
no-jquery/no-sizzle: [2]
no-jquery/no-slide: [2]
no-jquery/no-sub: [2]
no-jquery/no-support: [2]
no-jquery/no-text: [2]
no-jquery/no-trigger: [0]
no-jquery/no-trim: [2]
no-jquery/no-type: [2]
no-jquery/no-unique: [2]
no-jquery/no-unload-shorthand: [2]
no-jquery/no-val: [0]
no-jquery/no-visibility: [2]
no-jquery/no-when: [2]
no-jquery/no-wrap: [2]
no-jquery/variable-pattern: [2]
no-label-var: [2]
no-labels: [0] # handled by no-restricted-syntax
no-lone-blocks: [2]
no-lonely-if: [0]
no-loop-func: [0]
no-loss-of-precision: [2]
no-magic-numbers: [0]
no-misleading-character-class: [2]
no-multi-assign: [0]
no-multi-str: [2]
no-negated-condition: [0]
no-nested-ternary: [0]
no-new-func: [2]
no-new-native-nonconstructor: [2]
no-new-object: [2]
no-new-symbol: [2]
no-new-wrappers: [2]
no-new: [0]
no-nonoctal-decimal-escape: [2]
no-obj-calls: [2]
no-octal-escape: [2]
no-octal: [2]
no-param-reassign: [0]
no-plusplus: [0]
no-promise-executor-return: [0]
no-proto: [2]
no-prototype-builtins: [2]
no-redeclare: [0] # must be disabled for typescript overloads
no-regex-spaces: [2]
no-restricted-exports: [0]
no-restricted-globals: [2, addEventListener, blur, close, closed, confirm, defaultStatus, defaultstatus, error, event, external, find, focus, frameElement, frames, history, innerHeight, innerWidth, isFinite, isNaN, length, location, locationbar, menubar, moveBy, moveTo, name, onblur, onerror, onfocus, onload, onresize, onunload, open, opener, opera, outerHeight, outerWidth, pageXOffset, pageYOffset, parent, print, removeEventListener, resizeBy, resizeTo, screen, screenLeft, screenTop, screenX, screenY, scroll, scrollbars, scrollBy, scrollTo, scrollX, scrollY, self, status, statusbar, stop, toolbar, top, __dirname, __filename]
no-restricted-imports: [0]
no-restricted-syntax: [2, WithStatement, ForInStatement, LabeledStatement, SequenceExpression, {selector: "CallExpression[callee.name='fetch']", message: "use modules/fetch.ts instead"}]
no-return-assign: [0]
no-script-url: [2]
no-self-assign: [2, {props: true}]
no-self-compare: [2]
no-sequences: [2]
no-setter-return: [2]
no-shadow-restricted-names: [2]
no-shadow: [0]
no-sparse-arrays: [2]
no-template-curly-in-string: [2]
no-ternary: [0]
no-this-before-super: [2]
no-throw-literal: [2]
no-undef-init: [2]
no-undef: [2, {typeof: true}] # TODO: disable this rule after tsc passes
no-undefined: [0]
no-underscore-dangle: [0]
no-unexpected-multiline: [2]
no-unmodified-loop-condition: [2]
no-unneeded-ternary: [2]
no-unreachable-loop: [2]
no-unreachable: [2]
no-unsafe-finally: [2]
no-unsafe-negation: [2]
no-unused-expressions: [2]
no-unused-labels: [2]
no-unused-private-class-members: [2]
no-unused-vars: [0] # handled by @typescript-eslint/no-unused-vars
no-use-before-define: [2, {functions: false, classes: true, variables: true, allowNamedExports: true}]
no-use-extend-native/no-use-extend-native: [2]
no-useless-backreference: [2]
no-useless-call: [2]
no-useless-catch: [2]
no-useless-computed-key: [2]
no-useless-concat: [2]
no-useless-constructor: [2]
no-useless-escape: [2]
no-useless-rename: [2]
no-useless-return: [2]
no-var: [2]
no-void: [2]
no-warning-comments: [0]
no-with: [0] # handled by no-restricted-syntax
object-shorthand: [2, always]
one-var-declaration-per-line: [0]
one-var: [0]
operator-assignment: [2, always]
operator-linebreak: [2, after]
prefer-arrow-callback: [2, {allowNamedFunctions: true, allowUnboundThis: true}]
prefer-const: [2, {destructuring: all, ignoreReadBeforeAssign: true}]
prefer-destructuring: [0]
prefer-exponentiation-operator: [2]
prefer-named-capture-group: [0]
prefer-numeric-literals: [2]
prefer-object-has-own: [2]
prefer-object-spread: [2]
prefer-promise-reject-errors: [2, {allowEmptyReject: false}]
prefer-regex-literals: [2]
prefer-rest-params: [2]
prefer-spread: [2]
prefer-template: [2]
radix: [2, as-needed]
regexp/confusing-quantifier: [2]
regexp/control-character-escape: [2]
regexp/hexadecimal-escape: [0]
regexp/letter-case: [0]
regexp/match-any: [2]
regexp/negation: [2]
regexp/no-contradiction-with-assertion: [0]
regexp/no-control-character: [0]
regexp/no-dupe-characters-character-class: [2]
regexp/no-dupe-disjunctions: [2]
regexp/no-empty-alternative: [2]
regexp/no-empty-capturing-group: [2]
regexp/no-empty-character-class: [0]
regexp/no-empty-group: [2]
regexp/no-empty-lookarounds-assertion: [2]
regexp/no-empty-string-literal: [2]
regexp/no-escape-backspace: [2]
regexp/no-extra-lookaround-assertions: [0]
regexp/no-invalid-regexp: [2]
regexp/no-invisible-character: [2]
regexp/no-lazy-ends: [2]
regexp/no-legacy-features: [2]
regexp/no-misleading-capturing-group: [0]
regexp/no-misleading-unicode-character: [0]
regexp/no-missing-g-flag: [2]
regexp/no-non-standard-flag: [2]
regexp/no-obscure-range: [2]
regexp/no-octal: [2]
regexp/no-optional-assertion: [2]
regexp/no-potentially-useless-backreference: [2]
regexp/no-standalone-backslash: [2]
regexp/no-super-linear-backtracking: [0]
regexp/no-super-linear-move: [0]
regexp/no-trivially-nested-assertion: [2]
regexp/no-trivially-nested-quantifier: [2]
regexp/no-unused-capturing-group: [0]
regexp/no-useless-assertions: [2]
regexp/no-useless-backreference: [2]
regexp/no-useless-character-class: [2]
regexp/no-useless-dollar-replacements: [2]
regexp/no-useless-escape: [2]
regexp/no-useless-flag: [2]
regexp/no-useless-lazy: [2]
regexp/no-useless-non-capturing-group: [2]
regexp/no-useless-quantifier: [2]
regexp/no-useless-range: [2]
regexp/no-useless-set-operand: [2]
regexp/no-useless-string-literal: [2]
regexp/no-useless-two-nums-quantifier: [2]
regexp/no-zero-quantifier: [2]
regexp/optimal-lookaround-quantifier: [2]
regexp/optimal-quantifier-concatenation: [0]
regexp/prefer-character-class: [0]
regexp/prefer-d: [0]
regexp/prefer-escape-replacement-dollar-char: [0]
regexp/prefer-lookaround: [0]
regexp/prefer-named-backreference: [0]
regexp/prefer-named-capture-group: [0]
regexp/prefer-named-replacement: [0]
regexp/prefer-plus-quantifier: [2]
regexp/prefer-predefined-assertion: [2]
regexp/prefer-quantifier: [0]
regexp/prefer-question-quantifier: [2]
regexp/prefer-range: [2]
regexp/prefer-regexp-exec: [2]
regexp/prefer-regexp-test: [2]
regexp/prefer-result-array-groups: [0]
regexp/prefer-set-operation: [2]
regexp/prefer-star-quantifier: [2]
regexp/prefer-unicode-codepoint-escapes: [2]
regexp/prefer-w: [0]
regexp/require-unicode-regexp: [0]
regexp/simplify-set-operations: [2]
regexp/sort-alternatives: [0]
regexp/sort-character-class-elements: [0]
regexp/sort-flags: [0]
regexp/strict: [2]
regexp/unicode-escape: [0]
regexp/use-ignore-case: [0]
require-atomic-updates: [0]
require-await: [0] # handled by @typescript-eslint/require-await
require-unicode-regexp: [0]
require-yield: [2]
sonarjs/cognitive-complexity: [0]
sonarjs/elseif-without-else: [0]
sonarjs/max-switch-cases: [0]
sonarjs/no-all-duplicated-branches: [2]
sonarjs/no-collapsible-if: [0]
sonarjs/no-collection-size-mischeck: [2]
sonarjs/no-duplicate-string: [0]
sonarjs/no-duplicated-branches: [0]
sonarjs/no-element-overwrite: [2]
sonarjs/no-empty-collection: [2]
sonarjs/no-extra-arguments: [2]
sonarjs/no-gratuitous-expressions: [2]
sonarjs/no-identical-conditions: [2]
sonarjs/no-identical-expressions: [2]
sonarjs/no-identical-functions: [2, 5]
sonarjs/no-ignored-return: [2]
sonarjs/no-inverted-boolean-check: [2]
sonarjs/no-nested-switch: [0]
sonarjs/no-nested-template-literals: [0]
sonarjs/no-one-iteration-loop: [2]
sonarjs/no-redundant-boolean: [2]
sonarjs/no-redundant-jump: [2]
sonarjs/no-same-line-conditional: [2]
sonarjs/no-small-switch: [0]
sonarjs/no-unused-collection: [2]
sonarjs/no-use-of-empty-return-value: [2]
sonarjs/no-useless-catch: [2]
sonarjs/non-existent-operator: [2]
sonarjs/prefer-immediate-return: [0]
sonarjs/prefer-object-literal: [0]
sonarjs/prefer-single-boolean-return: [0]
sonarjs/prefer-while: [2]
sort-imports: [0]
sort-keys: [0]
sort-vars: [0]
strict: [0]
symbol-description: [2]
unicode-bom: [2, never]
unicorn/better-regex: [0]
unicorn/catch-error-name: [0]
unicorn/consistent-destructuring: [2]
unicorn/consistent-empty-array-spread: [2]
unicorn/consistent-existence-index-check: [0]
unicorn/consistent-function-scoping: [0]
unicorn/custom-error-definition: [0]
unicorn/empty-brace-spaces: [2]
unicorn/error-message: [0]
unicorn/escape-case: [0]
unicorn/expiring-todo-comments: [0]
unicorn/explicit-length-check: [0]
unicorn/filename-case: [0]
unicorn/import-index: [0]
unicorn/import-style: [0]
unicorn/new-for-builtins: [2]
unicorn/no-abusive-eslint-disable: [0]
unicorn/no-anonymous-default-export: [0]
unicorn/no-array-callback-reference: [0]
unicorn/no-array-for-each: [2]
unicorn/no-array-method-this-argument: [2]
unicorn/no-array-push-push: [2]
unicorn/no-array-reduce: [2]
unicorn/no-await-expression-member: [0]
unicorn/no-await-in-promise-methods: [2]
unicorn/no-console-spaces: [0]
unicorn/no-document-cookie: [2]
unicorn/no-empty-file: [2]
unicorn/no-for-loop: [0]
unicorn/no-hex-escape: [0]
unicorn/no-instanceof-array: [0]
unicorn/no-invalid-fetch-options: [2]
unicorn/no-invalid-remove-event-listener: [2]
unicorn/no-keyword-prefix: [0]
unicorn/no-length-as-slice-end: [2]
unicorn/no-lonely-if: [2]
unicorn/no-magic-array-flat-depth: [0]
unicorn/no-negated-condition: [0]
unicorn/no-negation-in-equality-check: [2]
unicorn/no-nested-ternary: [0]
unicorn/no-new-array: [0]
unicorn/no-new-buffer: [0]
unicorn/no-null: [0]
unicorn/no-object-as-default-parameter: [0]
unicorn/no-process-exit: [0]
unicorn/no-single-promise-in-promise-methods: [2]
unicorn/no-static-only-class: [2]
unicorn/no-thenable: [2]
unicorn/no-this-assignment: [2]
unicorn/no-typeof-undefined: [2]
unicorn/no-unnecessary-await: [2]
unicorn/no-unnecessary-polyfills: [2]
unicorn/no-unreadable-array-destructuring: [0]
unicorn/no-unreadable-iife: [2]
unicorn/no-unused-properties: [2]
unicorn/no-useless-fallback-in-spread: [2]
unicorn/no-useless-length-check: [2]
unicorn/no-useless-promise-resolve-reject: [2]
unicorn/no-useless-spread: [2]
unicorn/no-useless-switch-case: [2]
unicorn/no-useless-undefined: [0]
unicorn/no-zero-fractions: [2]
unicorn/number-literal-case: [0]
unicorn/numeric-separators-style: [0]
unicorn/prefer-add-event-listener: [2]
unicorn/prefer-array-find: [2]
unicorn/prefer-array-flat-map: [2]
unicorn/prefer-array-flat: [2]
unicorn/prefer-array-index-of: [2]
unicorn/prefer-array-some: [2]
unicorn/prefer-at: [0]
unicorn/prefer-blob-reading-methods: [2]
unicorn/prefer-code-point: [0]
unicorn/prefer-date-now: [2]
unicorn/prefer-default-parameters: [0]
unicorn/prefer-dom-node-append: [2]
unicorn/prefer-dom-node-dataset: [0]
unicorn/prefer-dom-node-remove: [2]
unicorn/prefer-dom-node-text-content: [2]
unicorn/prefer-event-target: [2]
unicorn/prefer-export-from: [0]
unicorn/prefer-global-this: [0]
unicorn/prefer-includes: [2]
unicorn/prefer-json-parse-buffer: [0]
unicorn/prefer-keyboard-event-key: [2]
unicorn/prefer-logical-operator-over-ternary: [2]
unicorn/prefer-math-min-max: [2]
unicorn/prefer-math-trunc: [2]
unicorn/prefer-modern-dom-apis: [0]
unicorn/prefer-modern-math-apis: [2]
unicorn/prefer-module: [2]
unicorn/prefer-native-coercion-functions: [2]
unicorn/prefer-negative-index: [2]
unicorn/prefer-node-protocol: [2]
unicorn/prefer-number-properties: [0]
unicorn/prefer-object-from-entries: [2]
unicorn/prefer-object-has-own: [0]
unicorn/prefer-optional-catch-binding: [2]
unicorn/prefer-prototype-methods: [0]
unicorn/prefer-query-selector: [2]
unicorn/prefer-reflect-apply: [0]
unicorn/prefer-regexp-test: [2]
unicorn/prefer-set-has: [0]
unicorn/prefer-set-size: [2]
unicorn/prefer-spread: [0]
unicorn/prefer-string-raw: [0]
unicorn/prefer-string-replace-all: [0]
unicorn/prefer-string-slice: [0]
unicorn/prefer-string-starts-ends-with: [2]
unicorn/prefer-string-trim-start-end: [2]
unicorn/prefer-structured-clone: [2]
unicorn/prefer-switch: [0]
unicorn/prefer-ternary: [0]
unicorn/prefer-text-content: [2]
unicorn/prefer-top-level-await: [0]
unicorn/prefer-type-error: [0]
unicorn/prevent-abbreviations: [0]
unicorn/relative-url-style: [2]
unicorn/require-array-join-separator: [2]
unicorn/require-number-to-fixed-digits-argument: [2]
unicorn/require-post-message-target-origin: [0]
unicorn/string-content: [0]
unicorn/switch-case-braces: [0]
unicorn/template-indent: [2]
unicorn/text-encoding-identifier-case: [0]
unicorn/throw-new-error: [2]
use-isnan: [2]
valid-typeof: [2, {requireStringLiterals: true}]
vars-on-top: [0]
wc/attach-shadow-constructor: [2]
wc/define-tag-after-class-definition: [0]
wc/expose-class-on-global: [0]
wc/file-name-matches-element: [2]
wc/guard-define-call: [0]
wc/guard-super-call: [2]
wc/max-elements-per-file: [0]
wc/no-child-traversal-in-attributechangedcallback: [2]
wc/no-child-traversal-in-connectedcallback: [2]
wc/no-closed-shadow-root: [2]
wc/no-constructor-attributes: [2]
wc/no-constructor-params: [2]
wc/no-constructor: [2]
wc/no-customized-built-in-elements: [2]
wc/no-exports-with-element: [0]
wc/no-invalid-element-name: [2]
wc/no-invalid-extends: [2]
wc/no-method-prefixed-with-on: [2]
wc/no-self-class: [2]
wc/no-typos: [2]
wc/require-listener-teardown: [2]
wc/tag-name-matches-class: [2]
yoda: [2, never]

3
.gitattributes vendored
View File

@ -4,8 +4,7 @@
/assets/*.json linguist-generated /assets/*.json linguist-generated
/public/assets/img/svg/*.svg linguist-generated /public/assets/img/svg/*.svg linguist-generated
/templates/swagger/v1_json.tmpl linguist-generated /templates/swagger/v1_json.tmpl linguist-generated
/options/fileicon/** linguist-generated
/vendor/** -text -eol linguist-vendored /vendor/** -text -eol linguist-vendored
/web_src/fomantic/build/** linguist-generated
/web_src/fomantic/_site/globals/site.variables linguist-language=Less
/web_src/js/vendor/** -text -eol linguist-vendored /web_src/js/vendor/** -text -eol linguist-vendored
Dockerfile.* linguist-language=Dockerfile Dockerfile.* linguist-language=Dockerfile

View File

@ -13,5 +13,5 @@ contact_links:
url: https://docs.gitea.com/help/faq url: https://docs.gitea.com/help/faq
about: Please check if your question isn't mentioned here. about: Please check if your question isn't mentioned here.
- name: Crowdin Translations - name: Crowdin Translations
url: https://crowdin.com/project/gitea url: https://translate.gitea.com
about: Translations are managed here. about: Translations are managed here.

10
.github/labeler.yml vendored
View File

@ -41,7 +41,7 @@ modifies/internal:
- ".dockerignore" - ".dockerignore"
- "docker/**" - "docker/**"
- ".editorconfig" - ".editorconfig"
- ".eslintrc.yaml" - ".eslintrc.cjs"
- ".golangci.yml" - ".golangci.yml"
- ".gitpod.yml" - ".gitpod.yml"
- ".markdownlint.yaml" - ".markdownlint.yaml"
@ -49,7 +49,7 @@ modifies/internal:
- "stylelint.config.js" - "stylelint.config.js"
- ".yamllint.yaml" - ".yamllint.yaml"
- ".github/**" - ".github/**"
- ".gitea/" - ".gitea/**"
- ".devcontainer/**" - ".devcontainer/**"
- "build.go" - "build.go"
- "build/**" - "build/**"
@ -73,9 +73,9 @@ modifies/go:
modifies/frontend: modifies/frontend:
- changed-files: - changed-files:
- any-glob-to-any-file: - any-glob-to-any-file:
- "**/*.js" - "*.js"
- "**/*.ts" - "*.ts"
- "**/*.vue" - "web_src/**"
docs-update-needed: docs-update-needed:
- changed-files: - changed-files:

View File

@ -1,8 +1,8 @@
name: cron-licenses name: cron-licenses
on: on:
schedule: # schedule:
- cron: "7 0 * * 1" # every Monday at 00:07 UTC # - cron: "7 0 * * 1" # every Monday at 00:07 UTC
workflow_dispatch: workflow_dispatch:
jobs: jobs:
@ -15,7 +15,7 @@ jobs:
with: with:
go-version-file: go.mod go-version-file: go.mod
check-latest: true check-latest: true
- run: make generate-license generate-gitignore - run: make generate-gitignore
timeout-minutes: 40 timeout-minutes: 40
- name: push translations to repo - name: push translations to repo
uses: appleboy/git-push-action@v0.0.3 uses: appleboy/git-push-action@v0.0.3

View File

@ -51,14 +51,16 @@ jobs:
- "options/locale/locale_en-US.ini" - "options/locale/locale_en-US.ini"
frontend: frontend:
- "**/*.js" - "*.js"
- "*.ts"
- "web_src/**" - "web_src/**"
- "tools/*.js"
- "tools/*.ts"
- "assets/emoji.json" - "assets/emoji.json"
- "package.json" - "package.json"
- "package-lock.json" - "package-lock.json"
- "Makefile" - "Makefile"
- ".eslintrc.yaml" - ".eslintrc.cjs"
- "stylelint.config.js"
- ".npmrc" - ".npmrc"
docs: docs:
@ -85,6 +87,7 @@ jobs:
swagger: swagger:
- "templates/swagger/v1_json.tmpl" - "templates/swagger/v1_json.tmpl"
- "templates/swagger/v1_input.json"
- "Makefile" - "Makefile"
- "package.json" - "package.json"
- "package-lock.json" - "package-lock.json"

View File

@ -95,7 +95,7 @@ jobs:
go-version-file: go.mod go-version-file: go.mod
check-latest: true check-latest: true
- run: make deps-backend deps-tools - run: make deps-backend deps-tools
- run: make lint-go-windows lint-go-vet - run: make lint-go-windows lint-go-gitea-vet
env: env:
TAGS: bindata sqlite sqlite_unlock_notify TAGS: bindata sqlite sqlite_unlock_notify
GOOS: windows GOOS: windows

View File

@ -98,7 +98,7 @@ jobs:
ports: ports:
- "9200:9200" - "9200:9200"
meilisearch: meilisearch:
image: getmeili/meilisearch:v1.2.0 image: getmeili/meilisearch:v1
env: env:
MEILI_ENV: development # disable auth MEILI_ENV: development # disable auth
ports: ports:
@ -202,12 +202,10 @@ jobs:
test-mssql: test-mssql:
if: needs.files-changed.outputs.backend == 'true' || needs.files-changed.outputs.actions == 'true' if: needs.files-changed.outputs.backend == 'true' || needs.files-changed.outputs.actions == 'true'
needs: files-changed needs: files-changed
# specifying the version of ubuntu in use as mssql fails on newer kernels runs-on: ubuntu-latest
# pending resolution from vendor
runs-on: ubuntu-20.04
services: services:
mssql: mssql:
image: mcr.microsoft.com/mssql/server:2017-latest image: mcr.microsoft.com/mssql/server:2019-latest
env: env:
ACCEPT_EULA: Y ACCEPT_EULA: Y
MSSQL_PID: Standard MSSQL_PID: Standard

View File

@ -59,6 +59,8 @@ jobs:
aws s3 sync dist/release s3://${{ secrets.AWS_S3_BUCKET }}/gitea/${{ steps.clean_name.outputs.branch }} --no-progress aws s3 sync dist/release s3://${{ secrets.AWS_S3_BUCKET }}/gitea/${{ steps.clean_name.outputs.branch }} --no-progress
nightly-docker-rootful: nightly-docker-rootful:
runs-on: namespace-profile-gitea-release-docker runs-on: namespace-profile-gitea-release-docker
permissions:
packages: write # to publish to ghcr.io
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
# fetch all commits instead of only the last as some branches are long lived and could have many between versions # fetch all commits instead of only the last as some branches are long lived and could have many between versions
@ -85,17 +87,27 @@ jobs:
with: with:
username: ${{ secrets.DOCKERHUB_USERNAME }} username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }} password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Login to GHCR using PAT
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: fetch go modules - name: fetch go modules
run: make vendor run: make vendor
- name: build rootful docker image - name: build rootful docker image
uses: docker/build-push-action@v5 uses: docker/build-push-action@v5
with: with:
context: . context: .
platforms: linux/amd64,linux/arm64 platforms: linux/amd64,linux/arm64,linux/riscv64
push: true push: true
tags: gitea/gitea:${{ steps.clean_name.outputs.branch }} tags: |-
gitea/gitea:${{ steps.clean_name.outputs.branch }}
ghcr.io/go-gitea/gitea:${{ steps.clean_name.outputs.branch }}
nightly-docker-rootless: nightly-docker-rootless:
runs-on: namespace-profile-gitea-release-docker runs-on: namespace-profile-gitea-release-docker
permissions:
packages: write # to publish to ghcr.io
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
# fetch all commits instead of only the last as some branches are long lived and could have many between versions # fetch all commits instead of only the last as some branches are long lived and could have many between versions
@ -122,6 +134,12 @@ jobs:
with: with:
username: ${{ secrets.DOCKERHUB_USERNAME }} username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }} password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Login to GHCR using PAT
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: fetch go modules - name: fetch go modules
run: make vendor run: make vendor
- name: build rootless docker image - name: build rootless docker image
@ -131,4 +149,6 @@ jobs:
platforms: linux/amd64,linux/arm64 platforms: linux/amd64,linux/arm64
push: true push: true
file: Dockerfile.rootless file: Dockerfile.rootless
tags: gitea/gitea:${{ steps.clean_name.outputs.branch }}-rootless tags: |-
gitea/gitea:${{ steps.clean_name.outputs.branch }}-rootless
ghcr.io/go-gitea/gitea:${{ steps.clean_name.outputs.branch }}-rootless

View File

@ -69,6 +69,8 @@ jobs:
GITHUB_TOKEN: ${{ secrets.RELEASE_TOKEN }} GITHUB_TOKEN: ${{ secrets.RELEASE_TOKEN }}
docker-rootful: docker-rootful:
runs-on: namespace-profile-gitea-release-docker runs-on: namespace-profile-gitea-release-docker
permissions:
packages: write # to publish to ghcr.io
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
# fetch all commits instead of only the last as some branches are long lived and could have many between versions # fetch all commits instead of only the last as some branches are long lived and could have many between versions
@ -79,7 +81,9 @@ jobs:
- uses: docker/metadata-action@v5 - uses: docker/metadata-action@v5
id: meta id: meta
with: with:
images: gitea/gitea images: |-
gitea/gitea
ghcr.io/go-gitea/gitea
flavor: | flavor: |
latest=false latest=false
# 1.2.3-rc0 # 1.2.3-rc0
@ -90,16 +94,24 @@ jobs:
with: with:
username: ${{ secrets.DOCKERHUB_USERNAME }} username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }} password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Login to GHCR using PAT
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: build rootful docker image - name: build rootful docker image
uses: docker/build-push-action@v5 uses: docker/build-push-action@v5
with: with:
context: . context: .
platforms: linux/amd64,linux/arm64 platforms: linux/amd64,linux/arm64,linux/riscv64
push: true push: true
tags: ${{ steps.meta.outputs.tags }} tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }} labels: ${{ steps.meta.outputs.labels }}
docker-rootless: docker-rootless:
runs-on: namespace-profile-gitea-release-docker runs-on: namespace-profile-gitea-release-docker
permissions:
packages: write # to publish to ghcr.io
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
# fetch all commits instead of only the last as some branches are long lived and could have many between versions # fetch all commits instead of only the last as some branches are long lived and could have many between versions
@ -110,7 +122,9 @@ jobs:
- uses: docker/metadata-action@v5 - uses: docker/metadata-action@v5
id: meta id: meta
with: with:
images: gitea/gitea images: |-
gitea/gitea
ghcr.io/go-gitea/gitea
# each tag below will have the suffix of -rootless # each tag below will have the suffix of -rootless
flavor: | flavor: |
latest=false latest=false
@ -123,11 +137,17 @@ jobs:
with: with:
username: ${{ secrets.DOCKERHUB_USERNAME }} username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }} password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Login to GHCR using PAT
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: build rootless docker image - name: build rootless docker image
uses: docker/build-push-action@v5 uses: docker/build-push-action@v5
with: with:
context: . context: .
platforms: linux/amd64,linux/arm64 platforms: linux/amd64,linux/arm64,linux/riscv64
push: true push: true
file: Dockerfile.rootless file: Dockerfile.rootless
tags: ${{ steps.meta.outputs.tags }} tags: ${{ steps.meta.outputs.tags }}

View File

@ -14,6 +14,8 @@ concurrency:
jobs: jobs:
binary: binary:
runs-on: namespace-profile-gitea-release-binary runs-on: namespace-profile-gitea-release-binary
permissions:
packages: write # to publish to ghcr.io
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
# fetch all commits instead of only the last as some branches are long lived and could have many between versions # fetch all commits instead of only the last as some branches are long lived and could have many between versions
@ -71,6 +73,8 @@ jobs:
GITHUB_TOKEN: ${{ secrets.RELEASE_TOKEN }} GITHUB_TOKEN: ${{ secrets.RELEASE_TOKEN }}
docker-rootful: docker-rootful:
runs-on: namespace-profile-gitea-release-docker runs-on: namespace-profile-gitea-release-docker
permissions:
packages: write # to publish to ghcr.io
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
# fetch all commits instead of only the last as some branches are long lived and could have many between versions # fetch all commits instead of only the last as some branches are long lived and could have many between versions
@ -81,26 +85,34 @@ jobs:
- uses: docker/metadata-action@v5 - uses: docker/metadata-action@v5
id: meta id: meta
with: with:
images: gitea/gitea images: |-
gitea/gitea
ghcr.io/go-gitea/gitea
# this will generate tags in the following format: # this will generate tags in the following format:
# latest # latest
# 1 # 1
# 1.2 # 1.2
# 1.2.3 # 1.2.3
tags: | tags: |
type=semver,pattern={{version}}
type=semver,pattern={{major}} type=semver,pattern={{major}}
type=semver,pattern={{major}}.{{minor}} type=semver,pattern={{major}}.{{minor}}
type=semver,pattern={{version}}
- name: Login to Docker Hub - name: Login to Docker Hub
uses: docker/login-action@v3 uses: docker/login-action@v3
with: with:
username: ${{ secrets.DOCKERHUB_USERNAME }} username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }} password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Login to GHCR using PAT
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: build rootful docker image - name: build rootful docker image
uses: docker/build-push-action@v5 uses: docker/build-push-action@v5
with: with:
context: . context: .
platforms: linux/amd64,linux/arm64 platforms: linux/amd64,linux/arm64,linux/riscv64
push: true push: true
tags: ${{ steps.meta.outputs.tags }} tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }} labels: ${{ steps.meta.outputs.labels }}
@ -116,7 +128,9 @@ jobs:
- uses: docker/metadata-action@v5 - uses: docker/metadata-action@v5
id: meta id: meta
with: with:
images: gitea/gitea images: |-
gitea/gitea
ghcr.io/go-gitea/gitea
# each tag below will have the suffix of -rootless # each tag below will have the suffix of -rootless
flavor: | flavor: |
suffix=-rootless,onlatest=true suffix=-rootless,onlatest=true
@ -126,19 +140,25 @@ jobs:
# 1.2 # 1.2
# 1.2.3 # 1.2.3
tags: | tags: |
type=semver,pattern={{version}}
type=semver,pattern={{major}} type=semver,pattern={{major}}
type=semver,pattern={{major}}.{{minor}} type=semver,pattern={{major}}.{{minor}}
type=semver,pattern={{version}}
- name: Login to Docker Hub - name: Login to Docker Hub
uses: docker/login-action@v3 uses: docker/login-action@v3
with: with:
username: ${{ secrets.DOCKERHUB_USERNAME }} username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }} password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Login to GHCR using PAT
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: build rootless docker image - name: build rootless docker image
uses: docker/build-push-action@v5 uses: docker/build-push-action@v5
with: with:
context: . context: .
platforms: linux/amd64,linux/arm64 platforms: linux/amd64,linux/arm64,linux/riscv64
push: true push: true
file: Dockerfile.rootless file: Dockerfile.rootless
tags: ${{ steps.meta.outputs.tags }} tags: ${{ steps.meta.outputs.tags }}

17
.gitignore vendored
View File

@ -9,6 +9,11 @@ _test
# IntelliJ # IntelliJ
.idea .idea
.run
# IntelliJ Gateway
.uuid
# Goland's output filename can not be set manually # Goland's output filename can not be set manually
/go_build_* /go_build_*
/gitea_* /gitea_*
@ -79,18 +84,6 @@ cpu.out
/public/assets/fonts /public/assets/fonts
/public/assets/licenses.txt /public/assets/licenses.txt
/vendor /vendor
/web_src/fomantic/node_modules
/web_src/fomantic/build/*
!/web_src/fomantic/build/semantic.js
!/web_src/fomantic/build/semantic.css
!/web_src/fomantic/build/themes
/web_src/fomantic/build/themes/*
!/web_src/fomantic/build/themes/default
/web_src/fomantic/build/themes/default/assets/*
!/web_src/fomantic/build/themes/default/assets/fonts
/web_src/fomantic/build/themes/default/assets/fonts/*
!/web_src/fomantic/build/themes/default/assets/fonts/icons.woff2
!/web_src/fomantic/build/themes/default/assets/fonts/outline-icons.woff2
/VERSION /VERSION
/.air /.air
/.go-licenses /.go-licenses

View File

@ -1,7 +1,9 @@
version: "2"
output:
sort-order:
- file
linters: linters:
enable-all: false default: none
disable-all: true
fast: false
enable: enable:
- bidichk - bidichk
- depguard - depguard
@ -9,41 +11,40 @@ linters:
- errcheck - errcheck
- forbidigo - forbidigo
- gocritic - gocritic
- gofmt
- gofumpt
- gosimple
- govet - govet
- ineffassign - ineffassign
- mirror
- nakedret - nakedret
- nolintlint - nolintlint
- perfsprint
- revive - revive
- staticcheck - staticcheck
- stylecheck
- tenv
- testifylint - testifylint
- typecheck
- unconvert - unconvert
- unused
- unparam - unparam
- unused
- usestdlibvars
- usetesting
- wastedassign - wastedassign
settings:
run: depguard:
timeout: 10m rules:
main:
output: deny:
sort-results: true - pkg: encoding/json
sort-order: [file] desc: use gitea's modules/json instead of encoding/json
show-stats: true - pkg: github.com/unknwon/com
desc: use gitea's util and replacements
linters-settings: - pkg: io/ioutil
testifylint: desc: use os or io instead
disable: - pkg: golang.org/x/exp
- go-require desc: it's experimental and unreliable
- require-error - pkg: code.gitea.io/gitea/modules/git/internal
stylecheck: desc: do not use the internal package, use AddXxx function instead
checks: ["all", "-ST1005", "-ST1003"] - pkg: gopkg.in/ini.v1
nakedret: desc: do not use the ini package, use gitea's config system instead
max-func-lines: 0 - pkg: gitea.com/go-chi/cache
desc: do not use the go-chi cache package, use gitea's cache system
gocritic: gocritic:
disabled-checks: disabled-checks:
- ifElseChain - ifElseChain
@ -82,66 +83,90 @@ linters-settings:
- name: unreachable-code - name: unreachable-code
- name: var-declaration - name: var-declaration
- name: var-naming - name: var-naming
gofumpt: staticcheck:
extra-rules: true checks:
depguard: - all
- -ST1003
- -ST1005
- -QF1001
- -QF1006
- -QF1008
testifylint:
disable:
- go-require
- require-error
usetesting:
os-temp-dir: true
exclusions:
generated: lax
presets:
- comments
- common-false-positives
- legacy
- std-error-handling
rules: rules:
main: - linters:
deny: - dupl
- pkg: encoding/json - errcheck
desc: use gitea's modules/json instead of encoding/json - gocyclo
- pkg: github.com/unknwon/com - gosec
desc: use gitea's util and replacements - staticcheck
- pkg: io/ioutil - unparam
desc: use os or io instead path: _test\.go
- pkg: golang.org/x/exp - linters:
desc: it's experimental and unreliable - dupl
- pkg: code.gitea.io/gitea/modules/git/internal - errcheck
desc: do not use the internal package, use AddXxx function instead - gocyclo
- pkg: gopkg.in/ini.v1 - gosec
desc: do not use the ini package, use gitea's config system instead path: models/migrations/v
- pkg: gitea.com/go-chi/cache - linters:
desc: do not use the go-chi cache package, use gitea's cache system - forbidigo
path: cmd
- linters:
- dupl
text: (?i)webhook
- linters:
- gocritic
text: (?i)`ID' should not be capitalized
- linters:
- deadcode
- unused
text: (?i)swagger
- linters:
- staticcheck
text: (?i)argument x is overwritten before first use
- linters:
- gocritic
text: '(?i)commentFormatting: put a space between `//` and comment text'
- linters:
- gocritic
text: '(?i)exitAfterDefer:'
paths:
- node_modules
- public
- web_src
- third_party$
- builtin$
- examples$
issues: issues:
max-issues-per-linter: 0 max-issues-per-linter: 0
max-same-issues: 0 max-same-issues: 0
exclude-dirs: [node_modules, public, web_src] formatters:
exclude-case-sensitive: true enable:
exclude-rules: - gofmt
- path: _test\.go - gofumpt
linters: settings:
- gocyclo gofumpt:
- errcheck extra-rules: true
- dupl exclusions:
- gosec generated: lax
- unparam paths:
- staticcheck - node_modules
- path: models/migrations/v - public
linters: - web_src
- gocyclo - third_party$
- errcheck - builtin$
- dupl - examples$
- gosec
- path: cmd run:
linters: timeout: 10m
- forbidigo
- text: "webhook"
linters:
- dupl
- text: "`ID' should not be capitalized"
linters:
- gocritic
- text: "swagger"
linters:
- unused
- deadcode
- text: "argument x is overwritten before first use"
linters:
- staticcheck
- text: "commentFormatting: put a space between `//` and comment text"
linters:
- gocritic
- text: "exitAfterDefer:"
linters:
- gocritic

2
.mailmap Normal file
View File

@ -0,0 +1,2 @@
Unknwon <u@gogs.io> <joe2010xtmf@163.com>
Unknwon <u@gogs.io> 无闻 <u@gogs.io>

View File

@ -4,6 +4,561 @@ This changelog goes through the changes that have been made in each release
without substantial changes to our git log; to see the highlights of what has without substantial changes to our git log; to see the highlights of what has
been added to each release, please refer to the [blog](https://blog.gitea.com). been added to each release, please refer to the [blog](https://blog.gitea.com).
## [1.23.6](https://github.com/go-gitea/gitea/releases/tag/v1.23.6) - 2025-03-24
* SECURITY
* Fix LFS URL (#33840) (#33843)
* Update jwt and redis packages (#33984) (#33987)
* Update golang crypto and net (#33989)
* BUGFIXES
* Drop timeout for requests made to the internal hook api (#33947) (#33970)
* Fix maven panic when no package exists (#33888) (#33889)
* Fix markdown render (#33870) (#33875)
* Fix auto concurrency cancellation skips commit status updates (#33764) (#33849)
* Fix oauth2 auth (#33961) (#33962)
* Fix incorrect 1.23 translations (#33932)
* Try to figure out attribute checker problem (#33901) (#33902)
* Ignore trivial errors when updating push data (#33864) (#33887)
* Fix some UI problems for 1.23 (#33856)
* Removing unwanted ui container (#33833) (#33835)
* Support disable passkey auth (#33348) (#33819)
* Do not call "git diff" when listing PRs (#33817)
* Try to fix ACME (3rd) (#33807) (#33808)
* Fix incorrect code search indexer options (#33992) #33999
## [1.23.5](https://github.com/go-gitea/gitea/releases/tag/v1.23.5) - 2025-03-04
* SECURITY
* Bump x/oauth2 & x/crypto (#33704) (#33727)
* PERFORMANCE
* Optimize user dashboard loading (#33686) (#33708)
* BUGFIXES
* Fix navbar dropdown item align (#33782)
* Fix inconsistent closed issue list icon (#33722) (#33728)
* Fix for Maven Package Naming Convention Handling (#33678) (#33679)
* Improve Open-with URL encoding (#33666) (#33680)
* Deleting repository should unlink all related packages (#33653) (#33673)
* Fix omitempty bug (#33663) (#33670)
* Upgrade go-crypto from 1.1.4 to 1.1.6 (#33745) (#33754)
* Fix OCI image.version annotation for releases to use full semver (#33698) (#33701)
* Try to fix ACME path when renew (#33668) (#33693)
* Fix mCaptcha bug (#33659) (#33661)
* Git graph: don't show detached commits (#33645) (#33650)
* Use MatchPhraseQuery for bleve code search (#33628)
* Adjust appearence of commit status webhook (#33778) #33789
* Upgrade golang net from 0.35.0 -> 0.36.0 (#33795) #33796
## [1.23.4](https://github.com/go-gitea/gitea/releases/tag/v1.23.4) - 2025-02-16
* SECURITY
* Enhance routers for the Actions variable operations (#33547) (#33553)
* Enhance routers for the Actions runner operations (#33549) (#33555)
* Fix project issues list and counting (#33594) #33619
* PERFORMANCES
* Performance optimization for pull request files loading comments attachments (#33585) (#33592)
* BUGFIXES
* Add a transaction to `pickTask` (#33543) (#33563)
* Fix mirror bug (#33597) (#33607)
* Use default Git timeout when checking repo health (#33593) (#33598)
* Fix PR's target branch dropdown (#33589) (#33591)
* Fix various problems (artifact order, api empty slice, assignee check, fuzzy prompt, mirror proxy, adopt git) (#33569) (#33577)
* Rework suggestion backend (#33538) (#33546)
* Fix context usage (#33554) (#33557)
* Only show the latest version in the Arch index (#33262) (#33580)
* Skip deletion error for action artifacts (#33476) (#33568)
* Make actions URL in commit status webhooks absolute (#33620) #33632
* Add missing locale (#33641) #33642
## [1.23.3](https://github.com/go-gitea/gitea/releases/tag/v1.23.3) - 2025-02-06
* Security
* Build Gitea with Golang v1.23.6 to fix security bugs
* BUGFIXES
* Fix a bug caused by status webhook template #33512
## [1.23.2](https://github.com/go-gitea/gitea/releases/tag/1.23.2) - 2025-02-04
* BREAKING
* Add tests for webhook and fix some webhook bugs (#33396) (#33442)
* Package webhooks Organization was incorrectly used as the User struct. This PR fixes the issue.
* This changelog is just a hint. The change is not really breaking because most fields are the same, most users are not affected.
* ENHANCEMENTS
* Clone button enhancements (#33362) (#33404)
* Repo homepage styling tweaks (#33289) (#33381)
* Add a confirm dialog for "sync fork" (#33270) (#33273)
* Make tracked time representation display as hours (#33315) (#33334)
* Improve sync fork behavior (#33319) (#33332)
* BUGFIXES
* Fix code button alignment (#33345) (#33351)
* Correct bot label `vertical-align` (#33477) (#33480)
* Fix SSH LFS memory usage (#33455) (#33460)
* Fix issue sidebar dropdown keyboard support (#33447) (#33450)
* Fix user avatar (#33439)
* Fix `GetCommitBranchStart` bug (#33298) (#33421)
* Add pubdate for repository rss and add some tests (#33411) (#33416)
* Add missed auto merge feed message on dashboard (#33309) (#33405)
* Fix issue suggestion bug (#33389) (#33391)
* Make issue suggestion work for all editors (#33340) (#33342)
* Fix issue count (#33338) (#33341)
* Fix Account linking page (#33325) (#33327)
* Fix closed dependency title (#33285) (#33287)
* Fix sidebar milestone link (#33269) (#33272)
* Fix missing license when sync mirror (#33255) (#33258)
* Fix upload file form (#33230) (#33233)
* Fix mirror bug (#33224) (#33225)
* Fix system admin cannot fork or get private fork with API (#33401) (#33417)
* Fix push message behavior (#33215) (#33317)
* Trivial fixes (#33304) (#33312)
* Fix "stop time tracking button" on navbar (#33084) (#33300)
* Fix tag route and empty repo (#33253)
* Fix cache test triggered by non memory cache (#33220) (#33221)
* Revert empty lfs ref name (#33454) (#33457)
* Fix flex width (#33414) (#33418)
* Fix commit status events (#33320) #33493
* Fix unnecessary comment when moving issue on the same project column (#33496) #33499
* Add timetzdata build tag to binary releases (#33463) #33503
* MISC
* Use ProtonMail/go-crypto to replace keybase/go-crypto (#33402) (#33410)
* Update katex to latest version (#33361)
* Update go tool dependencies (#32916) (#33355)
## [1.23.1](https://github.com/go-gitea/gitea/releases/tag/v1.23.1) - 2025-01-09
* ENHANCEMENTS
* Move repo size to sidebar (#33155) (#33182)
* BUGFIXES
* Use updated path to s6-svscan after alpine upgrade (#33185) (#33188)
* Fix fuzz test (#33156) (#33158)
* Fix raw file API ref handling (#33172) (#33189)
* Fix ACME panic (#33178) (#33186)
* Fix branch dropdown not display ref name (#33159) (#33183)
* Fix assignee list overlapping in Issue sidebar (#33176) (#33181)
* Fix sync fork for consistency (#33147) #33192
* Fix editor markdown not incrementing in a numbered list (#33187) #33193
## [1.23.0](https://github.com/go-gitea/gitea/releases/tag/v1.23.0) - 2025-01-08
* BREAKING
* Rename config option `[camo].Allways` to `[camo].Always` (#32097)
* Remove SHA1 for support for ssh rsa signing (#31857)
* Use UTC as default timezone when schedule Actions cron tasks (#31742)
* Delete Actions logs older than 1 year by default (#31735)
* Make OIDC introspection authentication strictly require Client ID and secret (#31632)
* SECURITY
* Include file extension checks in attachment API (#32151)
* Include all security fixes which have been backported to v1.22
* FEATURES
* Allow to fork repository into the same owner (#32819)
* Support "merge upstream branch" (Sync fork) (#32741)
* Add Arch package registry (#32692)
* Allow to disable the password-based login (sign-in) form (#32687)
* Allow cropping an avatar before setting it (#32565)
* Support quote selected comments to reply (#32431)
* Add reviewers selection to new pull request (#32403)
* Suggestions for issues (#32327)
* Add priority to protected branch (#32286)
* Included tag search capabilities (#32045)
* Add option to filter board cards by labels and assignees (#31999)
* Add automatic light/dark option for the colorblind theme (#31997)
* Support migration from AWS CodeCommit (#31981)
* Introduce globallock as distributed locks (#31908 & #31813)
* Support compression for Actions logs & enable by default (#31761 & #32013)
* Add pure SSH LFS support (#31516)
* Add Passkey login support (#31504)
* Actions support workflow dispatch event (#28163)
* Support repo license (#24872)
* Issue time estimate, meaningful time tracking (#23113)
* GitHub like repo home page (#32213 & #32847)
* Rearrange Clone Panel (#31142)
* Enhancing Gitea OAuth2 Provider with Granular Scopes for Resource Access (#32573)
* Use env GITEA_RUNNER_REGISTRATION_TOKEN as global runner token (#32946) #32964
* Update i18n.go - Language Picker (#32933) #32935
* PERFORMANCE
* Perf: add extra index to notification table (#32395)
* Introduce OrgList and add LoadTeams, optimaze Load teams for orgs (#32543)
* Improve performance of diffs (#32393)
* Make LFS http_client parallel within a batch. (#32369)
* Add new index for action to resolve the performance problem (#32333)
* Improve get feed with pagination (#31821)
* Performance improvements for pull request list API (#30490)
* Use batch database operations instead of one by one to optimze api pulls (#32680)
* Use gitrepo.GetTreePathLatestCommit to get file lastest commit instead from latest commit cache (#32987) #33046
* ENHANCEMENTS
* Code
* Remove unnecessary border in repo home page sidebar (#32767)
* Add 'Copy path' button to file view (#32584)
* Improve diff file tree (#32658)
* Add new [lfs_client].BATCH_SIZE and [server].LFS_MAX_BATCH_SIZE config settings. (#32307)
* Updated tokenizer to better matching when search for code snippets (#32261)
* Change the code search to sort results by relevance (#32134)
* Support migrating GitHub/GitLab PR draft status (#32242)
* Move lock icon position and add additional tooltips to branch list page (#31839)
* Add tag name in the commits list (#31082)
* Add `MAX_ROWS` option for CSV rendering (#30268)
* Allow code search by filename (#32210)
* Make git push options accept short name (#32245)
* Repo file list enhancements (#32835)
* Markdown & Editor
* Refactor markdown math render, add dollor-backquote syntax support (#32831)
* Make Monaco theme follow browser, fully type codeeditor.ts (#32756)
* Refactor markdown editor and use it for milestone description editor (#32688)
* Add some handy markdown editor features (#32400)
* Improve markdown textarea for indentation and lists (#31406)
* Issue
* Add label/author/assignee filters to the user/org home issue list (#32779)
* Refactor issue filter (labels, poster, assignee) (#32771)
* Style unification for the issue_management area (#32605)
* Add "View all branches/tags" entry to Branch Selector (#32653)
* Improve textarea paste (#31948)
* Add avif image file support (#32508)
* Prevent from submitting issue/comment on uploading (#32263)
* Issue Templates: add option to have dropdown printed list (#31577)
* Allow searching issues by ID (#31479)
* Add `is_archived` option for issue indexer (#32735)
* Improve attachment upload methods (#30513)
* Support issue template assignees (#31083)
* Prevent simultaneous editing of comments and issues (#31053)
* Add issue comment when moving issues from one column to another of the project (#29311)
* Pull Request
* Display head branch more comfortable on pull request view (#32000)
* Simplify review UI (#31062)
* Allow force push to protected branches (#28086)
* Add line-through for deleted branch on pull request view page (#32500)
* Support requested_reviewers data in comment webhook events (#26178)
* Allow maintainers to view and edit files of private repos when "Allow maintainers to edit" is enabled (#32215)
* Allow including `Reviewed-on`/`Reviewed-by` lines for custom merge messages (#31211)
* Actions
* Render job title as commit message (#32748)
* Refactor RepoActionView.vue, add `::group::` support (#32713)
* Make RepoActionView.vue support `##[group]` (#32770)
* Support `pull_request_target` event for commit status (#31703)
* Detect whether action view branch was deleted (#32764)
* Allow users with write permission to run actions (#32644)
* Show latest run when visit /run/latest (#31808)
* Packages
* Improve rubygems package registry (#31357)
* Add support for npm bundleDependencies (#30751)
* Add signature support for the RPM module (#27069)
* Extract and display readme and comments for Composer packages (#30927)
* Project
* Add title to project view page (#32747)
* Set the columns height to hug all its contents (#31726)
* Rename project `board` -> `column` to make the UI less confusing (#30170)
* User & Organazition
* Use better name for userinfo structure (#32544)
* Use user.FullName in Oauth2 id_token response (#32542)
* Limit org member view of restricted users (#32211)
* Allow disabling authentication related user features (#31535)
* Add option to change mail from user display name (#31528)
* Use FullName in Emails to address the recipient if possible (#31527)
* Administration
* Add support for a credentials chain for minio access (#31051)
* Move admin routers from /admin to /-/admin (#32189)
* Add cache test for admins (#31265)
* Add option for mailer to override mail headers (#27860)
* Azure blob storage support (#30995)
* Supports forced use of S3 virtual-hosted style (#30969)
* Move repository visibility to danger zone in the settings area (#31126)
* Others
* Remove urls from translations (#31950)
* Simplify 404/500 page (#31409)
* Optimize installation-page experience (#32558)
* Refactor login page (#31530)
* Add new event commit status creation and webhook implementation (#27151)
* Repo Activity: count new issues that were closed (#31776)
* Set manual `tabindex`es on login page (#31689)
* Add `YEAR`, `MONTH`, `MONTH_ENGLISH`, `DAY` variables for template repos (#31584)
* Add typescript guideline and typescript-specific eslint plugins and fix issues (#31521)
* Make toast support preventDuplicates (#31501)
* Fix tautological conditions (#30735)
* Issue change title notifications (#33050) #33065
* API
* Implement update branch API (#32433)
* Fix missing outputs for jobs with matrix (#32823)
* Make API "compare" accept commit IDs (#32801)
* Add github compatible tarball download API endpoints (#32572)
* Harden runner updateTask and updateLog api (#32462)
* Add `DISABLE_ORGANIZATIONS_PAGE` and `DISABLE_CODE_PAGE` settings for explore pages and fix an issue related to user search (#32288)
* Make admins adhere to branch protection rules (#32248)
* Calculate `PublicOnly` for org membership only once (#32234)
* Allow filtering PRs by poster in the ListPullRequests API (#32209)
* Return 404 instead of error when commit not exist (#31977)
* Save initial signup information for users to aid in spam prevention (#31852)
* Fix upload maven pacakge parallelly (#31851)
* Fix null requested_reviewer from API (#31773)
* Add permission description for API to add repo collaborator (#31744)
* Add return type to GetRawFileOrLFS and GetRawFile (#31680)
* Add skip secondary authorization option for public oauth2 clients (#31454)
* Add tag protection via rest api #17862 (#31295)
* Document possible action types for the user activity feed API (#31196)
* Add topics for repository API (#31127)
* Add support for searching users by email (#30908)
* Add API endpoints for getting action jobs status (#26673)
* REFACTOR
* Update JS and PY dependencies (#31940)
* Enable `no-jquery/no-parse-html-literal` and fix violation (#31684)
* Refactor image diff (#31444)
* Refactor CSRF token (#32216)
* Fix some typescript issues (#32586)
* Refactor names (#31405)
* Use per package global lock for container uploads instead of memory lock (#31860)
* Move team related functions to service layer (#32537)
* Move GetFeeds to service layer (#32526)
* Resolve lint for unused parameter and unnecessary type arguments (#30750)
* Reimplement GetUserOrgsList to make it simple and clear (#32486)
* Move some functions from issue.go to standalone files (#32468)
* Refactor sidebar assignee&milestone&project selectors (#32465)
* Refactor sidebar label selector (#32460)
* Fix a number of typescript issues (#32459)
* Refactor language menu and dom utils (#32450)
* Refactor issue page info (#32445)
* Split issue sidebar into small templates (#32444)
* Refactor template ctx and render utils (#32422)
* Refactor repo legacy (#32404)
* Refactor markup package (#32399)
* Refactor markup render system (#32533 & #32589 & #32612)
* Refactor the DB migration system slightly (#32344)
* Remove jQuery import from some files (#32512)
* Strict pagination check (#32548)
* Split mail sender sub package from mailer service package (#32618)
* Remove outdated code about fixture generation (#32708)
* Refactor RepoBranchTagSelector (#32681)
* Refactor issue list (#32755)
* Refactor LabelEdit (#32752)
* Split issue/pull view router function as multiple smaller functions (#32749)
* Refactor some LDAP code (#32849)
* Unify repo search order by logic (#30876)
* Remove duplicate empty repo check in delete branch API (#32569)
* Replace deprecated `math/rand` functions (#30733)
* Remove fomantic dimmer module (#30723)
* Add types to fetch,toast,bootstrap,svg (#31627)
* Refactor webhook (#31587)
* Move AddCollabrator and CreateRepositoryByExample to service layer (#32419)
* Refactor RepoRefByType (#32413)
* Refactor: remove redundant err declarations (#32381)
* Refactor markup code (#31399)
* Refactor render system (orgmode) (#32671)
* Refactor render system (#32492)
* Refactor markdown render (#32736 & #32728)
* Refactor repo unit "disabled" check (#31389)
* Refactor route path normalization (#31381)
* Refactor to use UnsafeStringToBytes (#31358)
* Migrate vue components to setup (#32329)
* Refactor globallock (#31933)
* Use correct function name (#31887)
* Use a common message template instead of a special one (#31878)
* Fix a number of Typescript issues (#31877)
* Refactor dropzone (#31482)
* Move custom `tw-` helpers to tailwind plugin (#31184)
* Replace `gt-word-break` with `tw-break-anywhere` (#31183)
* Drop `IDOrderDesc` for listing Actions task and always order by `id DESC` (#31150)
* Split common-global.js into separate files (#31438)
* Improve detecting empty files (#31332)
* Use `querySelector` over alternative DOM methods (#31280)
* Remove jQuery `.text()` (#30506)
* Use repo as of renderctx's member rather than a repoPath on metas (#29222)
* Refactor some frontend problems (#32646)
* Refactor DateUtils and merge TimeSince (#32409)
* Replace DateTime with proper functions (#32402)
* Replace DateTime with DateUtils (#32383)
* Convert frontend code to typescript (#31559)
* Refactor maven package registry (#33049) #33057
* Refactor testfixtures #33028
* BUGFIXES
* Fix issues with inconsistent spacing in areas (#32607)
* Fix incomplete Actions status aggregations (#32859)
* In some lfs server implementations, they require the ref attribute. (#32838)
* Update the list of watchers and stargazers when clicking watch/unwatch or star/unstar (#32570)
* Fix `recentupdate` sorting bugs (#32505)
* Fix incorrect "Target branch does not exist" in PR title (#32222)
* Handle "close" actionable references for manual merges (#31879)
* render plain text file if the LFS object doesn't exist (#31812)
* Fix Null Pointer error for CommitStatusesHideActionsURL (#31731)
* Fix loadRepository error when access user dashboard (#31719)
* Hide the "Details" link of commit status when the user cannot access actions (#30156)
* Fix duplicate dropdown dividers (#32760)
* Fix SSPI button visibility when SSPI is the only enabled method (#32841)
* Fix overflow on org header (#32837)
* Exclude protected branches from recently pushed (#31748)
* Fix large image overflow in comment page (#31740)
* Fix milestone deadline and date related problems (#32339)
* Fix markdown preview $$ support (#31514)
* Fix a compilation error in the Gitpod environment (#32559)
* Fix PR diff review form submit (#32596)
* Fix a number of typescript issues (#32308)
* Fix some function names in comment (#32300)
* Fix absolute-date (#32375)
* Clarify Actions resources ownership (#31724)
* Try to fix ACME directory problem (#33072) #33077
* Inherit submodules from template repository content (#16237) #33068
* Use project's redirect url instead of composing url (#33058) #33064
* Fix toggle commit body button ui when latest commit message is long (#32997) #33034
* Fix package error handling and npm meta and empty repo guide #33112
* Fix empty git repo handling logic and fix mobile view (#33101) #33102
* Fix line-number and scroll bugs (#33094) #33095
* Fix bleve fuzziness search (#33078) #33087
* Fix broken forms #33082
* Fix empty repo updated time (#33120) #33124
* Add missing transaction when set merge #33113
* Fix issue comment number (#30556) #33055
* Fix duplicate co-author in squashed merge commit messages (#33020) #33054
* Fix Agit pull request permission check (#32999) #33005
* Fix scoped label ui when contains emoji (#33007) #33014
* Fix bug on activities (#33008) #33016
* Fix review code comment avatar alignment (#33031) #33032
* Fix templating in pull request comparison (#33025) #33038
* Fix bug automerge cannot be chosed when there is only 1 merge style (#33040) #33043
* Fix settings not being loaded at CLI (#26402) #33048
* Support for email addresses containing uppercase characters when activating user account (#32998) #33001
* Support org labels when adding labels by label names (#32988) #32996
* Do not render truncated links in markdown (#32980) #32983
* Demilestone should not include milestone (#32923) #32979
* Fix Azure blob object Seek (#32974) #32975
* Fix maven pom inheritance (#32943) #32976
* Fix textarea newline handle (#32966) #32977
* Fix outdated tmpl code (#32953) #32961
* Fix commit range paging (#32944) #32962
* Fix repo avatar conflict (#32958) #32960
* Fix trailing comma not matched in the case of alphanumeric issue (#32945)
* Relax the version checking for Arch packages (#32908) #32913
* Add more load functions to make sure the reference object loaded (#32901) #32912
* Filter reviews of one pull request in memory instead of database to reduce slow response because of lacking database index (#33106) #33128
* Fix git remote error check, fix dependencies, fix js error (#33129) #33133
* MISC
* Optimize branch protection rule loading (#32280)
* Bump to go 1.23 (#31855)
* Remove unused call to $.HeadRepo in view_title template (#32317)
* Do not display `attestation-manifest` and use short sha256 instead of full sha256 (#32851)
* Upgrade htmx to 2.0.4 (#32834)
* Improve JSX/TSX support in code editor (#32833)
* Add User-Agent for gitea's self-implemented lfs client. (#32832)
* Use errors.New to replace fmt.Errorf with no parameters (#32800)
* Add "n commits" link to contributors in contributors graph page (#32799)
* Update dependencies, tweak eslint (#32719)
* Remove all "floated" CSS styles (#32691)
* Show tag name on branch/tag selector if repo shown from tag ref (#32689)
* Use new mail package instead of an unmintained one (#32682)
* Optimize the styling of icon buttons within file-header-right (#32675)
* Validate OAuth Redirect URIs (#32643)
* Support optional/configurable IAMEndpoint for Minio Client (#32581) (#32581)
* Make search box in issue sidebar dropdown list always show when scrolling (#32576)
* Bump CI,Flake and Snap to Node 22 (#32487)
* Update `github.com/meilisearch/meilisearch-go` (#32484)
* Add `DEFAULT_MIRROR_REPO_UNITS` and `DEFAULT_TEMPLATE_REPO_UNITS` options (#32416)
* Update go dependencies (#32389)
* Update JS and PY dependencies (#32388)
* Upgrade rollup to 4.24.0 (#32312)
* Upgrade vue to 3.5.12 (#32311)
* Improve the maintainblity of the reserved username list (#32229)
* Upgrade htmx to 2.0.3 (#32192)
* Count typescript files as frontend for labeling (#32088)
* Only use Host header from reverse proxy (#32060)
* Failed authentications are logged to level Warning (#32016)
* Enhance USER_DISABLED_FEATURES to allow disabling change username or full name (#31959)
* Distinguish official vs non-official reviews, add tool tips, and upgr… (#31924)
* Update mermaid to v11 (#31913)
* Bump relative-time-element to v4.4.3 (#31910)
* Upgrade `htmx` to `2.0.2` (#31847)
* Add warning message in merge instructions when `AutodetectManualMerge` was not enabled (#31805)
* Add types to various low-level functions (#31781)
* Update JS dependencies (#31766)
* Remove unused code from models/repos/release.go (#31756)
* Support delete user email in admin panel (#31690)
* Add `username` to OIDC introspection response (#31688)
* Use GetDisplayName() instead of DisplayName() to generate rss feeds (#31687)
* Code editor theme enhancements (#31629)
* Update JS dependencies (#31616)
* Add types for js globals (#31586)
* Add back esbuild-loader for .js files (#31585)
* Don't show hidden labels when filling out an issue template (#31576)
* Allow synchronizing user status from OAuth2 login providers (#31572)
* Display app name in the registration email title (#31562)
* Use stable version of fabric (#31526)
* Support legacy _links LFS batch responses (#31513)
* Fix JS error with disabled attachment and easymde (#31511)
* Always use HTML attributes for avatar size (#31509)
* Use nolyfill to remove some polyfills (#31468)
* Disable issue/PR comment button given empty input (#31463)
* Add simple JS init performance trace (#31459)
* Bump htmx to 2.0.0 (#31413)
* Update JS dependencies, remove `eslint-plugin-jquery` (#31402)
* Split org Propfile README to a new tab `overview` (#31373)
* Update nix flake and add gofumpt (#31320)
* Code optimization (#31315)
* Enable poetry non-package mode (#31282)
* Optimize profile layout to enhance visual experience (#31278)
* Update `golang.org/x/net` (#31260)
* Bump `@github/relative-time-element` to v4.4.1 (#31232)
* Remove unnecessary inline style for tab-size (#31224)
* Update golangci-lint to v1.59.0 (#31221)
* Update chroma to v2.14.0 (#31177)
* Update JS dependencies (#31120)
* Improve the handling of `jobs.<job_id>.if` (#31070)
* Clean up revive linter config, tweak golangci output (#30980)
* Use CSS `inset` shorthand (#30939)
* Forbid deprecated `break-word` in CSS (#30934)
* Remove obsolete monaco workaround (#30893)
* Update JS dependencies, add new eslint rules (#30840)
* Fix body margin shifting with modals, fix error on project column edit (#30831)
* Remove disk-clean workflow (#30741)
* Bump `github.com/google/go-github` to v61 (#30738)
* Add built js files to eslint ignore (#30737)
* Use `ProtonMail/go-crypto` for `opengpg` in tests (#30736)
* Upgrade xorm to v1.3.9 and improve some migrations Sync (#29899)
* Added default sorting milestones by name (#27084)
* Enable `unparam` linter (#31277)
* Use Alpine 3.21 for the docker images (#32924) #32951
* Bump x/net (#32896) #32899
* Use -s -w ldflags for release artifacts (#33041) #33042
* Remove aws go sdk package dependency (#33029) #33047
## [1.22.6](https://github.com/go-gitea/gitea/releases/tag/v1.22.6) - 2024-12-12
* SECURITY
* Fix misuse of PublicKeyCallback(#32810)
* BUGFIXES
* Fix lfs migration (#32812) (#32818)
* Add missing two sync feed for refs/pull (#32815)
* TESTING
* Avoid MacOS keychain dialog in integration tests (#32813) (#32816)
## [1.22.5](https://github.com/go-gitea/gitea/releases/tag/v1.22.5) - 2024-12-11
* SECURITY
* Upgrade crypto library (#32791)
* Fix delete branch perm checking (#32654) (#32707)
* BUGFIXES
* Add standard-compliant route to serve outdated R packages (#32783) (#32789)
* Fix internal server error when updating labels without write permission (#32776) (#32785)
* Add Swift login endpoint (#32693) (#32701)
* Fix fork page branch selection (#32711) (#32725)
* Fix word overflow in file search page (#32695) (#32699)
* Fix gogit `GetRefCommitID` (#32705) (#32712)
* Fix race condition in mermaid observer (#32599) (#32673)
* Fixe a keystring misuse and refactor duplicates keystrings (#32668) (#32792)
* Bump relative-time-element to v4.4.4 (#32739)
* PERFORMANCE
* Make wiki pages visit fast (#32732) (#32745)
* MISC
* Don't create action when syncing mirror pull refs (#32659) (#32664)
## [1.22.4](https://github.com/go-gitea/gitea/releases/tag/v1.22.4) - 2024-11-14 ## [1.22.4](https://github.com/go-gitea/gitea/releases/tag/v1.22.4) - 2024-11-14
* SECURITY * SECURITY

View File

@ -182,7 +182,7 @@ Here's how to run the test suite:
## Translation ## Translation
All translation work happens on [Crowdin](https://crowdin.com/project/gitea). All translation work happens on [Crowdin](https://translate.gitea.com).
The only translation that is maintained in this repository is [the English translation](https://github.com/go-gitea/gitea/blob/main/options/locale/locale_en-US.ini). The only translation that is maintained in this repository is [the English translation](https://github.com/go-gitea/gitea/blob/main/options/locale/locale_en-US.ini).
It is synced regularly with Crowdin. \ It is synced regularly with Crowdin. \
Other locales on main branch **should not** be updated manually as they will be overwritten with each sync. \ Other locales on main branch **should not** be updated manually as they will be overwritten with each sync. \

View File

@ -1,5 +1,5 @@
# Build stage # Build stage
FROM docker.io/library/golang:1.23-alpine3.20 AS build-env FROM docker.io/library/golang:1.24-alpine3.21 AS build-env
ARG GOPROXY ARG GOPROXY
ENV GOPROXY=${GOPROXY:-direct} ENV GOPROXY=${GOPROXY:-direct}
@ -41,7 +41,7 @@ RUN chmod 755 /tmp/local/usr/bin/entrypoint \
/go/src/code.gitea.io/gitea/environment-to-ini /go/src/code.gitea.io/gitea/environment-to-ini
RUN chmod 644 /go/src/code.gitea.io/gitea/contrib/autocompletion/bash_autocomplete RUN chmod 644 /go/src/code.gitea.io/gitea/contrib/autocompletion/bash_autocomplete
FROM docker.io/library/alpine:3.20 FROM docker.io/library/alpine:3.21
LABEL maintainer="maintainers@gitea.io" LABEL maintainer="maintainers@gitea.io"
EXPOSE 22 3000 EXPOSE 22 3000
@ -78,7 +78,7 @@ ENV GITEA_CUSTOM=/data/gitea
VOLUME ["/data"] VOLUME ["/data"]
ENTRYPOINT ["/usr/bin/entrypoint"] ENTRYPOINT ["/usr/bin/entrypoint"]
CMD ["/bin/s6-svscan", "/etc/s6"] CMD ["/usr/bin/s6-svscan", "/etc/s6"]
COPY --from=build-env /tmp/local / COPY --from=build-env /tmp/local /
COPY --from=build-env /go/src/code.gitea.io/gitea/gitea /app/gitea/gitea COPY --from=build-env /go/src/code.gitea.io/gitea/gitea /app/gitea/gitea

View File

@ -1,5 +1,5 @@
# Build stage # Build stage
FROM docker.io/library/golang:1.23-alpine3.20 AS build-env FROM docker.io/library/golang:1.24-alpine3.21 AS build-env
ARG GOPROXY ARG GOPROXY
ENV GOPROXY=${GOPROXY:-direct} ENV GOPROXY=${GOPROXY:-direct}
@ -39,7 +39,7 @@ RUN chmod 755 /tmp/local/usr/local/bin/docker-entrypoint.sh \
/go/src/code.gitea.io/gitea/environment-to-ini /go/src/code.gitea.io/gitea/environment-to-ini
RUN chmod 644 /go/src/code.gitea.io/gitea/contrib/autocompletion/bash_autocomplete RUN chmod 644 /go/src/code.gitea.io/gitea/contrib/autocompletion/bash_autocomplete
FROM docker.io/library/alpine:3.20 FROM docker.io/library/alpine:3.21
LABEL maintainer="maintainers@gitea.io" LABEL maintainer="maintainers@gitea.io"
EXPOSE 2222 3000 EXPOSE 2222 3000

View File

@ -31,7 +31,6 @@ Gary Kim <gary@garykim.dev> (@gary-kim)
Guillermo Prandi <gitea.maint@mailfilter.com.ar> (@guillep2k) Guillermo Prandi <gitea.maint@mailfilter.com.ar> (@guillep2k)
Mura Li <typeless@ctli.io> (@typeless) Mura Li <typeless@ctli.io> (@typeless)
6543 <6543@obermui.de> (@6543) 6543 <6543@obermui.de> (@6543)
jaqra <jaqra@hotmail.com> (@jaqra)
David Svantesson <davidsvantesson@gmail.com> (@davidsvantesson) David Svantesson <davidsvantesson@gmail.com> (@davidsvantesson)
a1012112796 <1012112796@qq.com> (@a1012112796) a1012112796 <1012112796@qq.com> (@a1012112796)
Karl Heinz Marbaise <kama@soebes.de> (@khmarbaise) Karl Heinz Marbaise <kama@soebes.de> (@khmarbaise)
@ -63,3 +62,5 @@ Yu Liu <1240335630@qq.com> (@HEREYUA)
Kemal Zebari <kemalzebra@gmail.com> (@kemzeb) Kemal Zebari <kemalzebra@gmail.com> (@kemzeb)
Rowan Bohde <rowan.bohde@gmail.com> (@bohde) Rowan Bohde <rowan.bohde@gmail.com> (@bohde)
hiifong <i@hiif.ong> (@hiifong) hiifong <i@hiif.ong> (@hiifong)
metiftikci <metiftikci@hotmail.com> (@metiftikci)
Christopher Homberger <christopher.homberger@web.de> (@ChristopherHX)

263
Makefile
View File

@ -23,20 +23,20 @@ SHASUM ?= shasum -a 256
HAS_GO := $(shell hash $(GO) > /dev/null 2>&1 && echo yes) HAS_GO := $(shell hash $(GO) > /dev/null 2>&1 && echo yes)
COMMA := , COMMA := ,
XGO_VERSION := go-1.23.x XGO_VERSION := go-1.24.x
AIR_PACKAGE ?= github.com/air-verse/air@v1 AIR_PACKAGE ?= github.com/air-verse/air@v1
EDITORCONFIG_CHECKER_PACKAGE ?= github.com/editorconfig-checker/editorconfig-checker/cmd/editorconfig-checker@2.7.0 EDITORCONFIG_CHECKER_PACKAGE ?= github.com/editorconfig-checker/editorconfig-checker/v3/cmd/editorconfig-checker@v3.2.1
GOFUMPT_PACKAGE ?= mvdan.cc/gofumpt@v0.7.0 GOFUMPT_PACKAGE ?= mvdan.cc/gofumpt@v0.7.0
GOLANGCI_LINT_PACKAGE ?= github.com/golangci/golangci-lint/cmd/golangci-lint@v1.62.2 GOLANGCI_LINT_PACKAGE ?= github.com/golangci/golangci-lint/v2/cmd/golangci-lint@v2.0.2
GXZ_PACKAGE ?= github.com/ulikunitz/xz/cmd/gxz@v0.5.11 GXZ_PACKAGE ?= github.com/ulikunitz/xz/cmd/gxz@v0.5.12
MISSPELL_PACKAGE ?= github.com/golangci/misspell/cmd/misspell@v0.5.1 MISSPELL_PACKAGE ?= github.com/golangci/misspell/cmd/misspell@v0.6.0
SWAGGER_PACKAGE ?= github.com/go-swagger/go-swagger/cmd/swagger@v0.31.0 SWAGGER_PACKAGE ?= github.com/go-swagger/go-swagger/cmd/swagger@v0.31.0
XGO_PACKAGE ?= src.techknowlogick.com/xgo@latest XGO_PACKAGE ?= src.techknowlogick.com/xgo@latest
GO_LICENSES_PACKAGE ?= github.com/google/go-licenses@v1 GO_LICENSES_PACKAGE ?= github.com/google/go-licenses@v1
GOVULNCHECK_PACKAGE ?= golang.org/x/vuln/cmd/govulncheck@v1 GOVULNCHECK_PACKAGE ?= golang.org/x/vuln/cmd/govulncheck@v1
ACTIONLINT_PACKAGE ?= github.com/rhysd/actionlint/cmd/actionlint@v1 ACTIONLINT_PACKAGE ?= github.com/rhysd/actionlint/cmd/actionlint@v1
GOPLS_PACKAGE ?= golang.org/x/tools/gopls@v0.15.3 GOPLS_PACKAGE ?= golang.org/x/tools/gopls@v0.17.1
DOCKER_IMAGE ?= gitea/gitea DOCKER_IMAGE ?= gitea/gitea
DOCKER_TAG ?= latest DOCKER_TAG ?= latest
@ -73,6 +73,7 @@ EXTRA_GOFLAGS ?=
MAKE_VERSION := $(shell "$(MAKE)" -v | cat | head -n 1) MAKE_VERSION := $(shell "$(MAKE)" -v | cat | head -n 1)
MAKE_EVIDENCE_DIR := .make_evidence MAKE_EVIDENCE_DIR := .make_evidence
GOTESTFLAGS ?=
ifeq ($(RACE_ENABLED),true) ifeq ($(RACE_ENABLED),true)
GOFLAGS += -race GOFLAGS += -race
GOTESTFLAGS += -race GOTESTFLAGS += -race
@ -109,13 +110,11 @@ endif
LDFLAGS := $(LDFLAGS) -X "main.MakeVersion=$(MAKE_VERSION)" -X "main.Version=$(GITEA_VERSION)" -X "main.Tags=$(TAGS)" LDFLAGS := $(LDFLAGS) -X "main.MakeVersion=$(MAKE_VERSION)" -X "main.Version=$(GITEA_VERSION)" -X "main.Tags=$(TAGS)"
LINUX_ARCHS ?= linux/amd64,linux/386,linux/arm-5,linux/arm-6,linux/arm64 LINUX_ARCHS ?= linux/amd64,linux/386,linux/arm-5,linux/arm-6,linux/arm64,linux/riscv64
GO_TEST_PACKAGES ?= $(filter-out $(shell $(GO) list code.gitea.io/gitea/models/migrations/...) code.gitea.io/gitea/tests/integration/migration-test code.gitea.io/gitea/tests code.gitea.io/gitea/tests/integration code.gitea.io/gitea/tests/e2e,$(shell $(GO) list ./... | grep -v /vendor/)) GO_TEST_PACKAGES ?= $(filter-out $(shell $(GO) list code.gitea.io/gitea/models/migrations/...) code.gitea.io/gitea/tests/integration/migration-test code.gitea.io/gitea/tests code.gitea.io/gitea/tests/integration code.gitea.io/gitea/tests/e2e,$(shell $(GO) list ./... | grep -v /vendor/))
MIGRATE_TEST_PACKAGES ?= $(shell $(GO) list code.gitea.io/gitea/models/migrations/...) MIGRATE_TEST_PACKAGES ?= $(shell $(GO) list code.gitea.io/gitea/models/migrations/...)
FOMANTIC_WORK_DIR := web_src/fomantic
WEBPACK_SOURCES := $(shell find web_src/js web_src/css -type f) WEBPACK_SOURCES := $(shell find web_src/js web_src/css -type f)
WEBPACK_CONFIGS := webpack.config.js tailwind.config.js WEBPACK_CONFIGS := webpack.config.js tailwind.config.js
WEBPACK_DEST := public/assets/js/index.js public/assets/css/index.css WEBPACK_DEST := public/assets/js/index.js public/assets/css/index.css
@ -139,14 +138,14 @@ TAGS_EVIDENCE := $(MAKE_EVIDENCE_DIR)/tags
TEST_TAGS ?= $(TAGS_SPLIT) sqlite sqlite_unlock_notify TEST_TAGS ?= $(TAGS_SPLIT) sqlite sqlite_unlock_notify
TAR_EXCLUDES := .git data indexers queues log node_modules $(EXECUTABLE) $(FOMANTIC_WORK_DIR)/node_modules $(DIST) $(MAKE_EVIDENCE_DIR) $(AIR_TMP_DIR) $(GO_LICENSE_TMP_DIR) TAR_EXCLUDES := .git data indexers queues log node_modules $(EXECUTABLE) $(DIST) $(MAKE_EVIDENCE_DIR) $(AIR_TMP_DIR) $(GO_LICENSE_TMP_DIR)
GO_DIRS := build cmd models modules routers services tests GO_DIRS := build cmd models modules routers services tests
WEB_DIRS := web_src/js web_src/css WEB_DIRS := web_src/js web_src/css
ESLINT_FILES := web_src/js tools *.js *.ts tests/e2e ESLINT_FILES := web_src/js tools *.js *.ts *.cjs tests/e2e
STYLELINT_FILES := web_src/css web_src/js/components/*.vue STYLELINT_FILES := web_src/css web_src/js/components/*.vue
SPELLCHECK_FILES := $(GO_DIRS) $(WEB_DIRS) templates options/locale/locale_en-US.ini .github $(filter-out CHANGELOG.md, $(wildcard *.go *.js *.md *.yml *.yaml *.toml)) SPELLCHECK_FILES := $(GO_DIRS) $(WEB_DIRS) templates options/locale/locale_en-US.ini .github $(filter-out CHANGELOG.md, $(wildcard *.go *.js *.md *.yml *.yaml *.toml)) $(filter-out tools/misspellings.csv, $(wildcard tools/*))
EDITORCONFIG_FILES := templates .github/workflows options/locale/locale_en-US.ini EDITORCONFIG_FILES := templates .github/workflows options/locale/locale_en-US.ini
GO_SOURCES := $(wildcard *.go) GO_SOURCES := $(wildcard *.go)
@ -165,10 +164,8 @@ ifdef DEPS_PLAYWRIGHT
endif endif
SWAGGER_SPEC := templates/swagger/v1_json.tmpl SWAGGER_SPEC := templates/swagger/v1_json.tmpl
SWAGGER_SPEC_S_TMPL := s|"basePath": *"/api/v1"|"basePath": "{{AppSubUrl \| JSEscape}}/api/v1"|g SWAGGER_SPEC_INPUT := templates/swagger/v1_input.json
SWAGGER_SPEC_S_JSON := s|"basePath": *"{{AppSubUrl \| JSEscape}}/api/v1"|"basePath": "/api/v1"|g
SWAGGER_EXCLUDE := code.gitea.io/sdk SWAGGER_EXCLUDE := code.gitea.io/sdk
SWAGGER_NEWLINE_COMMAND := -e '$$a\'
TEST_MYSQL_HOST ?= mysql:3306 TEST_MYSQL_HOST ?= mysql:3306
TEST_MYSQL_DBNAME ?= testgitea TEST_MYSQL_DBNAME ?= testgitea
@ -189,67 +186,11 @@ TEST_MSSQL_PASSWORD ?= MwantsaSecurePassword1
all: build all: build
.PHONY: help .PHONY: help
help: help: Makefile ## print Makefile help information.
@echo "Make Routines:" @awk 'BEGIN {FS = ":.*##"; printf "\nUsage:\n make \033[36m[TARGETS] default target: build\033[0m\n\n\033[35mTargets:\033[0m\n"} /^[0-9A-Za-z._-]+:.*?##/ { printf " \033[36m%-45s\033[0m %s\n", $$1, $$2 }' Makefile #$(MAKEFILE_LIST)
@echo " - \"\" equivalent to \"build\"" @printf " \033[36m%-46s\033[0m %s\n" "test-e2e[#TestSpecificName]" "test end to end using playwright"
@echo " - build build everything" @printf " \033[36m%-46s\033[0m %s\n" "test[#TestSpecificName]" "run unit test"
@echo " - frontend build frontend files" @printf " \033[36m%-46s\033[0m %s\n" "test-sqlite[#TestSpecificName]" "run integration test for sqlite"
@echo " - backend build backend files"
@echo " - watch watch everything and continuously rebuild"
@echo " - watch-frontend watch frontend files and continuously rebuild"
@echo " - watch-backend watch backend files and continuously rebuild"
@echo " - clean delete backend and integration files"
@echo " - clean-all delete backend, frontend and integration files"
@echo " - deps install dependencies"
@echo " - deps-frontend install frontend dependencies"
@echo " - deps-backend install backend dependencies"
@echo " - deps-tools install tool dependencies"
@echo " - deps-py install python dependencies"
@echo " - lint lint everything"
@echo " - lint-fix lint everything and fix issues"
@echo " - lint-actions lint action workflow files"
@echo " - lint-frontend lint frontend files"
@echo " - lint-frontend-fix lint frontend files and fix issues"
@echo " - lint-backend lint backend files"
@echo " - lint-backend-fix lint backend files and fix issues"
@echo " - lint-go lint go files"
@echo " - lint-go-fix lint go files and fix issues"
@echo " - lint-go-vet lint go files with vet"
@echo " - lint-go-gopls lint go files with gopls"
@echo " - lint-js lint js files"
@echo " - lint-js-fix lint js files and fix issues"
@echo " - lint-css lint css files"
@echo " - lint-css-fix lint css files and fix issues"
@echo " - lint-md lint markdown files"
@echo " - lint-swagger lint swagger files"
@echo " - lint-templates lint template files"
@echo " - lint-yaml lint yaml files"
@echo " - lint-spell lint spelling"
@echo " - lint-spell-fix lint spelling and fix issues"
@echo " - checks run various consistency checks"
@echo " - checks-frontend check frontend files"
@echo " - checks-backend check backend files"
@echo " - test test everything"
@echo " - test-frontend test frontend files"
@echo " - test-backend test backend files"
@echo " - test-e2e[\#TestSpecificName] test end to end using playwright"
@echo " - update update js and py dependencies"
@echo " - update-js update js dependencies"
@echo " - update-py update py dependencies"
@echo " - webpack build webpack files"
@echo " - svg build svg files"
@echo " - fomantic build fomantic files"
@echo " - generate run \"go generate\""
@echo " - fmt format the Go code"
@echo " - generate-license update license files"
@echo " - generate-gitignore update gitignore files"
@echo " - generate-manpage generate manpage"
@echo " - generate-swagger generate the swagger spec from code comments"
@echo " - swagger-validate check if the swagger spec is valid"
@echo " - go-licenses regenerate go licenses"
@echo " - tidy run go mod tidy"
@echo " - test[\#TestSpecificName] run unit test"
@echo " - test-sqlite[\#TestSpecificName] run integration test for sqlite"
.PHONY: go-check .PHONY: go-check
go-check: go-check:
@ -280,11 +221,11 @@ node-check:
fi fi
.PHONY: clean-all .PHONY: clean-all
clean-all: clean clean-all: clean ## delete backend, frontend and integration files
rm -rf $(WEBPACK_DEST_ENTRIES) node_modules rm -rf $(WEBPACK_DEST_ENTRIES) node_modules
.PHONY: clean .PHONY: clean
clean: clean: ## delete backend and integration files
rm -rf $(EXECUTABLE) $(DIST) $(BINDATA_DEST) $(BINDATA_HASH) \ rm -rf $(EXECUTABLE) $(DIST) $(BINDATA_DEST) $(BINDATA_HASH) \
integrations*.test \ integrations*.test \
e2e*.test \ e2e*.test \
@ -296,7 +237,7 @@ clean:
tests/e2e/reports/ tests/e2e/test-artifacts/ tests/e2e/test-snapshots/ tests/e2e/reports/ tests/e2e/test-artifacts/ tests/e2e/test-snapshots/
.PHONY: fmt .PHONY: fmt
fmt: fmt: ## format the Go code
@GOFUMPT_PACKAGE=$(GOFUMPT_PACKAGE) $(GO) run build/code-batch-process.go gitea-fmt -w '{file-list}' @GOFUMPT_PACKAGE=$(GOFUMPT_PACKAGE) $(GO) run build/code-batch-process.go gitea-fmt -w '{file-list}'
$(eval TEMPLATES := $(shell find templates -type f -name '*.tmpl')) $(eval TEMPLATES := $(shell find templates -type f -name '*.tmpl'))
@# strip whitespace after '{{' or '(' and before '}}' or ')' unless there is only @# strip whitespace after '{{' or '(' and before '}}' or ')' unless there is only
@ -311,7 +252,7 @@ fmt-check: fmt
@diff=$$(git diff --color=always $(GO_SOURCES) templates $(WEB_DIRS)); \ @diff=$$(git diff --color=always $(GO_SOURCES) templates $(WEB_DIRS)); \
if [ -n "$$diff" ]; then \ if [ -n "$$diff" ]; then \
echo "Please run 'make fmt' and commit the result:"; \ echo "Please run 'make fmt' and commit the result:"; \
echo "$${diff}"; \ printf "%s" "$${diff}"; \
exit 1; \ exit 1; \
fi fi
@ -325,95 +266,95 @@ TAGS_PREREQ := $(TAGS_EVIDENCE)
endif endif
.PHONY: generate-swagger .PHONY: generate-swagger
generate-swagger: $(SWAGGER_SPEC) generate-swagger: $(SWAGGER_SPEC) ## generate the swagger spec from code comments
$(SWAGGER_SPEC): $(GO_SOURCES_NO_BINDATA) $(SWAGGER_SPEC): $(GO_SOURCES_NO_BINDATA) $(SWAGGER_SPEC_INPUT)
$(GO) run $(SWAGGER_PACKAGE) generate spec -x "$(SWAGGER_EXCLUDE)" -o './$(SWAGGER_SPEC)' $(GO) run $(SWAGGER_PACKAGE) generate spec --exclude "$(SWAGGER_EXCLUDE)" --input "$(SWAGGER_SPEC_INPUT)" --output './$(SWAGGER_SPEC)'
$(SED_INPLACE) '$(SWAGGER_SPEC_S_TMPL)' './$(SWAGGER_SPEC)'
$(SED_INPLACE) $(SWAGGER_NEWLINE_COMMAND) './$(SWAGGER_SPEC)'
.PHONY: swagger-check .PHONY: swagger-check
swagger-check: generate-swagger swagger-check: generate-swagger
@diff=$$(git diff --color=always '$(SWAGGER_SPEC)'); \ @diff=$$(git diff --color=always '$(SWAGGER_SPEC)'); \
if [ -n "$$diff" ]; then \ if [ -n "$$diff" ]; then \
echo "Please run 'make generate-swagger' and commit the result:"; \ echo "Please run 'make generate-swagger' and commit the result:"; \
echo "$${diff}"; \ printf "%s" "$${diff}"; \
exit 1; \ exit 1; \
fi fi
.PHONY: swagger-validate .PHONY: swagger-validate
swagger-validate: swagger-validate: ## check if the swagger spec is valid
$(SED_INPLACE) '$(SWAGGER_SPEC_S_JSON)' './$(SWAGGER_SPEC)' @# swagger "validate" requires that the "basePath" must start with a slash, but we are using Golang template "{{...}}"
@$(SED_INPLACE) -E -e 's|"basePath":( *)"(.*)"|"basePath":\1"/\2"|g' './$(SWAGGER_SPEC)' # add a prefix slash to basePath
@# FIXME: there are some warnings
$(GO) run $(SWAGGER_PACKAGE) validate './$(SWAGGER_SPEC)' $(GO) run $(SWAGGER_PACKAGE) validate './$(SWAGGER_SPEC)'
$(SED_INPLACE) '$(SWAGGER_SPEC_S_TMPL)' './$(SWAGGER_SPEC)' @$(SED_INPLACE) -E -e 's|"basePath":( *)"/(.*)"|"basePath":\1"\2"|g' './$(SWAGGER_SPEC)' # remove the prefix slash from basePath
.PHONY: checks .PHONY: checks
checks: checks-frontend checks-backend checks: checks-frontend checks-backend ## run various consistency checks
.PHONY: checks-frontend .PHONY: checks-frontend
checks-frontend: lockfile-check svg-check checks-frontend: lockfile-check svg-check ## check frontend files
.PHONY: checks-backend .PHONY: checks-backend
checks-backend: tidy-check swagger-check fmt-check swagger-validate security-check checks-backend: tidy-check swagger-check fmt-check swagger-validate security-check ## check backend files
.PHONY: lint .PHONY: lint
lint: lint-frontend lint-backend lint-spell lint: lint-frontend lint-backend lint-spell ## lint everything
.PHONY: lint-fix .PHONY: lint-fix
lint-fix: lint-frontend-fix lint-backend-fix lint-spell-fix lint-fix: lint-frontend-fix lint-backend-fix lint-spell-fix ## lint everything and fix issues
.PHONY: lint-frontend .PHONY: lint-frontend
lint-frontend: lint-js lint-css lint-frontend: lint-js lint-css ## lint frontend files
.PHONY: lint-frontend-fix .PHONY: lint-frontend-fix
lint-frontend-fix: lint-js-fix lint-css-fix lint-frontend-fix: lint-js-fix lint-css-fix ## lint frontend files and fix issues
.PHONY: lint-backend .PHONY: lint-backend
lint-backend: lint-go lint-go-vet lint-go-gopls lint-editorconfig lint-backend: lint-go lint-go-gitea-vet lint-go-gopls lint-editorconfig ## lint backend files
.PHONY: lint-backend-fix .PHONY: lint-backend-fix
lint-backend-fix: lint-go-fix lint-go-vet lint-editorconfig lint-backend-fix: lint-go-fix lint-go-gitea-vet lint-editorconfig ## lint backend files and fix issues
.PHONY: lint-js .PHONY: lint-js
lint-js: node_modules lint-js: node_modules ## lint js files
npx eslint --color --max-warnings=0 --ext js,ts,vue $(ESLINT_FILES) npx eslint --color --max-warnings=0 --ext js,ts,vue $(ESLINT_FILES)
npx vue-tsc npx vue-tsc
.PHONY: lint-js-fix .PHONY: lint-js-fix
lint-js-fix: node_modules lint-js-fix: node_modules ## lint js files and fix issues
npx eslint --color --max-warnings=0 --ext js,ts,vue $(ESLINT_FILES) --fix npx eslint --color --max-warnings=0 --ext js,ts,vue $(ESLINT_FILES) --fix
npx vue-tsc npx vue-tsc
.PHONY: lint-css .PHONY: lint-css
lint-css: node_modules lint-css: node_modules ## lint css files
npx stylelint --color --max-warnings=0 $(STYLELINT_FILES) npx stylelint --color --max-warnings=0 $(STYLELINT_FILES)
.PHONY: lint-css-fix .PHONY: lint-css-fix
lint-css-fix: node_modules lint-css-fix: node_modules ## lint css files and fix issues
npx stylelint --color --max-warnings=0 $(STYLELINT_FILES) --fix npx stylelint --color --max-warnings=0 $(STYLELINT_FILES) --fix
.PHONY: lint-swagger .PHONY: lint-swagger
lint-swagger: node_modules lint-swagger: node_modules ## lint swagger files
npx spectral lint -q -F hint $(SWAGGER_SPEC) npx spectral lint -q -F hint $(SWAGGER_SPEC)
.PHONY: lint-md .PHONY: lint-md
lint-md: node_modules lint-md: node_modules ## lint markdown files
npx markdownlint *.md npx markdownlint *.md
.PHONY: lint-spell .PHONY: lint-spell
lint-spell: lint-spell: ## lint spelling
@go run $(MISSPELL_PACKAGE) -dict tools/misspellings.csv -error $(SPELLCHECK_FILES) @go run $(MISSPELL_PACKAGE) -dict tools/misspellings.csv -error $(SPELLCHECK_FILES)
.PHONY: lint-spell-fix .PHONY: lint-spell-fix
lint-spell-fix: lint-spell-fix: ## lint spelling and fix issues
@go run $(MISSPELL_PACKAGE) -dict tools/misspellings.csv -w $(SPELLCHECK_FILES) @go run $(MISSPELL_PACKAGE) -dict tools/misspellings.csv -w $(SPELLCHECK_FILES)
.PHONY: lint-go .PHONY: lint-go
lint-go: lint-go: ## lint go files
$(GO) run $(GOLANGCI_LINT_PACKAGE) run $(GO) run $(GOLANGCI_LINT_PACKAGE) run
.PHONY: lint-go-fix .PHONY: lint-go-fix
lint-go-fix: lint-go-fix: ## lint go files and fix issues
$(GO) run $(GOLANGCI_LINT_PACKAGE) run --fix $(GO) run $(GOLANGCI_LINT_PACKAGE) run --fix
# workaround step for the lint-go-windows CI task because 'go run' can not # workaround step for the lint-go-windows CI task because 'go run' can not
@ -423,57 +364,58 @@ lint-go-windows:
@GOOS= GOARCH= $(GO) install $(GOLANGCI_LINT_PACKAGE) @GOOS= GOARCH= $(GO) install $(GOLANGCI_LINT_PACKAGE)
golangci-lint run golangci-lint run
.PHONY: lint-go-vet .PHONY: lint-go-gitea-vet
lint-go-vet: lint-go-gitea-vet: ## lint go files with gitea-vet
@echo "Running go vet..." @echo "Running gitea-vet..."
@GOOS= GOARCH= $(GO) build code.gitea.io/gitea-vet @GOOS= GOARCH= $(GO) build code.gitea.io/gitea-vet
@$(GO) vet -vettool=gitea-vet ./... @$(GO) vet -vettool=gitea-vet ./...
.PHONY: lint-go-gopls .PHONY: lint-go-gopls
lint-go-gopls: lint-go-gopls: ## lint go files with gopls
@echo "Running gopls check..." @echo "Running gopls check..."
@GO=$(GO) GOPLS_PACKAGE=$(GOPLS_PACKAGE) tools/lint-go-gopls.sh $(GO_SOURCES_NO_BINDATA) @GO=$(GO) GOPLS_PACKAGE=$(GOPLS_PACKAGE) tools/lint-go-gopls.sh $(GO_SOURCES_NO_BINDATA)
.PHONY: lint-editorconfig .PHONY: lint-editorconfig
lint-editorconfig: lint-editorconfig:
@echo "Running editorconfig check..."
@$(GO) run $(EDITORCONFIG_CHECKER_PACKAGE) $(EDITORCONFIG_FILES) @$(GO) run $(EDITORCONFIG_CHECKER_PACKAGE) $(EDITORCONFIG_FILES)
.PHONY: lint-actions .PHONY: lint-actions
lint-actions: lint-actions: ## lint action workflow files
$(GO) run $(ACTIONLINT_PACKAGE) $(GO) run $(ACTIONLINT_PACKAGE)
.PHONY: lint-templates .PHONY: lint-templates
lint-templates: .venv node_modules lint-templates: .venv node_modules ## lint template files
@node tools/lint-templates-svg.js @node tools/lint-templates-svg.js
@poetry run djlint $(shell find templates -type f -iname '*.tmpl') @poetry run djlint $(shell find templates -type f -iname '*.tmpl')
.PHONY: lint-yaml .PHONY: lint-yaml
lint-yaml: .venv lint-yaml: .venv ## lint yaml files
@poetry run yamllint . @poetry run yamllint -s .
.PHONY: watch .PHONY: watch
watch: watch: ## watch everything and continuously rebuild
@bash tools/watch.sh @bash tools/watch.sh
.PHONY: watch-frontend .PHONY: watch-frontend
watch-frontend: node-check node_modules watch-frontend: node-check node_modules ## watch frontend files and continuously rebuild
@rm -rf $(WEBPACK_DEST_ENTRIES) @rm -rf $(WEBPACK_DEST_ENTRIES)
NODE_ENV=development npx webpack --watch --progress NODE_ENV=development npx webpack --watch --progress
.PHONY: watch-backend .PHONY: watch-backend
watch-backend: go-check watch-backend: go-check ## watch backend files and continuously rebuild
GITEA_RUN_MODE=dev $(GO) run $(AIR_PACKAGE) -c .air.toml GITEA_RUN_MODE=dev $(GO) run $(AIR_PACKAGE) -c .air.toml
.PHONY: test .PHONY: test
test: test-frontend test-backend test: test-frontend test-backend ## test everything
.PHONY: test-backend .PHONY: test-backend
test-backend: test-backend: ## test backend files
@echo "Running go test with $(GOTESTFLAGS) -tags '$(TEST_TAGS)'..." @echo "Running go test with $(GOTESTFLAGS) -tags '$(TEST_TAGS)'..."
@$(GO) test $(GOTESTFLAGS) -tags='$(TEST_TAGS)' $(GO_TEST_PACKAGES) @$(GO) test $(GOTESTFLAGS) -tags='$(TEST_TAGS)' $(GO_TEST_PACKAGES)
.PHONY: test-frontend .PHONY: test-frontend
test-frontend: node_modules test-frontend: node_modules ## test frontend files
npx vitest npx vitest
.PHONY: test-check .PHONY: test-check
@ -482,7 +424,7 @@ test-check:
@diff=$$(git status -s); \ @diff=$$(git status -s); \
if [ -n "$$diff" ]; then \ if [ -n "$$diff" ]; then \
echo "make test-backend has changed files in the source tree:"; \ echo "make test-backend has changed files in the source tree:"; \
echo "$${diff}"; \ printf "%s" "$${diff}"; \
echo "You should change the tests to create these files in a temporary directory."; \ echo "You should change the tests to create these files in a temporary directory."; \
echo "Do not simply add these files to .gitignore"; \ echo "Do not simply add these files to .gitignore"; \
exit 1; \ exit 1; \
@ -505,7 +447,7 @@ unit-test-coverage:
@$(GO) test $(GOTESTFLAGS) -timeout=20m -tags='$(TEST_TAGS)' -cover -coverprofile coverage.out $(GO_TEST_PACKAGES) && echo "\n==>\033[32m Ok\033[m\n" || exit 1 @$(GO) test $(GOTESTFLAGS) -timeout=20m -tags='$(TEST_TAGS)' -cover -coverprofile coverage.out $(GO_TEST_PACKAGES) && echo "\n==>\033[32m Ok\033[m\n" || exit 1
.PHONY: tidy .PHONY: tidy
tidy: tidy: ## run go mod tidy
$(eval MIN_GO_VERSION := $(shell grep -Eo '^go\s+[0-9]+\.[0-9.]+' go.mod | cut -d' ' -f2)) $(eval MIN_GO_VERSION := $(shell grep -Eo '^go\s+[0-9]+\.[0-9.]+' go.mod | cut -d' ' -f2))
$(GO) mod tidy -compat=$(MIN_GO_VERSION) $(GO) mod tidy -compat=$(MIN_GO_VERSION)
@$(MAKE) --no-print-directory $(GO_LICENSE_FILE) @$(MAKE) --no-print-directory $(GO_LICENSE_FILE)
@ -519,15 +461,17 @@ tidy-check: tidy
@diff=$$(git diff --color=always go.mod go.sum $(GO_LICENSE_FILE)); \ @diff=$$(git diff --color=always go.mod go.sum $(GO_LICENSE_FILE)); \
if [ -n "$$diff" ]; then \ if [ -n "$$diff" ]; then \
echo "Please run 'make tidy' and commit the result:"; \ echo "Please run 'make tidy' and commit the result:"; \
echo "$${diff}"; \ printf "%s" "$${diff}"; \
exit 1; \ exit 1; \
fi fi
.PHONY: go-licenses .PHONY: go-licenses
go-licenses: $(GO_LICENSE_FILE) go-licenses: $(GO_LICENSE_FILE) ## regenerate go licenses
$(GO_LICENSE_FILE): go.mod go.sum $(GO_LICENSE_FILE): go.mod go.sum
-$(GO) run $(GO_LICENSES_PACKAGE) save . --force --save_path=$(GO_LICENSE_TMP_DIR) 2>/dev/null @rm -rf $(GO_LICENSE_FILE)
$(GO) install $(GO_LICENSES_PACKAGE)
-GOOS=linux CGO_ENABLED=1 go-licenses save . --force --save_path=$(GO_LICENSE_TMP_DIR) 2>/dev/null
$(GO) run build/generate-go-licenses.go $(GO_LICENSE_TMP_DIR) $(GO_LICENSE_FILE) $(GO) run build/generate-go-licenses.go $(GO_LICENSE_TMP_DIR) $(GO_LICENSE_FILE)
@rm -rf $(GO_LICENSE_TMP_DIR) @rm -rf $(GO_LICENSE_TMP_DIR)
@ -771,17 +715,17 @@ install: $(wildcard *.go)
CGO_CFLAGS="$(CGO_CFLAGS)" $(GO) install -v -tags '$(TAGS)' -ldflags '-s -w $(LDFLAGS)' CGO_CFLAGS="$(CGO_CFLAGS)" $(GO) install -v -tags '$(TAGS)' -ldflags '-s -w $(LDFLAGS)'
.PHONY: build .PHONY: build
build: frontend backend build: frontend backend ## build everything
.PHONY: frontend .PHONY: frontend
frontend: $(WEBPACK_DEST) frontend: $(WEBPACK_DEST) ## build frontend files
.PHONY: backend .PHONY: backend
backend: go-check generate-backend $(EXECUTABLE) backend: go-check generate-backend $(EXECUTABLE) ## build backend files
# We generate the backend before the frontend in case we in future we want to generate things in the frontend from generated files in backend # We generate the backend before the frontend in case we in future we want to generate things in the frontend from generated files in backend
.PHONY: generate .PHONY: generate
generate: generate-backend generate: generate-backend ## run "go generate"
.PHONY: generate-backend .PHONY: generate-backend
generate-backend: $(TAGS_PREREQ) generate-go generate-backend: $(TAGS_PREREQ) generate-go
@ -793,7 +737,7 @@ generate-go: $(TAGS_PREREQ)
.PHONY: security-check .PHONY: security-check
security-check: security-check:
go run $(GOVULNCHECK_PACKAGE) ./... go run $(GOVULNCHECK_PACKAGE) -show color ./...
$(EXECUTABLE): $(GO_SOURCES) $(TAGS_PREREQ) $(EXECUTABLE): $(GO_SOURCES) $(TAGS_PREREQ)
CGO_CFLAGS="$(CGO_CFLAGS)" $(GO) build $(GOFLAGS) $(EXTRA_GOFLAGS) -tags '$(TAGS)' -ldflags '-s -w $(LDFLAGS)' -o $@ CGO_CFLAGS="$(CGO_CFLAGS)" $(GO) build $(GOFLAGS) $(EXTRA_GOFLAGS) -tags '$(TAGS)' -ldflags '-s -w $(LDFLAGS)' -o $@
@ -806,22 +750,22 @@ $(DIST_DIRS):
.PHONY: release-windows .PHONY: release-windows
release-windows: | $(DIST_DIRS) release-windows: | $(DIST_DIRS)
CGO_CFLAGS="$(CGO_CFLAGS)" $(GO) run $(XGO_PACKAGE) -go $(XGO_VERSION) -buildmode exe -dest $(DIST)/binaries -tags 'osusergo $(TAGS)' -ldflags '-linkmode external -extldflags "-static" $(LDFLAGS)' -targets 'windows/*' -out gitea-$(VERSION) . CGO_CFLAGS="$(CGO_CFLAGS)" $(GO) run $(XGO_PACKAGE) -go $(XGO_VERSION) -buildmode exe -dest $(DIST)/binaries -tags 'osusergo $(TAGS)' -ldflags '-s -w -linkmode external -extldflags "-static" $(LDFLAGS)' -targets 'windows/*' -out gitea-$(VERSION) .
ifeq (,$(findstring gogit,$(TAGS))) ifeq (,$(findstring gogit,$(TAGS)))
CGO_CFLAGS="$(CGO_CFLAGS)" $(GO) run $(XGO_PACKAGE) -go $(XGO_VERSION) -buildmode exe -dest $(DIST)/binaries -tags 'osusergo gogit $(TAGS)' -ldflags '-linkmode external -extldflags "-static" $(LDFLAGS)' -targets 'windows/*' -out gitea-$(VERSION)-gogit . CGO_CFLAGS="$(CGO_CFLAGS)" $(GO) run $(XGO_PACKAGE) -go $(XGO_VERSION) -buildmode exe -dest $(DIST)/binaries -tags 'osusergo gogit $(TAGS)' -ldflags '-s -w -linkmode external -extldflags "-static" $(LDFLAGS)' -targets 'windows/*' -out gitea-$(VERSION)-gogit .
endif endif
.PHONY: release-linux .PHONY: release-linux
release-linux: | $(DIST_DIRS) release-linux: | $(DIST_DIRS)
CGO_CFLAGS="$(CGO_CFLAGS)" $(GO) run $(XGO_PACKAGE) -go $(XGO_VERSION) -dest $(DIST)/binaries -tags 'netgo osusergo $(TAGS)' -ldflags '-linkmode external -extldflags "-static" $(LDFLAGS)' -targets '$(LINUX_ARCHS)' -out gitea-$(VERSION) . CGO_CFLAGS="$(CGO_CFLAGS)" $(GO) run $(XGO_PACKAGE) -go $(XGO_VERSION) -dest $(DIST)/binaries -tags 'netgo osusergo $(TAGS)' -ldflags '-s -w -linkmode external -extldflags "-static" $(LDFLAGS)' -targets '$(LINUX_ARCHS)' -out gitea-$(VERSION) .
.PHONY: release-darwin .PHONY: release-darwin
release-darwin: | $(DIST_DIRS) release-darwin: | $(DIST_DIRS)
CGO_CFLAGS="$(CGO_CFLAGS)" $(GO) run $(XGO_PACKAGE) -go $(XGO_VERSION) -dest $(DIST)/binaries -tags 'netgo osusergo $(TAGS)' -ldflags '$(LDFLAGS)' -targets 'darwin-10.12/amd64,darwin-10.12/arm64' -out gitea-$(VERSION) . CGO_CFLAGS="$(CGO_CFLAGS)" $(GO) run $(XGO_PACKAGE) -go $(XGO_VERSION) -dest $(DIST)/binaries -tags 'netgo osusergo $(TAGS)' -ldflags '-s -w $(LDFLAGS)' -targets 'darwin-10.12/amd64,darwin-10.12/arm64' -out gitea-$(VERSION) .
.PHONY: release-freebsd .PHONY: release-freebsd
release-freebsd: | $(DIST_DIRS) release-freebsd: | $(DIST_DIRS)
CGO_CFLAGS="$(CGO_CFLAGS)" $(GO) run $(XGO_PACKAGE) -go $(XGO_VERSION) -dest $(DIST)/binaries -tags 'netgo osusergo $(TAGS)' -ldflags '$(LDFLAGS)' -targets 'freebsd/amd64' -out gitea-$(VERSION) . CGO_CFLAGS="$(CGO_CFLAGS)" $(GO) run $(XGO_PACKAGE) -go $(XGO_VERSION) -dest $(DIST)/binaries -tags 'netgo osusergo $(TAGS)' -ldflags '-s -w $(LDFLAGS)' -targets 'freebsd/amd64' -out gitea-$(VERSION) .
.PHONY: release-copy .PHONY: release-copy
release-copy: | $(DIST_DIRS) release-copy: | $(DIST_DIRS)
@ -846,20 +790,20 @@ release-sources: | $(DIST_DIRS)
rm -f $(STORED_VERSION_FILE) rm -f $(STORED_VERSION_FILE)
.PHONY: deps .PHONY: deps
deps: deps-frontend deps-backend deps-tools deps-py deps: deps-frontend deps-backend deps-tools deps-py ## install dependencies
.PHONY: deps-py .PHONY: deps-py
deps-py: .venv deps-py: .venv ## install python dependencies
.PHONY: deps-frontend .PHONY: deps-frontend
deps-frontend: node_modules deps-frontend: node_modules ## install frontend dependencies
.PHONY: deps-backend .PHONY: deps-backend
deps-backend: deps-backend: ## install backend dependencies
$(GO) mod download $(GO) mod download
.PHONY: deps-tools .PHONY: deps-tools
deps-tools: deps-tools: ## install tool dependencies
$(GO) install $(AIR_PACKAGE) & \ $(GO) install $(AIR_PACKAGE) & \
$(GO) install $(EDITORCONFIG_CHECKER_PACKAGE) & \ $(GO) install $(EDITORCONFIG_CHECKER_PACKAGE) & \
$(GO) install $(GOFUMPT_PACKAGE) & \ $(GO) install $(GOFUMPT_PACKAGE) & \
@ -883,10 +827,10 @@ node_modules: package-lock.json
@touch .venv @touch .venv
.PHONY: update .PHONY: update
update: update-js update-py update: update-js update-py ## update js and py dependencies
.PHONY: update-js .PHONY: update-js
update-js: node-check | node_modules update-js: node-check | node_modules ## update js dependencies
npx updates -u -f package.json npx updates -u -f package.json
rm -rf node_modules package-lock.json rm -rf node_modules package-lock.json
npm install --package-lock npm install --package-lock
@ -895,27 +839,14 @@ update-js: node-check | node_modules
@touch node_modules @touch node_modules
.PHONY: update-py .PHONY: update-py
update-py: node-check | node_modules update-py: node-check | node_modules ## update py dependencies
npx updates -u -f pyproject.toml npx updates -u -f pyproject.toml
rm -rf .venv poetry.lock rm -rf .venv poetry.lock
poetry install poetry install
@touch .venv @touch .venv
.PHONY: fomantic
fomantic:
rm -rf $(FOMANTIC_WORK_DIR)/build
cd $(FOMANTIC_WORK_DIR) && npm install --no-save
cp -f $(FOMANTIC_WORK_DIR)/theme.config.less $(FOMANTIC_WORK_DIR)/node_modules/fomantic-ui/src/theme.config
cp -rf $(FOMANTIC_WORK_DIR)/_site $(FOMANTIC_WORK_DIR)/node_modules/fomantic-ui/src/
$(SED_INPLACE) -e 's/ overrideBrowserslist\r/ overrideBrowserslist: ["defaults"]\r/g' $(FOMANTIC_WORK_DIR)/node_modules/fomantic-ui/tasks/config/tasks.js
cd $(FOMANTIC_WORK_DIR) && npx gulp -f node_modules/fomantic-ui/gulpfile.js build
# fomantic uses "touchstart" as click event for some browsers, it's not ideal, so we force fomantic to always use "click" as click event
$(SED_INPLACE) -e 's/clickEvent[ \t]*=/clickEvent = "click", unstableClickEvent =/g' $(FOMANTIC_WORK_DIR)/build/semantic.js
$(SED_INPLACE) -e 's/\r//g' $(FOMANTIC_WORK_DIR)/build/semantic.css $(FOMANTIC_WORK_DIR)/build/semantic.js
rm -f $(FOMANTIC_WORK_DIR)/build/*.min.*
.PHONY: webpack .PHONY: webpack
webpack: $(WEBPACK_DEST) webpack: $(WEBPACK_DEST) ## build webpack files
$(WEBPACK_DEST): $(WEBPACK_SOURCES) $(WEBPACK_CONFIGS) package-lock.json $(WEBPACK_DEST): $(WEBPACK_SOURCES) $(WEBPACK_CONFIGS) package-lock.json
@$(MAKE) -s node-check node_modules @$(MAKE) -s node-check node_modules
@ -925,7 +856,7 @@ $(WEBPACK_DEST): $(WEBPACK_SOURCES) $(WEBPACK_CONFIGS) package-lock.json
@touch $(WEBPACK_DEST) @touch $(WEBPACK_DEST)
.PHONY: svg .PHONY: svg
svg: node-check | node_modules svg: node-check | node_modules ## build svg files
rm -rf $(SVG_DEST_DIR) rm -rf $(SVG_DEST_DIR)
node tools/generate-svg.js node tools/generate-svg.js
@ -935,7 +866,7 @@ svg-check: svg
@diff=$$(git diff --color=always --cached $(SVG_DEST_DIR)); \ @diff=$$(git diff --color=always --cached $(SVG_DEST_DIR)); \
if [ -n "$$diff" ]; then \ if [ -n "$$diff" ]; then \
echo "Please run 'make svg' and 'git add $(SVG_DEST_DIR)' and commit the result:"; \ echo "Please run 'make svg' and 'git add $(SVG_DEST_DIR)' and commit the result:"; \
echo "$${diff}"; \ printf "%s" "$${diff}"; \
exit 1; \ exit 1; \
fi fi
@ -946,7 +877,7 @@ lockfile-check:
if [ -n "$$diff" ]; then \ if [ -n "$$diff" ]; then \
echo "package-lock.json is inconsistent with package.json"; \ echo "package-lock.json is inconsistent with package.json"; \
echo "Please run 'npm install --package-lock-only' and commit the result:"; \ echo "Please run 'npm install --package-lock-only' and commit the result:"; \
echo "$${diff}"; \ printf "%s" "$${diff}"; \
exit 1; \ exit 1; \
fi fi
@ -960,12 +891,8 @@ update-translations:
mv ./translations/*.ini ./options/locale/ mv ./translations/*.ini ./options/locale/
rmdir ./translations rmdir ./translations
.PHONY: generate-license
generate-license:
$(GO) run build/generate-licenses.go
.PHONY: generate-gitignore .PHONY: generate-gitignore
generate-gitignore: generate-gitignore: ## update gitignore files
$(GO) run build/generate-gitignores.go $(GO) run build/generate-gitignores.go
.PHONY: generate-images .PHONY: generate-images
@ -974,7 +901,7 @@ generate-images: | node_modules
node tools/generate-images.js $(TAGS) node tools/generate-images.js $(TAGS)
.PHONY: generate-manpage .PHONY: generate-manpage
generate-manpage: generate-manpage: ## generate manpage
@[ -f gitea ] || make backend @[ -f gitea ] || make backend
@mkdir -p man/man1/ man/man5 @mkdir -p man/man1/ man/man5
@./gitea docs --man > man/man1/gitea.1 @./gitea docs --man > man/man1/gitea.1

108
README.md
View File

@ -9,9 +9,9 @@
[![](https://opencollective.com/gitea/tiers/backers/badge.svg?label=backers&color=brightgreen)](https://opencollective.com/gitea "Become a backer/sponsor of gitea") [![](https://opencollective.com/gitea/tiers/backers/badge.svg?label=backers&color=brightgreen)](https://opencollective.com/gitea "Become a backer/sponsor of gitea")
[![](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT "License: MIT") [![](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT "License: MIT")
[![Contribute with Gitpod](https://img.shields.io/badge/Contribute%20with-Gitpod-908a85?logo=gitpod&color=green)](https://gitpod.io/#https://github.com/go-gitea/gitea) [![Contribute with Gitpod](https://img.shields.io/badge/Contribute%20with-Gitpod-908a85?logo=gitpod&color=green)](https://gitpod.io/#https://github.com/go-gitea/gitea)
[![](https://badges.crowdin.net/gitea/localized.svg)](https://crowdin.com/project/gitea "Crowdin") [![](https://badges.crowdin.net/gitea/localized.svg)](https://translate.gitea.com "Crowdin")
[View this document in Chinese](./README_ZH.md) [繁體中文](./README.zh-tw.md) | [简体中文](./README.zh-cn.md)
## Purpose ## Purpose
@ -31,6 +31,14 @@ For accessing free Gitea service (with a limited number of repositories), you ca
To quickly deploy your own dedicated Gitea instance on Gitea Cloud, you can start a free trial at [cloud.gitea.com](https://cloud.gitea.com). To quickly deploy your own dedicated Gitea instance on Gitea Cloud, you can start a free trial at [cloud.gitea.com](https://cloud.gitea.com).
## Documentation
You can find comprehensive documentation on our official [documentation website](https://docs.gitea.com/).
It includes installation, administration, usage, development, contributing guides, and more to help you get started and explore all features effectively.
If you have any suggestions or would like to contribute to it, you can visit the [documentation repository](https://gitea.com/gitea/docs)
## Building ## Building
From the root of the source tree, run: From the root of the source tree, run:
@ -52,6 +60,8 @@ More info: https://docs.gitea.com/installation/install-from-source
## Using ## Using
After building, a binary file named `gitea` will be generated in the root of the source tree by default. To run it, use:
./gitea web ./gitea web
> [!NOTE] > [!NOTE]
@ -68,22 +78,25 @@ Expected workflow is: Fork -> Patch -> Push -> Pull Request
## Translating ## Translating
Translations are done through Crowdin. If you want to translate to a new language ask one of the managers in the Crowdin project to add a new language there. [![Crowdin](https://badges.crowdin.net/gitea/localized.svg)](https://translate.gitea.com)
Translations are done through [Crowdin](https://translate.gitea.com). If you want to translate to a new language ask one of the managers in the Crowdin project to add a new language there.
You can also just create an issue for adding a language or ask on discord on the #translation channel. If you need context or find some translation issues, you can leave a comment on the string or ask on Discord. For general translation questions there is a section in the docs. Currently a bit empty but we hope to fill it as questions pop up. You can also just create an issue for adding a language or ask on discord on the #translation channel. If you need context or find some translation issues, you can leave a comment on the string or ask on Discord. For general translation questions there is a section in the docs. Currently a bit empty but we hope to fill it as questions pop up.
https://docs.gitea.com/contributing/localization Get more information from [documentation](https://docs.gitea.com/contributing/localization).
[![Crowdin](https://badges.crowdin.net/gitea/localized.svg)](https://crowdin.com/project/gitea) ## Official and Third-Party Projects
## Further information We provide an official [go-sdk](https://gitea.com/gitea/go-sdk), a CLI tool called [tea](https://gitea.com/gitea/tea) and an [action runner](https://gitea.com/gitea/act_runner) for Gitea Action.
For more information and instructions about how to install Gitea, please look at our [documentation](https://docs.gitea.com/). We maintain a list of Gitea-related projects at [gitea/awesome-gitea](https://gitea.com/gitea/awesome-gitea), where you can discover more third-party projects, including SDKs, plugins, themes, and more.
If you have questions that are not covered by the documentation, you can get in contact with us on our [Discord server](https://discord.gg/Gitea) or create a post in the [discourse forum](https://forum.gitea.com/).
We maintain a list of Gitea-related projects at [gitea/awesome-gitea](https://gitea.com/gitea/awesome-gitea). ## Communication
The official Gitea CLI is developed at [gitea/tea](https://gitea.com/gitea/tea). [![](https://img.shields.io/discord/322538954119184384.svg?logo=discord&logoColor=white&label=Discord&color=5865F2)](https://discord.gg/Gitea "Join the Discord chat at https://discord.gg/Gitea")
If you have questions that are not covered by the [documentation](https://docs.gitea.com/), you can get in contact with us on our [Discord server](https://discord.gg/Gitea) or create a post in the [discourse forum](https://forum.gitea.com/).
## Authors ## Authors
@ -122,18 +135,79 @@ Gitea is pronounced [/ɡɪti:/](https://youtu.be/EM71-2uDAoY) as in "gi-tea"
We're [working on it](https://github.com/go-gitea/gitea/issues/1029). We're [working on it](https://github.com/go-gitea/gitea/issues/1029).
**Where can I find the security patches?**
In the [release log](https://github.com/go-gitea/gitea/releases) or the [change log](https://github.com/go-gitea/gitea/blob/main/CHANGELOG.md), search for the keyword `SECURITY` to find the security patches.
## License ## License
This project is licensed under the MIT License. This project is licensed under the MIT License.
See the [LICENSE](https://github.com/go-gitea/gitea/blob/main/LICENSE) file See the [LICENSE](https://github.com/go-gitea/gitea/blob/main/LICENSE) file
for the full license text. for the full license text.
## Screenshots ## Further information
Looking for an overview of the interface? Check it out! <details>
<summary>Looking for an overview of the interface? Check it out!</summary>
|![Dashboard](https://dl.gitea.com/screenshots/home_timeline.png)|![User Profile](https://dl.gitea.com/screenshots/user_profile.png)|![Global Issues](https://dl.gitea.com/screenshots/global_issues.png)| ### Login/Register Page
|:---:|:---:|:---:|
|![Branches](https://dl.gitea.com/screenshots/branches.png)|![Web Editor](https://dl.gitea.com/screenshots/web_editor.png)|![Activity](https://dl.gitea.com/screenshots/activity.png)| ![Login](https://dl.gitea.com/screenshots/login.png)
|![New Migration](https://dl.gitea.com/screenshots/migration.png)|![Migrating](https://dl.gitea.com/screenshots/migration.gif)|![Pull Request View](https://image.ibb.co/e02dSb/6.png)| ![Register](https://dl.gitea.com/screenshots/register.png)
|![Pull Request Dark](https://dl.gitea.com/screenshots/pull_requests_dark.png)|![Diff Review Dark](https://dl.gitea.com/screenshots/review_dark.png)|![Diff Dark](https://dl.gitea.com/screenshots/diff_dark.png)|
### User Dashboard
![Home](https://dl.gitea.com/screenshots/home.png)
![Issues](https://dl.gitea.com/screenshots/issues.png)
![Pull Requests](https://dl.gitea.com/screenshots/pull_requests.png)
![Milestones](https://dl.gitea.com/screenshots/milestones.png)
### User Profile
![Profile](https://dl.gitea.com/screenshots/user_profile.png)
### Explore
![Repos](https://dl.gitea.com/screenshots/explore_repos.png)
![Users](https://dl.gitea.com/screenshots/explore_users.png)
![Orgs](https://dl.gitea.com/screenshots/explore_orgs.png)
### Repository
![Home](https://dl.gitea.com/screenshots/repo_home.png)
![Commits](https://dl.gitea.com/screenshots/repo_commits.png)
![Branches](https://dl.gitea.com/screenshots/repo_branches.png)
![Labels](https://dl.gitea.com/screenshots/repo_labels.png)
![Milestones](https://dl.gitea.com/screenshots/repo_milestones.png)
![Releases](https://dl.gitea.com/screenshots/repo_releases.png)
![Tags](https://dl.gitea.com/screenshots/repo_tags.png)
#### Repository Issue
![List](https://dl.gitea.com/screenshots/repo_issues.png)
![Issue](https://dl.gitea.com/screenshots/repo_issue.png)
#### Repository Pull Requests
![List](https://dl.gitea.com/screenshots/repo_pull_requests.png)
![Pull Request](https://dl.gitea.com/screenshots/repo_pull_request.png)
![File](https://dl.gitea.com/screenshots/repo_pull_request_file.png)
![Commits](https://dl.gitea.com/screenshots/repo_pull_request_commits.png)
#### Repository Actions
![List](https://dl.gitea.com/screenshots/repo_actions.png)
![Details](https://dl.gitea.com/screenshots/repo_actions_run.png)
#### Repository Activity
![Activity](https://dl.gitea.com/screenshots/repo_activity.png)
![Contributors](https://dl.gitea.com/screenshots/repo_contributors.png)
![Code Frequency](https://dl.gitea.com/screenshots/repo_code_frequency.png)
![Recent Commits](https://dl.gitea.com/screenshots/repo_recent_commits.png)
### Organization
![Home](https://dl.gitea.com/screenshots/org_home.png)
</details>

206
README.zh-cn.md Normal file
View File

@ -0,0 +1,206 @@
# Gitea
[![](https://github.com/go-gitea/gitea/actions/workflows/release-nightly.yml/badge.svg?branch=main)](https://github.com/go-gitea/gitea/actions/workflows/release-nightly.yml?query=branch%3Amain "Release Nightly")
[![](https://img.shields.io/discord/322538954119184384.svg?logo=discord&logoColor=white&label=Discord&color=5865F2)](https://discord.gg/Gitea "Join the Discord chat at https://discord.gg/Gitea")
[![](https://goreportcard.com/badge/code.gitea.io/gitea)](https://goreportcard.com/report/code.gitea.io/gitea "Go Report Card")
[![](https://pkg.go.dev/badge/code.gitea.io/gitea?status.svg)](https://pkg.go.dev/code.gitea.io/gitea "GoDoc")
[![](https://img.shields.io/github/release/go-gitea/gitea.svg)](https://github.com/go-gitea/gitea/releases/latest "GitHub release")
[![](https://www.codetriage.com/go-gitea/gitea/badges/users.svg)](https://www.codetriage.com/go-gitea/gitea "Help Contribute to Open Source")
[![](https://opencollective.com/gitea/tiers/backers/badge.svg?label=backers&color=brightgreen)](https://opencollective.com/gitea "Become a backer/sponsor of gitea")
[![](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT "License: MIT")
[![Contribute with Gitpod](https://img.shields.io/badge/Contribute%20with-Gitpod-908a85?logo=gitpod&color=green)](https://gitpod.io/#https://github.com/go-gitea/gitea)
[![](https://badges.crowdin.net/gitea/localized.svg)](https://translate.gitea.com "Crowdin")
[English](./README.md) | [繁體中文](./README.zh-tw.md)
## 目的
这个项目的目标是提供最简单、最快速、最无痛的方式来设置自托管的 Git 服务。
由于 Gitea 是用 Go 语言编写的,它可以在 Go 支持的所有平台和架构上运行,包括 Linux、macOS 和 Windows 的 x86、amd64、ARM 和 PowerPC 架构。这个项目自 2016 年 11 月从 [Gogs](https://gogs.io) [分叉](https://blog.gitea.com/welcome-to-gitea/) 而来,但已经有了很多变化。
在线演示可以访问 [demo.gitea.com](https://demo.gitea.com)。
要访问免费的 Gitea 服务(有一定数量的仓库限制),可以访问 [gitea.com](https://gitea.com/user/login)。
要快速部署您自己的专用 Gitea 实例,可以在 [cloud.gitea.com](https://cloud.gitea.com) 开始免费试用。
## 文件
您可以在我们的官方 [文件网站](https://docs.gitea.com/) 上找到全面的文件。
它包括安装、管理、使用、开发、贡献指南等,帮助您快速入门并有效地探索所有功能。
如果您有任何建议或想要贡献,可以访问 [文件仓库](https://gitea.com/gitea/docs)
## 构建
从源代码树的根目录运行:
TAGS="bindata" make build
如果需要 SQLite 支持:
TAGS="bindata sqlite sqlite_unlock_notify" make build
`build` 目标分为两个子目标:
- `make backend` 需要 [Go Stable](https://go.dev/dl/),所需版本在 [go.mod](/go.mod) 中定义。
- `make frontend` 需要 [Node.js LTS](https://nodejs.org/en/download/) 或更高版本。
需要互联网连接来下载 go 和 npm 模块。从包含预构建前端文件的官方源代码压缩包构建时,不会触发 `frontend` 目标,因此可以在没有 Node.js 的情况下构建。
更多信息https://docs.gitea.com/installation/install-from-source
## 使用
构建后,默认情况下会在源代码树的根目录生成一个名为 `gitea` 的二进制文件。要运行它,请使用:
./gitea web
> [!注意]
> 如果您对使用我们的 API 感兴趣,我们提供了实验性支持,并附有 [文件](https://docs.gitea.com/api)。
## 贡献
预期的工作流程是Fork -> Patch -> Push -> Pull Request
> [!注意]
>
> 1. **在开始进行 Pull Request 之前,您必须阅读 [贡献者指南](CONTRIBUTING.md)。**
> 2. 如果您在项目中发现了漏洞,请私下写信给 **security@gitea.io**。谢谢!
## 翻译
[![Crowdin](https://badges.crowdin.net/gitea/localized.svg)](https://translate.gitea.com)
翻译通过 [Crowdin](https://translate.gitea.com) 进行。如果您想翻译成新的语言,请在 Crowdin 项目中请求管理员添加新语言。
您也可以创建一个 issue 来添加语言,或者在 discord 的 #translation 频道上询问。如果您需要上下文或发现一些翻译问题,可以在字符串上留言或在 Discord 上询问。对于一般的翻译问题,文档中有一个部分。目前有点空,但我们希望随着问题的出现而填充它。
更多信息请参阅 [文件](https://docs.gitea.com/contributing/localization)。
## 官方和第三方项目
我们提供了一个官方的 [go-sdk](https://gitea.com/gitea/go-sdk),一个名为 [tea](https://gitea.com/gitea/tea) 的 CLI 工具和一个 Gitea Action 的 [action runner](https://gitea.com/gitea/act_runner)。
我们在 [gitea/awesome-gitea](https://gitea.com/gitea/awesome-gitea) 维护了一个 Gitea 相关项目的列表,您可以在那里发现更多的第三方项目,包括 SDK、插件、主题等。
## 通讯
[![](https://img.shields.io/discord/322538954119184384.svg?logo=discord&logoColor=white&label=Discord&color=5865F2)](https://discord.gg/Gitea "Join the Discord chat at https://discord.gg/Gitea")
如果您有任何文件未涵盖的问题,可以在我们的 [Discord 服务器](https://discord.gg/Gitea) 上与我们联系,或者在 [discourse 论坛](https://forum.gitea.com/) 上创建帖子。
## 作者
- [维护者](https://github.com/orgs/go-gitea/people)
- [贡献者](https://github.com/go-gitea/gitea/graphs/contributors)
- [翻译者](options/locale/TRANSLATORS)
## 支持者
感谢所有支持者! 🙏 [[成为支持者](https://opencollective.com/gitea#backer)]
<a href="https://opencollective.com/gitea#backers" target="_blank"><img src="https://opencollective.com/gitea/backers.svg?width=890"></a>
## 赞助商
通过成为赞助商来支持这个项目。您的标志将显示在这里,并带有链接到您的网站。 [[成为赞助商](https://opencollective.com/gitea#sponsor)]
<a href="https://opencollective.com/gitea/sponsor/0/website" target="_blank"><img src="https://opencollective.com/gitea/sponsor/0/avatar.svg"></a>
<a href="https://opencollective.com/gitea/sponsor/1/website" target="_blank"><img src="https://opencollective.com/gitea/sponsor/1/avatar.svg"></a>
<a href="https://opencollective.com/gitea/sponsor/2/website" target="_blank"><img src="https://opencollective.com/gitea/sponsor/2/avatar.svg"></a>
<a href="https://opencollective.com/gitea/sponsor/3/website" target="_blank"><img src="https://opencollective.com/gitea/sponsor/3/avatar.svg"></a>
<a href="https://opencollective.com/gitea/sponsor/4/website" target="_blank"><img src="https://opencollective.com/gitea/sponsor/4/avatar.svg"></a>
<a href="https://opencollective.com/gitea/sponsor/5/website" target="_blank"><img src="https://opencollective.com/gitea/sponsor/5/avatar.svg"></a>
<a href="https://opencollective.com/gitea/sponsor/6/website" target="_blank"><img src="https://opencollective.com/gitea/sponsor/6/avatar.svg"></a>
<a href="https://opencollective.com/gitea/sponsor/7/website" target="_blank"><img src="https://opencollective.com/gitea/sponsor/7/avatar.svg"></a>
<a href="https://opencollective.com/gitea/sponsor/8/website" target="_blank"><img src="https://opencollective.com/gitea/sponsor/8/avatar.svg"></a>
<a href="https://opencollective.com/gitea/sponsor/9/website" target="_blank"><img src="https://opencollective.com/gitea/sponsor/9/avatar.svg"></a>
## 常见问题
**Gitea 怎么发音?**
Gitea 的发音是 [/ɡɪti:/](https://youtu.be/EM71-2uDAoY),就像 "gi-tea" 一样g 是硬音。
**为什么这个项目没有托管在 Gitea 实例上?**
我们正在 [努力](https://github.com/go-gitea/gitea/issues/1029)。
**在哪里可以找到安全补丁?**
在 [发布日志](https://github.com/go-gitea/gitea/releases) 或 [变更日志](https://github.com/go-gitea/gitea/blob/main/CHANGELOG.md) 中,搜索关键词 `SECURITY` 以找到安全补丁。
## 许可证
这个项目是根据 MIT 许可证授权的。
请参阅 [LICENSE](https://github.com/go-gitea/gitea/blob/main/LICENSE) 文件以获取完整的许可证文本。
## 进一步信息
<details>
<summary>寻找界面概述?查看这里!</summary>
### 登录/注册页面
![Login](https://dl.gitea.com/screenshots/login.png)
![Register](https://dl.gitea.com/screenshots/register.png)
### 用户仪表板
![Home](https://dl.gitea.com/screenshots/home.png)
![Issues](https://dl.gitea.com/screenshots/issues.png)
![Pull Requests](https://dl.gitea.com/screenshots/pull_requests.png)
![Milestones](https://dl.gitea.com/screenshots/milestones.png)
### 用户资料
![Profile](https://dl.gitea.com/screenshots/user_profile.png)
### 探索
![Repos](https://dl.gitea.com/screenshots/explore_repos.png)
![Users](https://dl.gitea.com/screenshots/explore_users.png)
![Orgs](https://dl.gitea.com/screenshots/explore_orgs.png)
### 仓库
![Home](https://dl.gitea.com/screenshots/repo_home.png)
![Commits](https://dl.gitea.com/screenshots/repo_commits.png)
![Branches](https://dl.gitea.com/screenshots/repo_branches.png)
![Labels](https://dl.gitea.com/screenshots/repo_labels.png)
![Milestones](https://dl.gitea.com/screenshots/repo_milestones.png)
![Releases](https://dl.gitea.com/screenshots/repo_releases.png)
![Tags](https://dl.gitea.com/screenshots/repo_tags.png)
#### 仓库问题
![List](https://dl.gitea.com/screenshots/repo_issues.png)
![Issue](https://dl.gitea.com/screenshots/repo_issue.png)
#### 仓库拉取请求
![List](https://dl.gitea.com/screenshots/repo_pull_requests.png)
![Pull Request](https://dl.gitea.com/screenshots/repo_pull_request.png)
![File](https://dl.gitea.com/screenshots/repo_pull_request_file.png)
![Commits](https://dl.gitea.com/screenshots/repo_pull_request_commits.png)
#### 仓库操作
![List](https://dl.gitea.com/screenshots/repo_actions.png)
![Details](https://dl.gitea.com/screenshots/repo_actions_run.png)
#### 仓库活动
![Activity](https://dl.gitea.com/screenshots/repo_activity.png)
![Contributors](https://dl.gitea.com/screenshots/repo_contributors.png)
![Code Frequency](https://dl.gitea.com/screenshots/repo_code_frequency.png)
![Recent Commits](https://dl.gitea.com/screenshots/repo_recent_commits.png)
### 组织
![Home](https://dl.gitea.com/screenshots/org_home.png)
</details>

206
README.zh-tw.md Normal file
View File

@ -0,0 +1,206 @@
# Gitea
[![](https://github.com/go-gitea/gitea/actions/workflows/release-nightly.yml/badge.svg?branch=main)](https://github.com/go-gitea/gitea/actions/workflows/release-nightly.yml?query=branch%3Amain "Release Nightly")
[![](https://img.shields.io/discord/322538954119184384.svg?logo=discord&logoColor=white&label=Discord&color=5865F2)](https://discord.gg/Gitea "Join the Discord chat at https://discord.gg/Gitea")
[![](https://goreportcard.com/badge/code.gitea.io/gitea)](https://goreportcard.com/report/code.gitea.io/gitea "Go Report Card")
[![](https://pkg.go.dev/badge/code.gitea.io/gitea?status.svg)](https://pkg.go.dev/code.gitea.io/gitea "GoDoc")
[![](https://img.shields.io/github/release/go-gitea/gitea.svg)](https://github.com/go-gitea/gitea/releases/latest "GitHub release")
[![](https://www.codetriage.com/go-gitea/gitea/badges/users.svg)](https://www.codetriage.com/go-gitea/gitea "Help Contribute to Open Source")
[![](https://opencollective.com/gitea/tiers/backers/badge.svg?label=backers&color=brightgreen)](https://opencollective.com/gitea "Become a backer/sponsor of gitea")
[![](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT "License: MIT")
[![Contribute with Gitpod](https://img.shields.io/badge/Contribute%20with-Gitpod-908a85?logo=gitpod&color=green)](https://gitpod.io/#https://github.com/go-gitea/gitea)
[![](https://badges.crowdin.net/gitea/localized.svg)](https://translate.gitea.com "Crowdin")
[English](./README.md) | [简体中文](./README.zh-cn.md)
## 目的
這個項目的目標是提供最簡單、最快速、最無痛的方式來設置自託管的 Git 服務。
由於 Gitea 是用 Go 語言編寫的,它可以在 Go 支援的所有平台和架構上運行,包括 Linux、macOS 和 Windows 的 x86、amd64、ARM 和 PowerPC 架構。這個項目自 2016 年 11 月從 [Gogs](https://gogs.io) [分叉](https://blog.gitea.com/welcome-to-gitea/) 而來,但已經有了很多變化。
在線演示可以訪問 [demo.gitea.com](https://demo.gitea.com)。
要訪問免費的 Gitea 服務(有一定數量的倉庫限制),可以訪問 [gitea.com](https://gitea.com/user/login)。
要快速部署您自己的專用 Gitea 實例,可以在 [cloud.gitea.com](https://cloud.gitea.com) 開始免費試用。
## 文件
您可以在我們的官方 [文件網站](https://docs.gitea.com/) 上找到全面的文件。
它包括安裝、管理、使用、開發、貢獻指南等,幫助您快速入門並有效地探索所有功能。
如果您有任何建議或想要貢獻,可以訪問 [文件倉庫](https://gitea.com/gitea/docs)
## 構建
從源代碼樹的根目錄運行:
TAGS="bindata" make build
如果需要 SQLite 支援:
TAGS="bindata sqlite sqlite_unlock_notify" make build
`build` 目標分為兩個子目標:
- `make backend` 需要 [Go Stable](https://go.dev/dl/),所需版本在 [go.mod](/go.mod) 中定義。
- `make frontend` 需要 [Node.js LTS](https://nodejs.org/en/download/) 或更高版本。
需要互聯網連接來下載 go 和 npm 模塊。從包含預構建前端文件的官方源代碼壓縮包構建時,不會觸發 `frontend` 目標,因此可以在沒有 Node.js 的情況下構建。
更多信息https://docs.gitea.com/installation/install-from-source
## 使用
構建後,默認情況下會在源代碼樹的根目錄生成一個名為 `gitea` 的二進制文件。要運行它,請使用:
./gitea web
> [!注意]
> 如果您對使用我們的 API 感興趣,我們提供了實驗性支援,並附有 [文件](https://docs.gitea.com/api)。
## 貢獻
預期的工作流程是Fork -> Patch -> Push -> Pull Request
> [!注意]
>
> 1. **在開始進行 Pull Request 之前,您必須閱讀 [貢獻者指南](CONTRIBUTING.md)。**
> 2. 如果您在項目中發現了漏洞,請私下寫信給 **security@gitea.io**。謝謝!
## 翻譯
[![Crowdin](https://badges.crowdin.net/gitea/localized.svg)](https://translate.gitea.com)
翻譯通過 [Crowdin](https://translate.gitea.com) 進行。如果您想翻譯成新的語言,請在 Crowdin 項目中請求管理員添加新語言。
您也可以創建一個 issue 來添加語言,或者在 discord 的 #translation 頻道上詢問。如果您需要上下文或發現一些翻譯問題,可以在字符串上留言或在 Discord 上詢問。對於一般的翻譯問題,文檔中有一個部分。目前有點空,但我們希望隨著問題的出現而填充它。
更多信息請參閱 [文件](https://docs.gitea.com/contributing/localization)。
## 官方和第三方項目
我們提供了一個官方的 [go-sdk](https://gitea.com/gitea/go-sdk),一個名為 [tea](https://gitea.com/gitea/tea) 的 CLI 工具和一個 Gitea Action 的 [action runner](https://gitea.com/gitea/act_runner)。
我們在 [gitea/awesome-gitea](https://gitea.com/gitea/awesome-gitea) 維護了一個 Gitea 相關項目的列表,您可以在那裡發現更多的第三方項目,包括 SDK、插件、主題等。
## 通訊
[![](https://img.shields.io/discord/322538954119184384.svg?logo=discord&logoColor=white&label=Discord&color=5865F2)](https://discord.gg/Gitea "Join the Discord chat at https://discord.gg/Gitea")
如果您有任何文件未涵蓋的問題,可以在我們的 [Discord 服務器](https://discord.gg/Gitea) 上與我們聯繫,或者在 [discourse 論壇](https://forum.gitea.com/) 上創建帖子。
## 作者
- [維護者](https://github.com/orgs/go-gitea/people)
- [貢獻者](https://github.com/go-gitea/gitea/graphs/contributors)
- [翻譯者](options/locale/TRANSLATORS)
## 支持者
感謝所有支持者! 🙏 [[成為支持者](https://opencollective.com/gitea#backer)]
<a href="https://opencollective.com/gitea#backers" target="_blank"><img src="https://opencollective.com/gitea/backers.svg?width=890"></a>
## 贊助商
通過成為贊助商來支持這個項目。您的標誌將顯示在這裡,並帶有鏈接到您的網站。 [[成為贊助商](https://opencollective.com/gitea#sponsor)]
<a href="https://opencollective.com/gitea/sponsor/0/website" target="_blank"><img src="https://opencollective.com/gitea/sponsor/0/avatar.svg"></a>
<a href="https://opencollective.com/gitea/sponsor/1/website" target="_blank"><img src="https://opencollective.com/gitea/sponsor/1/avatar.svg"></a>
<a href="https://opencollective.com/gitea/sponsor/2/website" target="_blank"><img src="https://opencollective.com/gitea/sponsor/2/avatar.svg"></a>
<a href="https://opencollective.com/gitea/sponsor/3/website" target="_blank"><img src="https://opencollective.com/gitea/sponsor/3/avatar.svg"></a>
<a href="https://opencollective.com/gitea/sponsor/4/website" target="_blank"><img src="https://opencollective.com/gitea/sponsor/4/avatar.svg"></a>
<a href="https://opencollective.com/gitea/sponsor/5/website" target="_blank"><img src="https://opencollective.com/gitea/sponsor/5/avatar.svg"></a>
<a href="https://opencollective.com/gitea/sponsor/6/website" target="_blank"><img src="https://opencollective.com/gitea/sponsor/6/avatar.svg"></a>
<a href="https://opencollective.com/gitea/sponsor/7/website" target="_blank"><img src="https://opencollective.com/gitea/sponsor/7/avatar.svg"></a>
<a href="https://opencollective.com/gitea/sponsor/8/website" target="_blank"><img src="https://opencollective.com/gitea/sponsor/8/avatar.svg"></a>
<a href="https://opencollective.com/gitea/sponsor/9/website" target="_blank"><img src="https://opencollective.com/gitea/sponsor/9/avatar.svg"></a>
## 常見問題
**Gitea 怎麼發音?**
Gitea 的發音是 [/ɡɪti:/](https://youtu.be/EM71-2uDAoY),就像 "gi-tea" 一樣g 是硬音。
**為什麼這個項目沒有託管在 Gitea 實例上?**
我們正在 [努力](https://github.com/go-gitea/gitea/issues/1029)。
**在哪裡可以找到安全補丁?**
在 [發佈日誌](https://github.com/go-gitea/gitea/releases) 或 [變更日誌](https://github.com/go-gitea/gitea/blob/main/CHANGELOG.md) 中,搜索關鍵詞 `SECURITY` 以找到安全補丁。
## 許可證
這個項目是根據 MIT 許可證授權的。
請參閱 [LICENSE](https://github.com/go-gitea/gitea/blob/main/LICENSE) 文件以獲取完整的許可證文本。
## 進一步信息
<details>
<summary>尋找界面概述?查看這裡!</summary>
### 登錄/註冊頁面
![Login](https://dl.gitea.com/screenshots/login.png)
![Register](https://dl.gitea.com/screenshots/register.png)
### 用戶儀表板
![Home](https://dl.gitea.com/screenshots/home.png)
![Issues](https://dl.gitea.com/screenshots/issues.png)
![Pull Requests](https://dl.gitea.com/screenshots/pull_requests.png)
![Milestones](https://dl.gitea.com/screenshots/milestones.png)
### 用戶資料
![Profile](https://dl.gitea.com/screenshots/user_profile.png)
### 探索
![Repos](https://dl.gitea.com/screenshots/explore_repos.png)
![Users](https://dl.gitea.com/screenshots/explore_users.png)
![Orgs](https://dl.gitea.com/screenshots/explore_orgs.png)
### 倉庫
![Home](https://dl.gitea.com/screenshots/repo_home.png)
![Commits](https://dl.gitea.com/screenshots/repo_commits.png)
![Branches](https://dl.gitea.com/screenshots/repo_branches.png)
![Labels](https://dl.gitea.com/screenshots/repo_labels.png)
![Milestones](https://dl.gitea.com/screenshots/repo_milestones.png)
![Releases](https://dl.gitea.com/screenshots/repo_releases.png)
![Tags](https://dl.gitea.com/screenshots/repo_tags.png)
#### 倉庫問題
![List](https://dl.gitea.com/screenshots/repo_issues.png)
![Issue](https://dl.gitea.com/screenshots/repo_issue.png)
#### 倉庫拉取請求
![List](https://dl.gitea.com/screenshots/repo_pull_requests.png)
![Pull Request](https://dl.gitea.com/screenshots/repo_pull_request.png)
![File](https://dl.gitea.com/screenshots/repo_pull_request_file.png)
![Commits](https://dl.gitea.com/screenshots/repo_pull_request_commits.png)
#### 倉庫操作
![List](https://dl.gitea.com/screenshots/repo_actions.png)
![Details](https://dl.gitea.com/screenshots/repo_actions_run.png)
#### 倉庫活動
![Activity](https://dl.gitea.com/screenshots/repo_activity.png)
![Contributors](https://dl.gitea.com/screenshots/repo_contributors.png)
![Code Frequency](https://dl.gitea.com/screenshots/repo_code_frequency.png)
![Recent Commits](https://dl.gitea.com/screenshots/repo_recent_commits.png)
### 組織
![Home](https://dl.gitea.com/screenshots/org_home.png)
</details>

View File

@ -1,61 +0,0 @@
# Gitea
[![](https://github.com/go-gitea/gitea/actions/workflows/release-nightly.yml/badge.svg?branch=main)](https://github.com/go-gitea/gitea/actions/workflows/release-nightly.yml?query=branch%3Amain "Release Nightly")
[![](https://img.shields.io/discord/322538954119184384.svg?logo=discord&logoColor=white&label=Discord&color=5865F2)](https://discord.gg/Gitea "Join the Discord chat at https://discord.gg/Gitea")
[![](https://goreportcard.com/badge/code.gitea.io/gitea)](https://goreportcard.com/report/code.gitea.io/gitea "Go Report Card")
[![](https://pkg.go.dev/badge/code.gitea.io/gitea?status.svg)](https://pkg.go.dev/code.gitea.io/gitea "GoDoc")
[![](https://img.shields.io/github/release/go-gitea/gitea.svg)](https://github.com/go-gitea/gitea/releases/latest "GitHub release")
[![](https://www.codetriage.com/go-gitea/gitea/badges/users.svg)](https://www.codetriage.com/go-gitea/gitea "Help Contribute to Open Source")
[![](https://opencollective.com/gitea/tiers/backers/badge.svg?label=backers&color=brightgreen)](https://opencollective.com/gitea "Become a backer/sponsor of gitea")
[![](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT "License: MIT")
[![Contribute with Gitpod](https://img.shields.io/badge/Contribute%20with-Gitpod-908a85?logo=gitpod&color=green)](https://gitpod.io/#https://github.com/go-gitea/gitea)
[![](https://badges.crowdin.net/gitea/localized.svg)](https://crowdin.com/project/gitea "Crowdin")
[View this document in English](./README.md)
## 目标
Gitea 的首要目标是创建一个极易安装,运行非常快速,安装和使用体验良好的自建 Git 服务。我们采用 Go 作为后端语言,这使我们只要生成一个可执行程序即可。并且他还支持跨平台,支持 Linux, macOS 和 Windows 以及各种架构,除了 x86amd64还包括 ARM 和 PowerPC。
如果你想试用在线演示和报告问题,请访问 [demo.gitea.com](https://demo.gitea.com/)。
如果你想使用免费的 Gitea 服务(有仓库数量限制),请访问 [gitea.com](https://gitea.com/user/login)。
如果你想在 Gitea Cloud 上快速部署你自己独享的 Gitea 实例,请访问 [cloud.gitea.com](https://cloud.gitea.com) 开始免费试用。
## 提示
1. **开始贡献代码之前请确保你已经看过了 [贡献者向导(英文)](CONTRIBUTING.md)**.
2. 所有的安全问题,请私下发送邮件给 **security@gitea.io**。谢谢!
3. 如果你要使用API请参见 [API 文档](https://godoc.org/code.gitea.io/sdk/gitea).
## 文档
关于如何安装请访问我们的 [文档站](https://docs.gitea.com/zh-cn/category/installation),如果没有找到对应的文档,你也可以通过 [Discord - 英文](https://discord.gg/gitea) 和 QQ群 328432459 来和我们交流。
## 贡献流程
Fork -> Patch -> Push -> Pull Request
## 翻译
多语言翻译是基于Crowdin进行的.
[![Crowdin](https://badges.crowdin.net/gitea/localized.svg)](https://crowdin.com/project/gitea)
## 作者
* [Maintainers](https://github.com/orgs/go-gitea/people)
* [Contributors](https://github.com/go-gitea/gitea/graphs/contributors)
* [Translators](options/locale/TRANSLATORS)
## 授权许可
本项目采用 MIT 开源授权许可证,完整的授权说明已放置在 [LICENSE](https://github.com/go-gitea/gitea/blob/main/LICENSE) 文件中。
## 截图
|![Dashboard](https://dl.gitea.com/screenshots/home_timeline.png)|![User Profile](https://dl.gitea.com/screenshots/user_profile.png)|![Global Issues](https://dl.gitea.com/screenshots/global_issues.png)|
|:---:|:---:|:---:|
|![Branches](https://dl.gitea.com/screenshots/branches.png)|![Web Editor](https://dl.gitea.com/screenshots/web_editor.png)|![Activity](https://dl.gitea.com/screenshots/activity.png)|
|![New Migration](https://dl.gitea.com/screenshots/migration.png)|![Migrating](https://dl.gitea.com/screenshots/migration.gif)|![Pull Request View](https://image.ibb.co/e02dSb/6.png)|
|![Pull Request Dark](https://dl.gitea.com/screenshots/pull_requests_dark.png)|![Diff Review Dark](https://dl.gitea.com/screenshots/review_dark.png)|![Diff Dark](https://dl.gitea.com/screenshots/diff_dark.png)|

121
assets/go-licenses.json generated

File diff suppressed because one or more lines are too long

View File

@ -1,176 +0,0 @@
// Copyright 2017 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
//go:build ignore
package main
import (
"archive/tar"
"compress/gzip"
"crypto/md5"
"encoding/hex"
"flag"
"fmt"
"io"
"log"
"net/http"
"os"
"path"
"path/filepath"
"strings"
"code.gitea.io/gitea/build/license"
"code.gitea.io/gitea/modules/json"
"code.gitea.io/gitea/modules/util"
)
func main() {
var (
prefix = "gitea-licenses"
url = "https://api.github.com/repos/spdx/license-list-data/tarball"
githubApiToken = ""
githubUsername = ""
destination = ""
)
flag.StringVar(&destination, "dest", "options/license/", "destination for the licenses")
flag.StringVar(&githubUsername, "username", "", "github username")
flag.StringVar(&githubApiToken, "token", "", "github api token")
flag.Parse()
file, err := os.CreateTemp(os.TempDir(), prefix)
if err != nil {
log.Fatalf("Failed to create temp file. %s", err)
}
defer util.Remove(file.Name())
if err := os.RemoveAll(destination); err != nil {
log.Fatalf("Cannot clean destination folder: %v", err)
}
if err := os.MkdirAll(destination, 0o755); err != nil {
log.Fatalf("Cannot create destination: %v", err)
}
req, err := http.NewRequest("GET", url, nil)
if err != nil {
log.Fatalf("Failed to download archive. %s", err)
}
if len(githubApiToken) > 0 && len(githubUsername) > 0 {
req.SetBasicAuth(githubUsername, githubApiToken)
}
resp, err := http.DefaultClient.Do(req)
if err != nil {
log.Fatalf("Failed to download archive. %s", err)
}
defer resp.Body.Close()
if _, err := io.Copy(file, resp.Body); err != nil {
log.Fatalf("Failed to copy archive to file. %s", err)
}
if _, err := file.Seek(0, 0); err != nil {
log.Fatalf("Failed to reset seek on archive. %s", err)
}
gz, err := gzip.NewReader(file)
if err != nil {
log.Fatalf("Failed to gunzip the archive. %s", err)
}
tr := tar.NewReader(gz)
aliasesFiles := make(map[string][]string)
for {
hdr, err := tr.Next()
if err == io.EOF {
break
}
if err != nil {
log.Fatalf("Failed to iterate archive. %s", err)
}
if !strings.Contains(hdr.Name, "/text/") {
continue
}
if filepath.Ext(hdr.Name) != ".txt" {
continue
}
fileBaseName := filepath.Base(hdr.Name)
licenseName := strings.TrimSuffix(fileBaseName, ".txt")
if strings.HasPrefix(fileBaseName, "README") {
continue
}
if strings.HasPrefix(fileBaseName, "deprecated_") {
continue
}
out, err := os.Create(path.Join(destination, licenseName))
if err != nil {
log.Fatalf("Failed to create new file. %s", err)
}
defer out.Close()
// some license files have same content, so we need to detect these files and create a convert map into a json file
// Later we use this convert map to avoid adding same license content with different license name
h := md5.New()
// calculate md5 and write file in the same time
r := io.TeeReader(tr, h)
if _, err := io.Copy(out, r); err != nil {
log.Fatalf("Failed to write new file. %s", err)
} else {
fmt.Printf("Written %s\n", out.Name())
md5 := hex.EncodeToString(h.Sum(nil))
aliasesFiles[md5] = append(aliasesFiles[md5], licenseName)
}
}
// generate convert license name map
licenseAliases := make(map[string]string)
for _, fileNames := range aliasesFiles {
if len(fileNames) > 1 {
licenseName := license.GetLicenseNameFromAliases(fileNames)
if licenseName == "" {
// license name should not be empty as expected
// if it is empty, we need to rewrite the logic of GetLicenseNameFromAliases
log.Fatalf("GetLicenseNameFromAliases: license name is empty")
}
for _, fileName := range fileNames {
licenseAliases[fileName] = licenseName
}
}
}
// save convert license name map to file
b, err := json.Marshal(licenseAliases)
if err != nil {
log.Fatalf("Failed to create json bytes. %s", err)
}
licenseAliasesDestination := filepath.Join(destination, "etc", "license-aliases.json")
if err := os.MkdirAll(filepath.Dir(licenseAliasesDestination), 0o755); err != nil {
log.Fatalf("Failed to create directory for license aliases json file. %s", err)
}
f, err := os.Create(licenseAliasesDestination)
if err != nil {
log.Fatalf("Failed to create license aliases json file. %s", err)
}
defer f.Close()
if _, err = f.Write(b); err != nil {
log.Fatalf("Failed to write license aliases json file. %s", err)
}
fmt.Println("Done")
}

View File

@ -1,41 +0,0 @@
// Copyright 2024 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package license
import "strings"
func GetLicenseNameFromAliases(fnl []string) string {
if len(fnl) == 0 {
return ""
}
shortestItem := func(list []string) string {
s := list[0]
for _, l := range list[1:] {
if len(l) < len(s) {
s = l
}
}
return s
}
allHasPrefix := func(list []string, s string) bool {
for _, l := range list {
if !strings.HasPrefix(l, s) {
return false
}
}
return true
}
sl := shortestItem(fnl)
slv := strings.Split(sl, "-")
var result string
for i := len(slv); i >= 0; i-- {
result = strings.Join(slv[:i], "-")
if allHasPrefix(fnl, result) {
return result
}
}
return ""
}

View File

@ -1,39 +0,0 @@
// Copyright 2024 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package license
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestGetLicenseNameFromAliases(t *testing.T) {
tests := []struct {
target string
inputs []string
}{
{
// real case which you can find in license-aliases.json
target: "AGPL-1.0",
inputs: []string{
"AGPL-1.0-only",
"AGPL-1.0-or-late",
},
},
{
target: "",
inputs: []string{
"APSL-1.0",
"AGPL-1.0-only",
"AGPL-1.0-or-late",
},
},
}
for _, tt := range tests {
result := GetLicenseNameFromAliases(tt.inputs)
assert.Equal(t, result, tt.target)
}
}

View File

@ -127,6 +127,34 @@ var (
&cli.UintFlag{ &cli.UintFlag{
Name: "page-size", Name: "page-size",
Usage: "Search page size.", Usage: "Search page size.",
},
&cli.BoolFlag{
Name: "enable-groups",
Usage: "Enable LDAP groups",
},
&cli.StringFlag{
Name: "group-search-base-dn",
Usage: "The LDAP base DN at which group accounts will be searched for",
},
&cli.StringFlag{
Name: "group-member-attribute",
Usage: "Group attribute containing list of users",
},
&cli.StringFlag{
Name: "group-user-attribute",
Usage: "User attribute listed in group",
},
&cli.StringFlag{
Name: "group-filter",
Usage: "Verify group membership in LDAP",
},
&cli.StringFlag{
Name: "group-team-map",
Usage: "Map LDAP groups to Organization teams",
},
&cli.BoolFlag{
Name: "group-team-map-removal",
Usage: "Remove users from synchronized teams if user does not belong to corresponding LDAP group",
}) })
ldapSimpleAuthCLIFlags = append(commonLdapCLIFlags, ldapSimpleAuthCLIFlags = append(commonLdapCLIFlags,
@ -273,6 +301,27 @@ func parseLdapConfig(c *cli.Context, config *ldap.Source) error {
if c.IsSet("skip-local-2fa") { if c.IsSet("skip-local-2fa") {
config.SkipLocalTwoFA = c.Bool("skip-local-2fa") config.SkipLocalTwoFA = c.Bool("skip-local-2fa")
} }
if c.IsSet("enable-groups") {
config.GroupsEnabled = c.Bool("enable-groups")
}
if c.IsSet("group-search-base-dn") {
config.GroupDN = c.String("group-search-base-dn")
}
if c.IsSet("group-member-attribute") {
config.GroupMemberUID = c.String("group-member-attribute")
}
if c.IsSet("group-user-attribute") {
config.UserUID = c.String("group-user-attribute")
}
if c.IsSet("group-filter") {
config.GroupFilter = c.String("group-filter")
}
if c.IsSet("group-team-map") {
config.GroupTeamMap = c.String("group-team-map")
}
if c.IsSet("group-team-map-removal") {
config.GroupTeamMapRemoval = c.Bool("group-team-map-removal")
}
return nil return nil
} }

View File

@ -51,6 +51,13 @@ func TestAddLdapBindDn(t *testing.T) {
"--attributes-in-bind", "--attributes-in-bind",
"--synchronize-users", "--synchronize-users",
"--page-size", "99", "--page-size", "99",
"--enable-groups",
"--group-search-base-dn", "ou=group,dc=full-domain-bind,dc=org",
"--group-member-attribute", "memberUid",
"--group-user-attribute", "uid",
"--group-filter", "(|(cn=gitea_users)(cn=admins))",
"--group-team-map", `{"cn=my-group,cn=groups,dc=example,dc=org": {"MyGiteaOrganization": ["MyGiteaTeam1", "MyGiteaTeam2"]}}`,
"--group-team-map-removal",
}, },
source: &auth.Source{ source: &auth.Source{
Type: auth.LDAP, Type: auth.LDAP,
@ -78,6 +85,13 @@ func TestAddLdapBindDn(t *testing.T) {
AdminFilter: "(memberOf=cn=admin-group,ou=example,dc=full-domain-bind,dc=org)", AdminFilter: "(memberOf=cn=admin-group,ou=example,dc=full-domain-bind,dc=org)",
RestrictedFilter: "(memberOf=cn=restricted-group,ou=example,dc=full-domain-bind,dc=org)", RestrictedFilter: "(memberOf=cn=restricted-group,ou=example,dc=full-domain-bind,dc=org)",
Enabled: true, Enabled: true,
GroupsEnabled: true,
GroupDN: "ou=group,dc=full-domain-bind,dc=org",
GroupMemberUID: "memberUid",
UserUID: "uid",
GroupFilter: "(|(cn=gitea_users)(cn=admins))",
GroupTeamMap: `{"cn=my-group,cn=groups,dc=example,dc=org": {"MyGiteaOrganization": ["MyGiteaTeam1", "MyGiteaTeam2"]}}`,
GroupTeamMapRemoval: true,
}, },
}, },
}, },
@ -215,11 +229,11 @@ func TestAddLdapBindDn(t *testing.T) {
return nil return nil
}, },
updateAuthSource: func(ctx context.Context, authSource *auth.Source) error { updateAuthSource: func(ctx context.Context, authSource *auth.Source) error {
assert.FailNow(t, "case %d: should not call updateAuthSource", n) assert.FailNow(t, "updateAuthSource called", "case %d: should not call updateAuthSource", n)
return nil return nil
}, },
getAuthSourceByID: func(ctx context.Context, id int64) (*auth.Source, error) { getAuthSourceByID: func(ctx context.Context, id int64) (*auth.Source, error) {
assert.FailNow(t, "case %d: should not call getAuthSourceByID", n) assert.FailNow(t, "getAuthSourceByID called", "case %d: should not call getAuthSourceByID", n)
return nil, nil return nil, nil
}, },
} }
@ -446,11 +460,11 @@ func TestAddLdapSimpleAuth(t *testing.T) {
return nil return nil
}, },
updateAuthSource: func(ctx context.Context, authSource *auth.Source) error { updateAuthSource: func(ctx context.Context, authSource *auth.Source) error {
assert.FailNow(t, "case %d: should not call updateAuthSource", n) assert.FailNow(t, "updateAuthSource called", "case %d: should not call updateAuthSource", n)
return nil return nil
}, },
getAuthSourceByID: func(ctx context.Context, id int64) (*auth.Source, error) { getAuthSourceByID: func(ctx context.Context, id int64) (*auth.Source, error) {
assert.FailNow(t, "case %d: should not call getAuthSourceByID", n) assert.FailNow(t, "getAuthSourceById called", "case %d: should not call getAuthSourceByID", n)
return nil, nil return nil, nil
}, },
} }
@ -510,6 +524,13 @@ func TestUpdateLdapBindDn(t *testing.T) {
"--bind-password", "secret-bind-full", "--bind-password", "secret-bind-full",
"--synchronize-users", "--synchronize-users",
"--page-size", "99", "--page-size", "99",
"--enable-groups",
"--group-search-base-dn", "ou=group,dc=full-domain-bind,dc=org",
"--group-member-attribute", "memberUid",
"--group-user-attribute", "uid",
"--group-filter", "(|(cn=gitea_users)(cn=admins))",
"--group-team-map", `{"cn=my-group,cn=groups,dc=example,dc=org": {"MyGiteaOrganization": ["MyGiteaTeam1", "MyGiteaTeam2"]}}`,
"--group-team-map-removal",
}, },
id: 23, id: 23,
existingAuthSource: &auth.Source{ existingAuthSource: &auth.Source{
@ -545,6 +566,13 @@ func TestUpdateLdapBindDn(t *testing.T) {
AdminFilter: "(memberOf=cn=admin-group,ou=example,dc=full-domain-bind,dc=org)", AdminFilter: "(memberOf=cn=admin-group,ou=example,dc=full-domain-bind,dc=org)",
RestrictedFilter: "(memberOf=cn=restricted-group,ou=example,dc=full-domain-bind,dc=org)", RestrictedFilter: "(memberOf=cn=restricted-group,ou=example,dc=full-domain-bind,dc=org)",
Enabled: true, Enabled: true,
GroupsEnabled: true,
GroupDN: "ou=group,dc=full-domain-bind,dc=org",
GroupMemberUID: "memberUid",
UserUID: "uid",
GroupFilter: "(|(cn=gitea_users)(cn=admins))",
GroupTeamMap: `{"cn=my-group,cn=groups,dc=example,dc=org": {"MyGiteaOrganization": ["MyGiteaTeam1", "MyGiteaTeam2"]}}`,
GroupTeamMapRemoval: true,
}, },
}, },
}, },
@ -897,7 +925,7 @@ func TestUpdateLdapBindDn(t *testing.T) {
return nil return nil
}, },
createAuthSource: func(ctx context.Context, authSource *auth.Source) error { createAuthSource: func(ctx context.Context, authSource *auth.Source) error {
assert.FailNow(t, "case %d: should not call createAuthSource", n) assert.FailNow(t, "createAuthSource called", "case %d: should not call createAuthSource", n)
return nil return nil
}, },
updateAuthSource: func(ctx context.Context, authSource *auth.Source) error { updateAuthSource: func(ctx context.Context, authSource *auth.Source) error {
@ -1287,7 +1315,7 @@ func TestUpdateLdapSimpleAuth(t *testing.T) {
return nil return nil
}, },
createAuthSource: func(ctx context.Context, authSource *auth.Source) error { createAuthSource: func(ctx context.Context, authSource *auth.Source) error {
assert.FailNow(t, "case %d: should not call createAuthSource", n) assert.FailNow(t, "createAuthSource called", "case %d: should not call createAuthSource", n)
return nil return nil
}, },
updateAuthSource: func(ctx context.Context, authSource *auth.Source) error { updateAuthSource: func(ctx context.Context, authSource *auth.Source) error {

View File

@ -7,6 +7,7 @@ import (
"context" "context"
"errors" "errors"
"fmt" "fmt"
"strings"
auth_model "code.gitea.io/gitea/models/auth" auth_model "code.gitea.io/gitea/models/auth"
"code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/db"
@ -31,6 +32,11 @@ var microcmdUserCreate = &cli.Command{
Name: "username", Name: "username",
Usage: "Username", Usage: "Username",
}, },
&cli.StringFlag{
Name: "user-type",
Usage: "Set user's type: individual or bot",
Value: "individual",
},
&cli.StringFlag{ &cli.StringFlag{
Name: "password", Name: "password",
Usage: "User password", Usage: "User password",
@ -61,18 +67,52 @@ var microcmdUserCreate = &cli.Command{
Name: "access-token", Name: "access-token",
Usage: "Generate access token for the user", Usage: "Generate access token for the user",
}, },
&cli.StringFlag{
Name: "access-token-name",
Usage: `Name of the generated access token`,
Value: "gitea-admin",
},
&cli.StringFlag{
Name: "access-token-scopes",
Usage: `Scopes of the generated access token, comma separated. Examples: "all", "public-only,read:issue", "write:repository,write:user"`,
Value: "all",
},
&cli.BoolFlag{ &cli.BoolFlag{
Name: "restricted", Name: "restricted",
Usage: "Make a restricted user account", Usage: "Make a restricted user account",
}, },
&cli.StringFlag{
Name: "fullname",
Usage: `The full, human-readable name of the user`,
},
}, },
} }
func runCreateUser(c *cli.Context) error { func runCreateUser(c *cli.Context) error {
// this command highly depends on the many setting options (create org, visibility, etc.), so it must have a full setting load first
// duplicate setting loading should be safe at the moment, but it should be refactored & improved in the future.
setting.LoadSettings()
if err := argsSet(c, "email"); err != nil { if err := argsSet(c, "email"); err != nil {
return err return err
} }
userTypes := map[string]user_model.UserType{
"individual": user_model.UserTypeIndividual,
"bot": user_model.UserTypeBot,
}
userType, ok := userTypes[c.String("user-type")]
if !ok {
return fmt.Errorf("invalid user type: %s", c.String("user-type"))
}
if userType != user_model.UserTypeIndividual {
// Some other commands like "change-password" also only support individual users.
// It needs to clarify the "password" behavior for bot users in the future.
// At the moment, we do not allow setting password for bot users.
if c.IsSet("password") || c.IsSet("random-password") {
return errors.New("password can only be set for individual users")
}
}
if c.IsSet("name") && c.IsSet("username") { if c.IsSet("name") && c.IsSet("username") {
return errors.New("cannot set both --name and --username flags") return errors.New("cannot set both --name and --username flags")
} }
@ -114,16 +154,19 @@ func runCreateUser(c *cli.Context) error {
return err return err
} }
fmt.Printf("generated random password is '%s'\n", password) fmt.Printf("generated random password is '%s'\n", password)
} else { } else if userType == user_model.UserTypeIndividual {
return errors.New("must set either password or random-password flag") return errors.New("must set either password or random-password flag")
} }
isAdmin := c.Bool("admin") isAdmin := c.Bool("admin")
mustChangePassword := true // always default to true mustChangePassword := true // always default to true
if c.IsSet("must-change-password") { if c.IsSet("must-change-password") {
if userType != user_model.UserTypeIndividual {
return errors.New("must-change-password flag can only be set for individual users")
}
// if the flag is set, use the value provided by the user // if the flag is set, use the value provided by the user
mustChangePassword = c.Bool("must-change-password") mustChangePassword = c.Bool("must-change-password")
} else { } else if userType == user_model.UserTypeIndividual {
// check whether there are users in the database // check whether there are users in the database
hasUserRecord, err := db.IsTableNotEmpty(&user_model.User{}) hasUserRecord, err := db.IsTableNotEmpty(&user_model.User{})
if err != nil { if err != nil {
@ -147,10 +190,12 @@ func runCreateUser(c *cli.Context) error {
u := &user_model.User{ u := &user_model.User{
Name: username, Name: username,
Email: c.String("email"), Email: c.String("email"),
Passwd: password,
IsAdmin: isAdmin, IsAdmin: isAdmin,
Type: userType,
Passwd: password,
MustChangePassword: mustChangePassword, MustChangePassword: mustChangePassword,
Visibility: visibility, Visibility: visibility,
FullName: c.String("fullname"),
} }
overwriteDefault := &user_model.CreateUserOverwriteOptions{ overwriteDefault := &user_model.CreateUserOverwriteOptions{
@ -158,23 +203,40 @@ func runCreateUser(c *cli.Context) error {
IsRestricted: restricted, IsRestricted: restricted,
} }
var accessTokenName string
var accessTokenScope auth_model.AccessTokenScope
if c.IsSet("access-token") {
accessTokenName = strings.TrimSpace(c.String("access-token-name"))
if accessTokenName == "" {
return errors.New("access-token-name cannot be empty")
}
var err error
accessTokenScope, err = auth_model.AccessTokenScope(c.String("access-token-scopes")).Normalize()
if err != nil {
return fmt.Errorf("invalid access token scope provided: %w", err)
}
if !accessTokenScope.HasPermissionScope() {
return errors.New("access token does not have any permission")
}
} else if c.IsSet("access-token-name") || c.IsSet("access-token-scopes") {
return errors.New("access-token-name and access-token-scopes flags are only valid when access-token flag is set")
}
// arguments should be prepared before creating the user & access token, in case there is anything wrong
// create the user
if err := user_model.CreateUser(ctx, u, &user_model.Meta{}, overwriteDefault); err != nil { if err := user_model.CreateUser(ctx, u, &user_model.Meta{}, overwriteDefault); err != nil {
return fmt.Errorf("CreateUser: %w", err) return fmt.Errorf("CreateUser: %w", err)
} }
fmt.Printf("New user '%s' has been successfully created!\n", username)
if c.Bool("access-token") { // create the access token
t := &auth_model.AccessToken{ if accessTokenScope != "" {
Name: "gitea-admin", t := &auth_model.AccessToken{Name: accessTokenName, UID: u.ID, Scope: accessTokenScope}
UID: u.ID,
}
if err := auth_model.NewAccessToken(ctx, t); err != nil { if err := auth_model.NewAccessToken(ctx, t); err != nil {
return err return err
} }
fmt.Printf("Access token was successfully created... %s\n", t.Token) fmt.Printf("Access token was successfully created... %s\n", t.Token)
} }
fmt.Printf("New user '%s' has been successfully created!\n", username)
return nil return nil
} }

View File

@ -8,37 +8,128 @@ import (
"strings" "strings"
"testing" "testing"
auth_model "code.gitea.io/gitea/models/auth"
"code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/models/unittest" "code.gitea.io/gitea/models/unittest"
user_model "code.gitea.io/gitea/models/user" user_model "code.gitea.io/gitea/models/user"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
) )
func TestAdminUserCreate(t *testing.T) { func TestAdminUserCreate(t *testing.T) {
app := NewMainApp(AppVersion{}) app := NewMainApp(AppVersion{})
reset := func() { reset := func() {
assert.NoError(t, db.TruncateBeans(db.DefaultContext, &user_model.User{})) require.NoError(t, db.TruncateBeans(db.DefaultContext, &user_model.User{}))
assert.NoError(t, db.TruncateBeans(db.DefaultContext, &user_model.EmailAddress{})) require.NoError(t, db.TruncateBeans(db.DefaultContext, &user_model.EmailAddress{}))
require.NoError(t, db.TruncateBeans(db.DefaultContext, &auth_model.AccessToken{}))
} }
type createCheck struct{ IsAdmin, MustChangePassword bool } t.Run("MustChangePassword", func(t *testing.T) {
createUser := func(name, args string) createCheck { type check struct {
assert.NoError(t, app.Run(strings.Fields(fmt.Sprintf("./gitea admin user create --username %s --email %s@gitea.local %s --password foobar", name, name, args)))) IsAdmin bool
MustChangePassword bool
}
createCheck := func(name, args string) check {
require.NoError(t, app.Run(strings.Fields(fmt.Sprintf("./gitea admin user create --username %s --email %s@gitea.local %s --password foobar", name, name, args))))
u := unittest.AssertExistsAndLoadBean(t, &user_model.User{LowerName: name}) u := unittest.AssertExistsAndLoadBean(t, &user_model.User{LowerName: name})
return createCheck{u.IsAdmin, u.MustChangePassword} return check{IsAdmin: u.IsAdmin, MustChangePassword: u.MustChangePassword}
} }
reset() reset()
assert.Equal(t, createCheck{IsAdmin: false, MustChangePassword: false}, createUser("u", ""), "first non-admin user doesn't need to change password") assert.Equal(t, check{IsAdmin: false, MustChangePassword: false}, createCheck("u", ""), "first non-admin user doesn't need to change password")
reset() reset()
assert.Equal(t, createCheck{IsAdmin: true, MustChangePassword: false}, createUser("u", "--admin"), "first admin user doesn't need to change password") assert.Equal(t, check{IsAdmin: true, MustChangePassword: false}, createCheck("u", "--admin"), "first admin user doesn't need to change password")
reset() reset()
assert.Equal(t, createCheck{IsAdmin: true, MustChangePassword: true}, createUser("u", "--admin --must-change-password")) assert.Equal(t, check{IsAdmin: true, MustChangePassword: true}, createCheck("u", "--admin --must-change-password"))
assert.Equal(t, createCheck{IsAdmin: true, MustChangePassword: true}, createUser("u2", "--admin")) assert.Equal(t, check{IsAdmin: true, MustChangePassword: true}, createCheck("u2", "--admin"))
assert.Equal(t, createCheck{IsAdmin: true, MustChangePassword: false}, createUser("u3", "--admin --must-change-password=false")) assert.Equal(t, check{IsAdmin: true, MustChangePassword: false}, createCheck("u3", "--admin --must-change-password=false"))
assert.Equal(t, createCheck{IsAdmin: false, MustChangePassword: true}, createUser("u4", "")) assert.Equal(t, check{IsAdmin: false, MustChangePassword: true}, createCheck("u4", ""))
assert.Equal(t, createCheck{IsAdmin: false, MustChangePassword: false}, createUser("u5", "--must-change-password=false")) assert.Equal(t, check{IsAdmin: false, MustChangePassword: false}, createCheck("u5", "--must-change-password=false"))
})
createUser := func(name string, args ...string) error {
return app.Run(append([]string{"./gitea", "admin", "user", "create", "--username", name, "--email", name + "@gitea.local"}, args...))
}
t.Run("UserType", func(t *testing.T) {
reset()
assert.ErrorContains(t, createUser("u", "--user-type", "invalid"), "invalid user type")
assert.ErrorContains(t, createUser("u", "--user-type", "bot", "--password", "123"), "can only be set for individual users")
assert.ErrorContains(t, createUser("u", "--user-type", "bot", "--must-change-password"), "can only be set for individual users")
assert.NoError(t, createUser("u", "--user-type", "bot"))
u := unittest.AssertExistsAndLoadBean(t, &user_model.User{LowerName: "u"})
assert.Equal(t, user_model.UserTypeBot, u.Type)
assert.Empty(t, u.Passwd)
})
t.Run("AccessToken", func(t *testing.T) {
// no generated access token
reset()
assert.NoError(t, createUser("u", "--random-password"))
assert.Equal(t, 1, unittest.GetCount(t, &user_model.User{}))
assert.Equal(t, 0, unittest.GetCount(t, &auth_model.AccessToken{}))
// using "--access-token" only means "all" access
reset()
assert.NoError(t, createUser("u", "--random-password", "--access-token"))
assert.Equal(t, 1, unittest.GetCount(t, &user_model.User{}))
assert.Equal(t, 1, unittest.GetCount(t, &auth_model.AccessToken{}))
accessToken := unittest.AssertExistsAndLoadBean(t, &auth_model.AccessToken{Name: "gitea-admin"})
hasScopes, err := accessToken.Scope.HasScope(auth_model.AccessTokenScopeWriteAdmin, auth_model.AccessTokenScopeWriteRepository)
assert.NoError(t, err)
assert.True(t, hasScopes)
// using "--access-token" with name & scopes
reset()
assert.NoError(t, createUser("u", "--random-password", "--access-token", "--access-token-name", "new-token-name", "--access-token-scopes", "read:issue,read:user"))
assert.Equal(t, 1, unittest.GetCount(t, &user_model.User{}))
assert.Equal(t, 1, unittest.GetCount(t, &auth_model.AccessToken{}))
accessToken = unittest.AssertExistsAndLoadBean(t, &auth_model.AccessToken{Name: "new-token-name"})
hasScopes, err = accessToken.Scope.HasScope(auth_model.AccessTokenScopeReadIssue, auth_model.AccessTokenScopeReadUser)
assert.NoError(t, err)
assert.True(t, hasScopes)
hasScopes, err = accessToken.Scope.HasScope(auth_model.AccessTokenScopeWriteAdmin, auth_model.AccessTokenScopeWriteRepository)
assert.NoError(t, err)
assert.False(t, hasScopes)
// using "--access-token-name" without "--access-token"
reset()
err = createUser("u", "--random-password", "--access-token-name", "new-token-name")
assert.Equal(t, 0, unittest.GetCount(t, &user_model.User{}))
assert.Equal(t, 0, unittest.GetCount(t, &auth_model.AccessToken{}))
assert.ErrorContains(t, err, "access-token-name and access-token-scopes flags are only valid when access-token flag is set")
// using "--access-token-scopes" without "--access-token"
reset()
err = createUser("u", "--random-password", "--access-token-scopes", "read:issue")
assert.Equal(t, 0, unittest.GetCount(t, &user_model.User{}))
assert.Equal(t, 0, unittest.GetCount(t, &auth_model.AccessToken{}))
assert.ErrorContains(t, err, "access-token-name and access-token-scopes flags are only valid when access-token flag is set")
// empty permission
reset()
err = createUser("u", "--random-password", "--access-token", "--access-token-scopes", "public-only")
assert.Equal(t, 0, unittest.GetCount(t, &user_model.User{}))
assert.Equal(t, 0, unittest.GetCount(t, &auth_model.AccessToken{}))
assert.ErrorContains(t, err, "access token does not have any permission")
})
t.Run("UserFields", func(t *testing.T) {
reset()
assert.NoError(t, createUser("u-FullNameWithSpace", "--random-password", "--fullname", "First O'Middle Last"))
unittest.AssertExistsAndLoadBean(t, &user_model.User{
Name: "u-FullNameWithSpace",
LowerName: "u-fullnamewithspace",
FullName: "First O'Middle Last",
Email: "u-FullNameWithSpace@gitea.local",
})
assert.NoError(t, createUser("u-FullNameEmpty", "--random-password", "--fullname", ""))
u := unittest.AssertExistsAndLoadBean(t, &user_model.User{LowerName: "u-fullnameempty"})
assert.Empty(t, u.FullName)
})
} }

View File

@ -34,8 +34,8 @@ var microcmdUserGenerateAccessToken = &cli.Command{
}, },
&cli.StringFlag{ &cli.StringFlag{
Name: "scopes", Name: "scopes",
Value: "", Value: "all",
Usage: "Comma separated list of scopes to apply to access token", Usage: `Comma separated list of scopes to apply to access token, examples: "all", "public-only,read:issue", "write:repository,write:user"`,
}, },
}, },
Action: runGenerateAccessToken, Action: runGenerateAccessToken,
@ -43,7 +43,7 @@ var microcmdUserGenerateAccessToken = &cli.Command{
func runGenerateAccessToken(c *cli.Context) error { func runGenerateAccessToken(c *cli.Context) error {
if !c.IsSet("username") { if !c.IsSet("username") {
return errors.New("You must provide a username to generate a token for") return errors.New("you must provide a username to generate a token for")
} }
ctx, cancel := installSignals() ctx, cancel := installSignals()
@ -77,6 +77,9 @@ func runGenerateAccessToken(c *cli.Context) error {
if err != nil { if err != nil {
return fmt.Errorf("invalid access token scope provided: %w", err) return fmt.Errorf("invalid access token scope provided: %w", err)
} }
if !accessTokenScope.HasPermissionScope() {
return errors.New("access token does not have any permission")
}
t.Scope = accessTokenScope t.Scope = accessTokenScope
// create the token // create the token

View File

@ -4,6 +4,7 @@
package cmd package cmd
import ( import (
"context"
"fmt" "fmt"
golog "log" golog "log"
"os" "os"
@ -130,8 +131,8 @@ func runRecreateTable(ctx *cli.Context) error {
} }
recreateTables := migrate_base.RecreateTables(beans...) recreateTables := migrate_base.RecreateTables(beans...)
return db.InitEngineWithMigration(stdCtx, func(x *xorm.Engine) error { return db.InitEngineWithMigration(stdCtx, func(ctx context.Context, x *xorm.Engine) error {
if err := migrations.EnsureUpToDate(x); err != nil { if err := migrations.EnsureUpToDate(ctx, x); err != nil {
return err return err
} }
return recreateTables(x) return recreateTables(x)
@ -143,11 +144,12 @@ func setupDoctorDefaultLogger(ctx *cli.Context, colorize bool) {
setupConsoleLogger(log.FATAL, log.CanColorStderr, os.Stderr) setupConsoleLogger(log.FATAL, log.CanColorStderr, os.Stderr)
logFile := ctx.String("log-file") logFile := ctx.String("log-file")
if logFile == "" { switch logFile {
case "":
return // if no doctor log-file is set, do not show any log from default logger return // if no doctor log-file is set, do not show any log from default logger
} else if logFile == "-" { case "-":
setupConsoleLogger(log.TRACE, colorize, os.Stdout) setupConsoleLogger(log.TRACE, colorize, os.Stdout)
} else { default:
logFile, _ = filepath.Abs(logFile) logFile, _ = filepath.Abs(logFile)
writeMode := log.WriterMode{Level: log.TRACE, WriterOption: log.WriterFileOption{FileName: logFile}} writeMode := log.WriterMode{Level: log.TRACE, WriterOption: log.WriterFileOption{FileName: logFile}}
writer, err := log.NewEventWriter("console-to-file", "file", writeMode) writer, err := log.NewEventWriter("console-to-file", "file", writeMode)

View File

@ -5,7 +5,6 @@
package cmd package cmd
import ( import (
"fmt"
"os" "os"
"path" "path"
"path/filepath" "path/filepath"
@ -93,7 +92,7 @@ var CmdDump = &cli.Command{
}, },
&cli.StringFlag{ &cli.StringFlag{
Name: "type", Name: "type",
Usage: fmt.Sprintf(`Dump output format, default to "zip", supported types: %s`, strings.Join(dump.SupportedOutputTypes, ", ")), Usage: `Dump output format, default to "zip", supported types: ` + strings.Join(dump.SupportedOutputTypes, ", "),
}, },
}, },
} }

View File

@ -316,7 +316,7 @@ func runHookPostReceive(c *cli.Context) error {
setup(ctx, c.Bool("debug")) setup(ctx, c.Bool("debug"))
// First of all run update-server-info no matter what // First of all run update-server-info no matter what
if _, _, err := git.NewCommand(ctx, "update-server-info").RunStdString(nil); err != nil { if _, _, err := git.NewCommand("update-server-info").RunStdString(ctx, nil); err != nil {
return fmt.Errorf("Failed to call 'git update-server-info': %w", err) return fmt.Errorf("Failed to call 'git update-server-info': %w", err)
} }

View File

@ -6,7 +6,6 @@ package cmd
import ( import (
"bufio" "bufio"
"bytes" "bytes"
"context"
"strings" "strings"
"testing" "testing"
@ -15,7 +14,7 @@ import (
func TestPktLine(t *testing.T) { func TestPktLine(t *testing.T) {
// test read // test read
ctx := context.Background() ctx := t.Context()
s := strings.NewReader("0000") s := strings.NewReader("0000")
r := bufio.NewReader(s) r := bufio.NewReader(s)
result, err := readPktLine(ctx, r, pktLineTypeFlush) result, err := readPktLine(ctx, r, pktLineTypeFlush)

View File

@ -165,6 +165,7 @@ func NewMainApp(appVer AppVersion) *cli.App {
app.Commands = append(app.Commands, subCmdWithConfig...) app.Commands = append(app.Commands, subCmdWithConfig...)
app.Commands = append(app.Commands, subCmdStandalone...) app.Commands = append(app.Commands, subCmdStandalone...)
setting.InitGiteaEnvVars()
return app return app
} }

View File

@ -4,9 +4,9 @@
package cmd package cmd
import ( import (
"errors"
"fmt" "fmt"
"io" "io"
"os"
"path/filepath" "path/filepath"
"strings" "strings"
"testing" "testing"
@ -113,53 +113,33 @@ func TestCliCmd(t *testing.T) {
_, _ = fmt.Fprint(ctx.App.Writer, makePathOutput(setting.AppWorkPath, setting.CustomPath, setting.CustomConf)) _, _ = fmt.Fprint(ctx.App.Writer, makePathOutput(setting.AppWorkPath, setting.CustomPath, setting.CustomConf))
return nil return nil
}) })
var envBackup []string
for _, s := range os.Environ() {
if strings.HasPrefix(s, "GITEA_") && strings.Contains(s, "=") {
envBackup = append(envBackup, s)
}
}
clearGiteaEnv := func() {
for _, s := range os.Environ() {
if strings.HasPrefix(s, "GITEA_") {
_ = os.Unsetenv(s)
}
}
}
defer func() {
clearGiteaEnv()
for _, s := range envBackup {
k, v, _ := strings.Cut(s, "=")
_ = os.Setenv(k, v)
}
}()
for _, c := range cases { for _, c := range cases {
clearGiteaEnv() t.Run(c.cmd, func(t *testing.T) {
for k, v := range c.env { for k, v := range c.env {
_ = os.Setenv(k, v) t.Setenv(k, v)
} }
args := strings.Split(c.cmd, " ") // for test only, "split" is good enough args := strings.Split(c.cmd, " ") // for test only, "split" is good enough
r, err := runTestApp(app, args...) r, err := runTestApp(app, args...)
assert.NoError(t, err, c.cmd) assert.NoError(t, err, c.cmd)
assert.NotEmpty(t, c.exp, c.cmd) assert.NotEmpty(t, c.exp, c.cmd)
assert.Contains(t, r.Stdout, c.exp, c.cmd) assert.Contains(t, r.Stdout, c.exp, c.cmd)
})
} }
} }
func TestCliCmdError(t *testing.T) { func TestCliCmdError(t *testing.T) {
app := newTestApp(func(ctx *cli.Context) error { return fmt.Errorf("normal error") }) app := newTestApp(func(ctx *cli.Context) error { return errors.New("normal error") })
r, err := runTestApp(app, "./gitea", "test-cmd") r, err := runTestApp(app, "./gitea", "test-cmd")
assert.Error(t, err) assert.Error(t, err)
assert.Equal(t, 1, r.ExitCode) assert.Equal(t, 1, r.ExitCode)
assert.Equal(t, "", r.Stdout) assert.Empty(t, r.Stdout)
assert.Equal(t, "Command error: normal error\n", r.Stderr) assert.Equal(t, "Command error: normal error\n", r.Stderr)
app = newTestApp(func(ctx *cli.Context) error { return cli.Exit("exit error", 2) }) app = newTestApp(func(ctx *cli.Context) error { return cli.Exit("exit error", 2) })
r, err = runTestApp(app, "./gitea", "test-cmd") r, err = runTestApp(app, "./gitea", "test-cmd")
assert.Error(t, err) assert.Error(t, err)
assert.Equal(t, 2, r.ExitCode) assert.Equal(t, 2, r.ExitCode)
assert.Equal(t, "", r.Stdout) assert.Empty(t, r.Stdout)
assert.Equal(t, "exit error\n", r.Stderr) assert.Equal(t, "exit error\n", r.Stderr)
app = newTestApp(func(ctx *cli.Context) error { return nil }) app = newTestApp(func(ctx *cli.Context) error { return nil })
@ -167,12 +147,12 @@ func TestCliCmdError(t *testing.T) {
assert.Error(t, err) assert.Error(t, err)
assert.Equal(t, 1, r.ExitCode) assert.Equal(t, 1, r.ExitCode)
assert.Equal(t, "Incorrect Usage: flag provided but not defined: -no-such\n\n", r.Stdout) assert.Equal(t, "Incorrect Usage: flag provided but not defined: -no-such\n\n", r.Stdout)
assert.Equal(t, "", r.Stderr) // the cli package's strange behavior, the error message is not in stderr .... assert.Empty(t, r.Stderr) // the cli package's strange behavior, the error message is not in stderr ....
app = newTestApp(func(ctx *cli.Context) error { return nil }) app = newTestApp(func(ctx *cli.Context) error { return nil })
r, err = runTestApp(app, "./gitea", "test-cmd") r, err = runTestApp(app, "./gitea", "test-cmd")
assert.NoError(t, err) assert.NoError(t, err)
assert.Equal(t, -1, r.ExitCode) // the cli.OsExiter is not called assert.Equal(t, -1, r.ExitCode) // the cli.OsExiter is not called
assert.Equal(t, "", r.Stdout) assert.Empty(t, r.Stdout)
assert.Equal(t, "", r.Stderr) assert.Empty(t, r.Stderr)
} }

View File

@ -7,9 +7,9 @@ import (
"context" "context"
"code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/models/migrations"
"code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/services/versioned_migration"
"github.com/urfave/cli/v2" "github.com/urfave/cli/v2"
) )
@ -18,7 +18,7 @@ import (
var CmdMigrate = &cli.Command{ var CmdMigrate = &cli.Command{
Name: "migrate", Name: "migrate",
Usage: "Migrate the database", Usage: "Migrate the database",
Description: "This is a command for migrating the database, so that you can run gitea admin create-user before starting the server.", Description: `This is a command for migrating the database, so that you can run "gitea admin create user" before starting the server.`,
Action: runMigrate, Action: runMigrate,
} }
@ -36,7 +36,7 @@ func runMigrate(ctx *cli.Context) error {
log.Info("Log path: %s", setting.Log.RootPath) log.Info("Log path: %s", setting.Log.RootPath)
log.Info("Configuration file: %s", setting.CustomConf) log.Info("Configuration file: %s", setting.CustomConf)
if err := db.InitEngineWithMigration(context.Background(), migrations.Migrate); err != nil { if err := db.InitEngineWithMigration(context.Background(), versioned_migration.Migrate); err != nil {
log.Fatal("Failed to initialize ORM engine: %v", err) log.Fatal("Failed to initialize ORM engine: %v", err)
return err return err
} }

View File

@ -13,7 +13,6 @@ import (
actions_model "code.gitea.io/gitea/models/actions" actions_model "code.gitea.io/gitea/models/actions"
"code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/db"
git_model "code.gitea.io/gitea/models/git" git_model "code.gitea.io/gitea/models/git"
"code.gitea.io/gitea/models/migrations"
packages_model "code.gitea.io/gitea/models/packages" packages_model "code.gitea.io/gitea/models/packages"
repo_model "code.gitea.io/gitea/models/repo" repo_model "code.gitea.io/gitea/models/repo"
user_model "code.gitea.io/gitea/models/user" user_model "code.gitea.io/gitea/models/user"
@ -21,6 +20,7 @@ import (
packages_module "code.gitea.io/gitea/modules/packages" packages_module "code.gitea.io/gitea/modules/packages"
"code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/storage" "code.gitea.io/gitea/modules/storage"
"code.gitea.io/gitea/services/versioned_migration"
"github.com/urfave/cli/v2" "github.com/urfave/cli/v2"
) )
@ -196,7 +196,7 @@ func migrateActionsLog(ctx context.Context, dstStorage storage.ObjectStorage) er
func migrateActionsArtifacts(ctx context.Context, dstStorage storage.ObjectStorage) error { func migrateActionsArtifacts(ctx context.Context, dstStorage storage.ObjectStorage) error {
return db.Iterate(ctx, nil, func(ctx context.Context, artifact *actions_model.ActionArtifact) error { return db.Iterate(ctx, nil, func(ctx context.Context, artifact *actions_model.ActionArtifact) error {
if artifact.Status == int64(actions_model.ArtifactStatusExpired) { if artifact.Status == actions_model.ArtifactStatusExpired {
return nil return nil
} }
@ -227,7 +227,7 @@ func runMigrateStorage(ctx *cli.Context) error {
log.Info("Log path: %s", setting.Log.RootPath) log.Info("Log path: %s", setting.Log.RootPath)
log.Info("Configuration file: %s", setting.CustomConf) log.Info("Configuration file: %s", setting.CustomConf)
if err := db.InitEngineWithMigration(context.Background(), migrations.Migrate); err != nil { if err := db.InitEngineWithMigration(context.Background(), versioned_migration.Migrate); err != nil {
log.Fatal("Failed to initialize ORM engine: %v", err) log.Fatal("Failed to initialize ORM engine: %v", err)
return err return err
} }

View File

@ -4,7 +4,6 @@
package cmd package cmd
import ( import (
"context"
"os" "os"
"strings" "strings"
"testing" "testing"
@ -53,7 +52,7 @@ func TestMigratePackages(t *testing.T) {
assert.NotNil(t, v) assert.NotNil(t, v)
assert.NotNil(t, f) assert.NotNil(t, f)
ctx := context.Background() ctx := t.Context()
p := t.TempDir() p := t.TempDir()
@ -70,6 +69,6 @@ func TestMigratePackages(t *testing.T) {
entries, err := os.ReadDir(p) entries, err := os.ReadDir(p)
assert.NoError(t, err) assert.NoError(t, err)
assert.Len(t, entries, 2) assert.Len(t, entries, 2)
assert.EqualValues(t, "01", entries[0].Name()) assert.Equal(t, "01", entries[0].Name())
assert.EqualValues(t, "tmp", entries[1].Name()) assert.Equal(t, "tmp", entries[1].Name())
} }

View File

@ -104,7 +104,10 @@ func fail(ctx context.Context, userMessage, logMsgFmt string, args ...any) error
// There appears to be a chance to cause a zombie process and failure to read the Exit status // There appears to be a chance to cause a zombie process and failure to read the Exit status
// if nothing is outputted on stdout. // if nothing is outputted on stdout.
_, _ = fmt.Fprintln(os.Stdout, "") _, _ = fmt.Fprintln(os.Stdout, "")
_, _ = fmt.Fprintln(os.Stderr, "Gitea:", userMessage) // add extra empty lines to separate our message from other git errors to get more attention
_, _ = fmt.Fprintln(os.Stderr, "error:")
_, _ = fmt.Fprintln(os.Stderr, "error:", userMessage)
_, _ = fmt.Fprintln(os.Stderr, "error:")
if logMsgFmt != "" { if logMsgFmt != "" {
logMsg := fmt.Sprintf(logMsgFmt, args...) logMsg := fmt.Sprintf(logMsgFmt, args...)
@ -170,7 +173,7 @@ func getLFSAuthToken(ctx context.Context, lfsVerb string, results *private.ServC
if err != nil { if err != nil {
return "", fail(ctx, "Failed to sign JWT Token", "Failed to sign JWT token: %v", err) return "", fail(ctx, "Failed to sign JWT Token", "Failed to sign JWT token: %v", err)
} }
return fmt.Sprintf("Bearer %s", tokenString), nil return "Bearer " + tokenString, nil
} }
func runServ(c *cli.Context) error { func runServ(c *cli.Context) error {
@ -369,9 +372,9 @@ func runServ(c *cli.Context) error {
repo_module.EnvPusherEmail+"="+results.UserEmail, repo_module.EnvPusherEmail+"="+results.UserEmail,
repo_module.EnvPusherID+"="+strconv.FormatInt(results.UserID, 10), repo_module.EnvPusherID+"="+strconv.FormatInt(results.UserID, 10),
repo_module.EnvRepoID+"="+strconv.FormatInt(results.RepoID, 10), repo_module.EnvRepoID+"="+strconv.FormatInt(results.RepoID, 10),
repo_module.EnvPRID+"="+fmt.Sprintf("%d", 0), repo_module.EnvPRID+"="+strconv.Itoa(0),
repo_module.EnvDeployKeyID+"="+fmt.Sprintf("%d", results.DeployKeyID), repo_module.EnvDeployKeyID+"="+strconv.FormatInt(results.DeployKeyID, 10),
repo_module.EnvKeyID+"="+fmt.Sprintf("%d", results.KeyID), repo_module.EnvKeyID+"="+strconv.FormatInt(results.KeyID, 10),
repo_module.EnvAppURL+"="+setting.AppURL, repo_module.EnvAppURL+"="+setting.AppURL,
) )
// to avoid breaking, here only use the minimal environment variables for the "gitea serv" command. // to avoid breaking, here only use the minimal environment variables for the "gitea serv" command.

View File

@ -12,15 +12,18 @@ import (
"path/filepath" "path/filepath"
"strconv" "strconv"
"strings" "strings"
"time"
_ "net/http/pprof" // Used for debugging if enabled and a web server is running _ "net/http/pprof" // Used for debugging if enabled and a web server is running
"code.gitea.io/gitea/modules/container" "code.gitea.io/gitea/modules/container"
"code.gitea.io/gitea/modules/graceful" "code.gitea.io/gitea/modules/graceful"
"code.gitea.io/gitea/modules/gtprof"
"code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/process" "code.gitea.io/gitea/modules/process"
"code.gitea.io/gitea/modules/public" "code.gitea.io/gitea/modules/public"
"code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/util"
"code.gitea.io/gitea/routers" "code.gitea.io/gitea/routers"
"code.gitea.io/gitea/routers/install" "code.gitea.io/gitea/routers/install"
@ -115,6 +118,16 @@ func showWebStartupMessage(msg string) {
log.Info("* CustomPath: %s", setting.CustomPath) log.Info("* CustomPath: %s", setting.CustomPath)
log.Info("* ConfigFile: %s", setting.CustomConf) log.Info("* ConfigFile: %s", setting.CustomConf)
log.Info("%s", msg) // show startup message log.Info("%s", msg) // show startup message
if setting.CORSConfig.Enabled {
log.Info("CORS Service Enabled")
}
if setting.DefaultUILocation != time.Local {
log.Info("Default UI Location is %v", setting.DefaultUILocation.String())
}
if setting.MailService != nil {
log.Info("Mail Service Enabled: RegisterEmailConfirm=%v, Service.EnableNotifyMail=%v", setting.Service.RegisterEmailConfirm, setting.Service.EnableNotifyMail)
}
} }
func serveInstall(ctx *cli.Context) error { func serveInstall(ctx *cli.Context) error {
@ -200,6 +213,10 @@ func serveInstalled(ctx *cli.Context) error {
log.Fatal("Can not find APP_DATA_PATH %q", setting.AppDataPath) log.Fatal("Can not find APP_DATA_PATH %q", setting.AppDataPath)
} }
// the AppDataTempDir is fully managed by us with a safe sub-path
// so it's safe to automatically remove the outdated files
setting.AppDataTempDir("").RemoveOutdated(3 * 24 * time.Hour)
// Override the provided port number within the configuration // Override the provided port number within the configuration
if ctx.IsSet("port") { if ctx.IsSet("port") {
if err := setPort(ctx.String("port")); err != nil { if err := setPort(ctx.String("port")); err != nil {
@ -207,6 +224,8 @@ func serveInstalled(ctx *cli.Context) error {
} }
} }
gtprof.EnableBuiltinTracer(util.Iif(setting.IsProd, 2000*time.Millisecond, 100*time.Millisecond))
// Set up Chi routes // Set up Chi routes
webRoutes := routers.NormalRoutes() webRoutes := routers.NormalRoutes()
err := listen(webRoutes, true) err := listen(webRoutes, true)

View File

@ -16,6 +16,7 @@ import (
"code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/process" "code.gitea.io/gitea/modules/process"
"code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/util"
"github.com/caddyserver/certmagic" "github.com/caddyserver/certmagic"
) )
@ -54,8 +55,6 @@ func runACME(listenAddr string, m http.Handler) error {
altTLSALPNPort = p altTLSALPNPort = p
} }
magic := certmagic.NewDefault()
magic.Storage = &certmagic.FileStorage{Path: setting.AcmeLiveDirectory}
// Try to use private CA root if provided, otherwise defaults to system's trust // Try to use private CA root if provided, otherwise defaults to system's trust
var certPool *x509.CertPool var certPool *x509.CertPool
if setting.AcmeCARoot != "" { if setting.AcmeCARoot != "" {
@ -65,8 +64,20 @@ func runACME(listenAddr string, m http.Handler) error {
log.Warn("Failed to parse CA Root certificate, using default CA trust: %v", err) log.Warn("Failed to parse CA Root certificate, using default CA trust: %v", err)
} }
} }
myACME := certmagic.NewACMEIssuer(magic, certmagic.ACMEIssuer{ // FIXME: this path is not right, it uses "AppWorkPath" incorrectly, and writes the data into "AppWorkPath/https"
CA: setting.AcmeURL, // Ideally it should migrate to AppDataPath write to "AppDataPath/https"
// And one more thing, no idea why we should set the global default variables here
// But it seems that the current ACME code needs these global variables to make renew work.
// Otherwise, "renew" will use incorrect storage path
oldDefaultACME := certmagic.DefaultACME
certmagic.Default.Storage = &certmagic.FileStorage{Path: setting.AcmeLiveDirectory}
certmagic.DefaultACME = certmagic.ACMEIssuer{
// try to use the default values provided by DefaultACME
CA: util.IfZero(setting.AcmeURL, oldDefaultACME.CA),
TestCA: oldDefaultACME.TestCA,
Logger: oldDefaultACME.Logger,
HTTPProxy: oldDefaultACME.HTTPProxy,
TrustedRoots: certPool, TrustedRoots: certPool,
Email: setting.AcmeEmail, Email: setting.AcmeEmail,
Agreed: setting.AcmeTOS, Agreed: setting.AcmeTOS,
@ -75,8 +86,10 @@ func runACME(listenAddr string, m http.Handler) error {
ListenHost: setting.HTTPAddr, ListenHost: setting.HTTPAddr,
AltTLSALPNPort: altTLSALPNPort, AltTLSALPNPort: altTLSALPNPort,
AltHTTPPort: altHTTPPort, AltHTTPPort: altHTTPPort,
}) }
magic := certmagic.NewDefault()
myACME := certmagic.NewACMEIssuer(magic, certmagic.DefaultACME)
magic.Issuers = []certmagic.Issuer{myACME} magic.Issuers = []certmagic.Issuer{myACME}
// this obtains certificates or renews them if necessary // this obtains certificates or renews them if necessary
@ -123,7 +136,7 @@ func runACME(listenAddr string, m http.Handler) error {
} }
func runLetsEncryptFallbackHandler(w http.ResponseWriter, r *http.Request) { func runLetsEncryptFallbackHandler(w http.ResponseWriter, r *http.Request) {
if r.Method != "GET" && r.Method != "HEAD" { if r.Method != http.MethodGet && r.Method != http.MethodHead {
http.Error(w, "Use HTTPS", http.StatusBadRequest) http.Error(w, "Use HTTPS", http.StatusBadRequest)
return return
} }

View File

@ -6,6 +6,7 @@ package main
import ( import (
"context" "context"
"errors"
"fmt" "fmt"
"log" "log"
"net/http" "net/http"
@ -158,7 +159,7 @@ func runBackport(c *cli.Context) error {
args := c.Args().Slice() args := c.Args().Slice()
if len(args) == 0 && pr == "" { if len(args) == 0 && pr == "" {
return fmt.Errorf("no PR number provided\nProvide a PR number to backport") return errors.New("no PR number provided\nProvide a PR number to backport")
} else if len(args) != 1 && pr == "" { } else if len(args) != 1 && pr == "" {
return fmt.Errorf("multiple PRs provided %v\nOnly a single PR can be backported at a time", args) return fmt.Errorf("multiple PRs provided %v\nOnly a single PR can be backported at a time", args)
} }

View File

@ -78,8 +78,9 @@ RUN_USER = ; git
;; Set the domain for the server ;; Set the domain for the server
;DOMAIN = localhost ;DOMAIN = localhost
;; ;;
;; Overwrite the automatically generated public URL. Necessary for proxies and docker. ;; The AppURL used by Gitea to generate absolute links, defaults to "{PROTOCOL}://{DOMAIN}:{HTTP_PORT}/".
;ROOT_URL = %(PROTOCOL)s://%(DOMAIN)s:%(HTTP_PORT)s/ ;; Most users should set it to the real website URL of their Gitea instance.
;ROOT_URL =
;; ;;
;; For development purpose only. It makes Gitea handle sub-path ("/sub-path/owner/repo/...") directly when debugging without a reverse proxy. ;; For development purpose only. It makes Gitea handle sub-path ("/sub-path/owner/repo/...") directly when debugging without a reverse proxy.
;; DO NOT USE IT IN PRODUCTION!!! ;; DO NOT USE IT IN PRODUCTION!!!
@ -103,8 +104,8 @@ RUN_USER = ; git
;REDIRECT_OTHER_PORT = false ;REDIRECT_OTHER_PORT = false
;PORT_TO_REDIRECT = 80 ;PORT_TO_REDIRECT = 80
;; ;;
;; expect PROXY protocol header on connections to https redirector. ;; expect PROXY protocol header on connections to https redirector, defaults to USE_PROXY_PROTOCOL
;REDIRECTOR_USE_PROXY_PROTOCOL = %(USE_PROXY_PROTOCOL)s ;REDIRECTOR_USE_PROXY_PROTOCOL =
;; Minimum and maximum supported TLS versions ;; Minimum and maximum supported TLS versions
;SSL_MIN_VERSION=TLSv1.2 ;SSL_MIN_VERSION=TLSv1.2
;SSL_MAX_VERSION= ;SSL_MAX_VERSION=
@ -128,13 +129,14 @@ RUN_USER = ; git
;; most cases you do not need to change the default value. Alter it only if ;; most cases you do not need to change the default value. Alter it only if
;; your SSH server node is not the same as HTTP node. For different protocol, the default ;; your SSH server node is not the same as HTTP node. For different protocol, the default
;; values are different. If `PROTOCOL` is `http+unix`, the default value is `http://unix/`. ;; values are different. If `PROTOCOL` is `http+unix`, the default value is `http://unix/`.
;; If `PROTOCOL` is `fcgi` or `fcgi+unix`, the default value is `%(PROTOCOL)s://%(HTTP_ADDR)s:%(HTTP_PORT)s/`. ;; If `PROTOCOL` is `fcgi` or `fcgi+unix`, the default value is `{PROTOCOL}://{HTTP_ADDR}:{HTTP_PORT}/`.
;; If listen on `0.0.0.0`, the default value is `%(PROTOCOL)s://localhost:%(HTTP_PORT)s/`, Otherwise the default ;; If listen on `0.0.0.0`, the default value is `{PROTOCOL}://localhost:{HTTP_PORT}/`.
;; value is `%(PROTOCOL)s://%(HTTP_ADDR)s:%(HTTP_PORT)s/`. ;; Otherwise the default value is `{PROTOCOL}://{HTTP_ADDR}:{HTTP_PORT}/`.
;LOCAL_ROOT_URL = %(PROTOCOL)s://%(HTTP_ADDR)s:%(HTTP_PORT)s/ ;; Most users don't need (and shouldn't) set this value.
;LOCAL_ROOT_URL =
;; ;;
;; When making local connections pass the PROXY protocol header. ;; When making local connections pass the PROXY protocol header, defaults to USE_PROXY_PROTOCOL
;LOCAL_USE_PROXY_PROTOCOL = %(USE_PROXY_PROTOCOL)s ;LOCAL_USE_PROXY_PROTOCOL =
;; ;;
;; Disable SSH feature when not available ;; Disable SSH feature when not available
;DISABLE_SSH = false ;DISABLE_SSH = false
@ -146,13 +148,17 @@ RUN_USER = ; git
;SSH_SERVER_USE_PROXY_PROTOCOL = false ;SSH_SERVER_USE_PROXY_PROTOCOL = false
;; ;;
;; Username to use for the builtin SSH server. If blank, then it is the value of RUN_USER. ;; Username to use for the builtin SSH server. If blank, then it is the value of RUN_USER.
;BUILTIN_SSH_SERVER_USER = %(RUN_USER)s ;BUILTIN_SSH_SERVER_USER =
;; ;;
;; Domain name to be exposed in clone URL ;; Domain name to be exposed in clone URL, defaults to DOMAIN or the domain part of ROOT_URL
;SSH_DOMAIN = %(DOMAIN)s ;SSH_DOMAIN =
;; ;;
;; SSH username displayed in clone URLs. ;; SSH username displayed in clone URLs. It defaults to BUILTIN_SSH_SERVER_USER or RUN_USER.
;SSH_USER = %(BUILTIN_SSH_SERVER_USER)s ;; If it is set to "(DOER_USERNAME)", it will use current signed-in user's username.
;; This option is only for some advanced users who have configured their SSH reverse-proxy
;; and need to use different usernames for git SSH clone.
;; Most users should just leave it blank.
;SSH_USER =
;; ;;
;; The network interface the builtin SSH server should listen on ;; The network interface the builtin SSH server should listen on
;SSH_LISTEN_HOST = ;SSH_LISTEN_HOST =
@ -160,8 +166,8 @@ RUN_USER = ; git
;; Port number to be exposed in clone URL ;; Port number to be exposed in clone URL
;SSH_PORT = 22 ;SSH_PORT = 22
;; ;;
;; The port number the builtin SSH server should listen on ;; The port number the builtin SSH server should listen on, defaults to SSH_PORT
;SSH_LISTEN_PORT = %(SSH_PORT)s ;SSH_LISTEN_PORT =
;; ;;
;; Root path of SSH directory, default is '~/.ssh', but you have to use '/home/git/.ssh'. ;; Root path of SSH directory, default is '~/.ssh', but you have to use '/home/git/.ssh'.
;SSH_ROOT_PATH = ;SSH_ROOT_PATH =
@ -188,16 +194,9 @@ RUN_USER = ; git
;; ;;
;; For the built-in SSH server, choose the keypair to offer as the host key ;; For the built-in SSH server, choose the keypair to offer as the host key
;; The private key should be at SSH_SERVER_HOST_KEY and the public SSH_SERVER_HOST_KEY.pub ;; The private key should be at SSH_SERVER_HOST_KEY and the public SSH_SERVER_HOST_KEY.pub
;; relative paths are made absolute relative to the %(APP_DATA_PATH)s ;; relative paths are made absolute relative to the APP_DATA_PATH
;SSH_SERVER_HOST_KEYS=ssh/gitea.rsa, ssh/gogs.rsa ;SSH_SERVER_HOST_KEYS=ssh/gitea.rsa, ssh/gogs.rsa
;; ;;
;; Directory to create temporary files in when testing public keys using ssh-keygen,
;; default is the system temporary directory.
;SSH_KEY_TEST_PATH =
;;
;; Use `ssh-keygen` to parse public SSH keys. The value is passed to the shell. By default, Gitea does the parsing itself.
;SSH_KEYGEN_PATH =
;;
;; Enable SSH Authorized Key Backup when rewriting all keys, default is false ;; Enable SSH Authorized Key Backup when rewriting all keys, default is false
;SSH_AUTHORIZED_KEYS_BACKUP = false ;SSH_AUTHORIZED_KEYS_BACKUP = false
;; ;;
@ -288,6 +287,9 @@ RUN_USER = ; git
;; Default path for App data ;; Default path for App data
;APP_DATA_PATH = data ; relative paths will be made absolute with _`AppWorkPath`_ ;APP_DATA_PATH = data ; relative paths will be made absolute with _`AppWorkPath`_
;; ;;
;; Base path for App's temp files, leave empty to use the managed tmp directory in APP_DATA_PATH
;APP_TEMP_PATH =
;;
;; Enable gzip compression for runtime-generated content, static resources excluded ;; Enable gzip compression for runtime-generated content, static resources excluded
;ENABLE_GZIP = false ;ENABLE_GZIP = false
;; ;;
@ -582,7 +584,7 @@ ENABLED = true
[log] [log]
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Root path for the log files - defaults to %(GITEA_WORK_DIR)/log ;; Root path for the log files - defaults to "{AppWorkPath}/log"
;ROOT_PATH = ;ROOT_PATH =
;; ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@ -682,8 +684,8 @@ LEVEL = Info
;; The path of git executable. If empty, Gitea searches through the PATH environment. ;; The path of git executable. If empty, Gitea searches through the PATH environment.
;PATH = ;PATH =
;; ;;
;; The HOME directory for Git ;; The HOME directory for Git, defaults to "{APP_DATA_PATH}/home"
;HOME_PATH = %(APP_DATA_PATH)s/home ;HOME_PATH =
;; ;;
;; Disables highlight of added and removed changes ;; Disables highlight of added and removed changes
;DISABLE_DIFF_HIGHLIGHT = false ;DISABLE_DIFF_HIGHLIGHT = false
@ -774,6 +776,9 @@ LEVEL = Info
;ALLOW_ONLY_EXTERNAL_REGISTRATION = false ;ALLOW_ONLY_EXTERNAL_REGISTRATION = false
;; ;;
;; User must sign in to view anything. ;; User must sign in to view anything.
;; It could be set to "expensive" to block anonymous users accessing some pages which consume a lot of resources,
;; for example: block anonymous AI crawlers from accessing repo code pages.
;; The "expensive" mode is experimental and subject to change.
;REQUIRE_SIGNIN_VIEW = false ;REQUIRE_SIGNIN_VIEW = false
;; ;;
;; Mail notification ;; Mail notification
@ -784,10 +789,13 @@ LEVEL = Info
;; Please note that setting this to false will not disable OAuth Basic or Basic authentication using a token ;; Please note that setting this to false will not disable OAuth Basic or Basic authentication using a token
;ENABLE_BASIC_AUTHENTICATION = true ;ENABLE_BASIC_AUTHENTICATION = true
;; ;;
;; Show the password sign-in form (for password-based login), otherwise, only show OAuth2 login methods. ;; Show the password sign-in form (for password-based login), otherwise, only show OAuth2 or passkey login methods if they are enabled.
;; If you set it to false, maybe it also needs to set ENABLE_BASIC_AUTHENTICATION to false to completely disable password-based authentication. ;; If you set it to false, maybe it also needs to set ENABLE_BASIC_AUTHENTICATION to false to completely disable password-based authentication.
;ENABLE_PASSWORD_SIGNIN_FORM = true ;ENABLE_PASSWORD_SIGNIN_FORM = true
;; ;;
;; Allow users to sign-in with a passkey
;ENABLE_PASSKEY_AUTHENTICATION = true
;;
;; More detail: https://github.com/gogits/gogs/issues/165 ;; More detail: https://github.com/gogits/gogs/issues/165
;ENABLE_REVERSE_PROXY_AUTHENTICATION = false ;ENABLE_REVERSE_PROXY_AUTHENTICATION = false
; Enable this to allow reverse proxy authentication for API requests, the reverse proxy is responsible for ensuring that no CSRF is possible. ; Enable this to allow reverse proxy authentication for API requests, the reverse proxy is responsible for ensuring that no CSRF is possible.
@ -932,7 +940,29 @@ LEVEL = Info
;; ;;
;; Disable the code explore page. ;; Disable the code explore page.
;DISABLE_CODE_PAGE = false ;DISABLE_CODE_PAGE = false
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;[qos]
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ;;
;; Enable request quality of service and overload protection.
; ENABLED = false
;;
;; The maximum number of concurrent requests that the server will
;; process before enqueueing new requests. Default is "CpuNum * 4".
; MAX_INFLIGHT =
;;
;; The maximum number of requests that can be enqueued before new
;; requests will be dropped.
; MAX_WAITING = 100
;;
;; Target maximum wait time a request may be enqueued for. Requests
;; that are enqueued for less than this amount of time will not be
;; dropped. When wait times exceed this amount, a portion of requests
;; will be dropped until wait times have decreased below this amount.
; TARGET_WAIT_TIME = 250ms
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@ -946,8 +976,8 @@ LEVEL = Info
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;[repository] ;[repository]
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Root path for storing all repository data. By default, it is set to %(APP_DATA_PATH)s/gitea-repositories. ;; Root path for storing all repository data. By default, it is set to "{APP_DATA_PATH}/gitea-repositories".
;; A relative path is interpreted as _`AppWorkPath`_/%(ROOT)s ;; A relative path is interpreted as "{AppWorkPath}/{ROOT}" (use AppWorkPath as base path).
;ROOT = ;ROOT =
;; ;;
;; The script type this server supports. Usually this is `bash`, but some users report that only `sh` is available. ;; The script type this server supports. Usually this is `bash`, but some users report that only `sh` is available.
@ -1057,15 +1087,6 @@ LEVEL = Info
;; Separate extensions with a comma. To line wrap files without an extension, just put a comma ;; Separate extensions with a comma. To line wrap files without an extension, just put a comma
;LINE_WRAP_EXTENSIONS = .txt,.md,.markdown,.mdown,.mkd,.livemd, ;LINE_WRAP_EXTENSIONS = .txt,.md,.markdown,.mdown,.mkd,.livemd,
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;[repository.local]
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; Path for local repository copy. Defaults to `tmp/local-repo` (content gets deleted on gitea restart)
;LOCAL_COPY_PATH = tmp/local-repo
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;[repository.upload] ;[repository.upload]
@ -1075,9 +1096,6 @@ LEVEL = Info
;; Whether repository file uploads are enabled. Defaults to `true` ;; Whether repository file uploads are enabled. Defaults to `true`
;ENABLED = true ;ENABLED = true
;; ;;
;; Path for uploads. Defaults to `data/tmp/uploads` (content gets deleted on gitea restart)
;TEMP_PATH = data/tmp/uploads
;;
;; Comma-separated list of allowed file extensions (`.zip`), mime types (`text/plain`) or wildcard type (`image/*`, `audio/*`, `video/*`). Empty value or `*/*` allows all types. ;; Comma-separated list of allowed file extensions (`.zip`), mime types (`text/plain`) or wildcard type (`image/*`, `audio/*`, `video/*`). Empty value or `*/*` allows all types.
;ALLOWED_TYPES = ;ALLOWED_TYPES =
;; ;;
@ -1120,6 +1138,9 @@ LEVEL = Info
;; In default merge messages only include approvers who are official ;; In default merge messages only include approvers who are official
;DEFAULT_MERGE_MESSAGE_OFFICIAL_APPROVERS_ONLY = true ;DEFAULT_MERGE_MESSAGE_OFFICIAL_APPROVERS_ONLY = true
;; ;;
;; In default squash-merge messages include the commit message of all commits comprising the pull request.
;POPULATE_SQUASH_COMMENT_WITH_COMMIT_MESSAGES = false
;;
;; Add co-authored-by and co-committed-by trailers if committer does not match author ;; Add co-authored-by and co-committed-by trailers if committer does not match author
;ADD_CO_COMMITTER_TRAILERS = true ;ADD_CO_COMMITTER_TRAILERS = true
;; ;;
@ -1282,6 +1303,9 @@ LEVEL = Info
;; Leave it empty to allow users to select any theme from "{CustomPath}/public/assets/css/theme-*.css" ;; Leave it empty to allow users to select any theme from "{CustomPath}/public/assets/css/theme-*.css"
;THEMES = ;THEMES =
;; ;;
;; The icons for file list (basic/material), this is a temporary option which will be replaced by a user setting in the future.
;FILE_ICON_THEME = material
;;
;; All available reactions users can choose on issues/prs and comments. ;; All available reactions users can choose on issues/prs and comments.
;; Values can be emoji alias (:smile:) or a unicode emoji. ;; Values can be emoji alias (:smile:) or a unicode emoji.
;; For custom reactions, add a tightly cropped square image to public/assets/img/emoji/reaction_name.png ;; For custom reactions, add a tightly cropped square image to public/assets/img/emoji/reaction_name.png
@ -1339,6 +1363,9 @@ LEVEL = Info
;; Number of repos that are displayed on one page ;; Number of repos that are displayed on one page
;REPO_PAGING_NUM = 15 ;REPO_PAGING_NUM = 15
;; Number of orgs that are displayed on profile page
;ORG_PAGING_NUM = 15
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;[ui.meta] ;[ui.meta]
@ -1392,14 +1419,14 @@ LEVEL = Info
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ;;
;; Render soft line breaks as hard line breaks, which means a single newline character between ;; Customize render options for different contexts. Set to "none" to disable the defaults, or use comma separated list:
;; * short-issue-pattern: recognized "#123" issue reference and render it as a link to the issue
;; * new-line-hard-break: render soft line breaks as hard line breaks, which means a single newline character between
;; paragraphs will cause a line break and adding trailing whitespace to paragraphs is not ;; paragraphs will cause a line break and adding trailing whitespace to paragraphs is not
;; necessary to force a line break. ;; necessary to force a line break.
;; Render soft line breaks as hard line breaks for comments ;RENDER_OPTIONS_COMMENT = short-issue-pattern, new-line-hard-break
;ENABLE_HARD_LINE_BREAK_IN_COMMENTS = true ;RENDER_OPTIONS_WIKI = short-issue-pattern
;; ;RENDER_OPTIONS_REPO_FILE =
;; Render soft line breaks as hard line breaks for markdown documents
;ENABLE_HARD_LINE_BREAK_IN_DOCUMENTS = false
;; ;;
;; Comma separated list of custom URL-Schemes that are allowed as links when rendering Markdown ;; Comma separated list of custom URL-Schemes that are allowed as links when rendering Markdown
;; for example git,magnet,ftp (more at https://en.wikipedia.org/wiki/List_of_URI_schemes) ;; for example git,magnet,ftp (more at https://en.wikipedia.org/wiki/List_of_URI_schemes)
@ -1413,6 +1440,11 @@ LEVEL = Info
;; ;;
;; Enables math inline and block detection ;; Enables math inline and block detection
;ENABLE_MATH = true ;ENABLE_MATH = true
;;
;; Enable delimiters for math code block detection. Set to "none" to disable all,
;; or use comma separated list: inline-dollar, inline-parentheses, block-dollar, block-square-brackets
;; Defaults to "inline-dollar,block-dollar" to follow GitHub's behavior.
;MATH_CODE_BLOCK_DETECTION =
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@ -1482,6 +1514,10 @@ LEVEL = Info
;REPO_INDEXER_EXCLUDE = ;REPO_INDEXER_EXCLUDE =
;; ;;
;MAX_FILE_SIZE = 1048576 ;MAX_FILE_SIZE = 1048576
;;
;; Bleve engine has performance problems with fuzzy search, so we limit the fuzziness to 0 by default to disable it.
;; If you'd like to enable it, you can set it to a value between 0 and 2.
;TYPE_BLEVE_MAX_FUZZINESS = 0
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@ -1499,7 +1535,8 @@ LEVEL = Info
;TYPE = persistable-channel ;TYPE = persistable-channel
;; ;;
;; data-dir for storing persistable queues and level queues, individual queues will default to `queues/common` meaning the queue is shared. ;; data-dir for storing persistable queues and level queues, individual queues will default to `queues/common` meaning the queue is shared.
;DATADIR = queues/ ; Relative paths will be made absolute against `%(APP_DATA_PATH)s`. ;; Relative paths will be made absolute against "APP_DATA_PATH"
;DATADIR = queues/
;; ;;
;; Default queue length before a channel queue will block ;; Default queue length before a channel queue will block
;LENGTH = 100000 ;LENGTH = 100000
@ -1747,6 +1784,9 @@ LEVEL = Info
;; ;;
;; convert \r\n to \n for Sendmail ;; convert \r\n to \n for Sendmail
;SENDMAIL_CONVERT_CRLF = true ;SENDMAIL_CONVERT_CRLF = true
;;
;; convert links of attached images to inline images. Only for images hosted in this gitea instance.
;EMBED_ATTACHMENT_IMAGES = false
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@ -2438,7 +2478,7 @@ LEVEL = Info
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Set the maximum number of characters in a mermaid source. (Set to -1 to disable limits) ;; Set the maximum number of characters in a mermaid source. (Set to -1 to disable limits)
;MERMAID_MAX_SOURCE_CHARACTERS = 5000 ;MERMAID_MAX_SOURCE_CHARACTERS = 50000
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@ -2559,9 +2599,6 @@ LEVEL = Info
;; Currently, only `minio` and `azureblob` is supported. ;; Currently, only `minio` and `azureblob` is supported.
;SERVE_DIRECT = false ;SERVE_DIRECT = false
;; ;;
;; Path for chunked uploads. Defaults to APP_DATA_PATH + `tmp/package-upload`
;CHUNKED_UPLOAD_PATH = tmp/package-upload
;;
;; Maximum count of package versions a single owner can have (`-1` means no limits) ;; Maximum count of package versions a single owner can have (`-1` means no limits)
;LIMIT_TOTAL_OWNER_COUNT = -1 ;LIMIT_TOTAL_OWNER_COUNT = -1
;; Maximum size of packages a single owner can use (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`) ;; Maximum size of packages a single owner can use (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`)

View File

@ -22,3 +22,8 @@ manifests:
architecture: arm64 architecture: arm64
os: linux os: linux
variant: v8 variant: v8
-
image: gitea/gitea:{{#if build.tag}}{{trimPrefix "v" build.tag}}{{else}}{{#if (hasPrefix "refs/heads/release/v" build.ref)}}{{trimPrefix "refs/heads/release/v" build.ref}}-{{/if}}nightly{{/if}}-linux-riscv64-rootless
platform:
architecture: riscv64
os: linux

View File

@ -22,3 +22,8 @@ manifests:
architecture: arm64 architecture: arm64
os: linux os: linux
variant: v8 variant: v8
-
image: gitea/gitea:{{#if build.tag}}{{trimPrefix "v" build.tag}}{{else}}{{#if (hasPrefix "refs/heads/release/v" build.ref)}}{{trimPrefix "refs/heads/release/v" build.ref}}-{{/if}}nightly{{/if}}-linux-riscv64
platform:
architecture: riscv64
os: linux

View File

@ -31,6 +31,21 @@ if [ -e /data/ssh/ssh_host_ecdsa_cert ]; then
SSH_ECDSA_CERT=${SSH_ECDSA_CERT:-"/data/ssh/ssh_host_ecdsa_cert"} SSH_ECDSA_CERT=${SSH_ECDSA_CERT:-"/data/ssh/ssh_host_ecdsa_cert"}
fi fi
# In case someone wants to sign the `{keyname}.pub` key by `ssh-keygen -s ca -I identity ...` to
# make use of the ssh-key certificate authority feature (see ssh-keygen CERTIFICATES section),
# the generated key file name is `{keyname}-cert.pub`
if [ -e /data/ssh/ssh_host_ed25519_key-cert.pub ]; then
SSH_ED25519_CERT=${SSH_ED25519_CERT:-"/data/ssh/ssh_host_ed25519_key-cert.pub"}
fi
if [ -e /data/ssh/ssh_host_rsa_key-cert.pub ]; then
SSH_RSA_CERT=${SSH_RSA_CERT:-"/data/ssh/ssh_host_rsa_key-cert.pub"}
fi
if [ -e /data/ssh/ssh_host_ecdsa_key-cert.pub ]; then
SSH_ECDSA_CERT=${SSH_ECDSA_CERT:-"/data/ssh/ssh_host_ecdsa_key-cert.pub"}
fi
if [ -d /etc/ssh ]; then if [ -d /etc/ssh ]; then
SSH_PORT=${SSH_PORT:-"22"} \ SSH_PORT=${SSH_PORT:-"22"} \
SSH_LISTEN_PORT=${SSH_LISTEN_PORT:-"${SSH_PORT}"} \ SSH_LISTEN_PORT=${SSH_LISTEN_PORT:-"${SSH_PORT}"} \

View File

@ -37,5 +37,5 @@ done
if [ $# -gt 0 ]; then if [ $# -gt 0 ]; then
exec "$@" exec "$@"
else else
exec /bin/s6-svscan /etc/s6 exec /usr/bin/s6-svscan /etc/s6
fi fi

12
flake.lock generated
View File

@ -5,11 +5,11 @@
"systems": "systems" "systems": "systems"
}, },
"locked": { "locked": {
"lastModified": 1726560853, "lastModified": 1731533236,
"narHash": "sha256-X6rJYSESBVr3hBoH0WbKE5KvhPU5bloyZ2L4K60/fPQ=", "narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=",
"owner": "numtide", "owner": "numtide",
"repo": "flake-utils", "repo": "flake-utils",
"rev": "c1dfcf08411b08f6b8615f7d8971a2bfa81d5e8a", "rev": "11707dc2f618dd54ca8739b309ec4fc024de578b",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -20,11 +20,11 @@
}, },
"nixpkgs": { "nixpkgs": {
"locked": { "locked": {
"lastModified": 1731139594, "lastModified": 1739214665,
"narHash": "sha256-IigrKK3vYRpUu+HEjPL/phrfh7Ox881er1UEsZvw9Q4=", "narHash": "sha256-26L8VAu3/1YRxS8MHgBOyOM8xALdo6N0I04PgorE7UM=",
"owner": "nixos", "owner": "nixos",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "76612b17c0ce71689921ca12d9ffdc9c23ce40b2", "rev": "64e75cd44acf21c7933d61d7721e812eac1b5a0a",
"type": "github" "type": "github"
}, },
"original": { "original": {

View File

@ -29,9 +29,14 @@
poetry poetry
# backend # backend
go_1_24
gofumpt gofumpt
sqlite sqlite
]; ];
shellHook = ''
export GO="${pkgs.go_1_24}/bin/go"
export GOROOT="${pkgs.go_1_24}/share/go"
'';
}; };
} }
); );

225
go.mod
View File

@ -1,6 +1,6 @@
module code.gitea.io/gitea module code.gitea.io/gitea
go 1.23 go 1.24
// rfc5280 said: "The serial number is an integer assigned by the CA to each certificate." // rfc5280 said: "The serial number is an integer assigned by the CA to each certificate."
// But some CAs use negative serial number, just relax the check. related: // But some CAs use negative serial number, just relax the check. related:
@ -8,11 +8,11 @@ go 1.23
godebug x509negativeserial=1 godebug x509negativeserial=1
require ( require (
code.gitea.io/actions-proto-go v0.4.0 code.gitea.io/actions-proto-go v0.4.1
code.gitea.io/gitea-vet v0.2.3 code.gitea.io/gitea-vet v0.2.3
code.gitea.io/sdk/gitea v0.19.0 code.gitea.io/sdk/gitea v0.20.0
codeberg.org/gusted/mcaptcha v0.0.0-20220723083913-4f3072e1d570 codeberg.org/gusted/mcaptcha v0.0.0-20220723083913-4f3072e1d570
connectrpc.com/connect v1.17.0 connectrpc.com/connect v1.18.1
gitea.com/go-chi/binding v0.0.0-20240430071103-39a851e106ed gitea.com/go-chi/binding v0.0.0-20240430071103-39a851e106ed
gitea.com/go-chi/cache v0.2.1 gitea.com/go-chi/cache v0.2.1
gitea.com/go-chi/captcha v0.0.0-20240315150714-fb487f629098 gitea.com/go-chi/captcha v0.0.0-20240315150714-fb487f629098
@ -21,20 +21,20 @@ require (
gitea.com/lunny/levelqueue v0.4.2-0.20230414023320-3c0159fe0fe4 gitea.com/lunny/levelqueue v0.4.2-0.20230414023320-3c0159fe0fe4
github.com/42wim/httpsig v1.2.2 github.com/42wim/httpsig v1.2.2
github.com/42wim/sshsig v0.0.0-20240818000253-e3a6333df815 github.com/42wim/sshsig v0.0.0-20240818000253-e3a6333df815
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.16.0 github.com/Azure/azure-sdk-for-go/sdk/azcore v1.17.1
github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.4.1 github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.6.0
github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358
github.com/ProtonMail/go-crypto v1.0.0 github.com/ProtonMail/go-crypto v1.1.6
github.com/PuerkitoBio/goquery v1.10.0 github.com/PuerkitoBio/goquery v1.10.2
github.com/SaveTheRbtz/zstd-seekable-format-go/pkg v0.7.3 github.com/SaveTheRbtz/zstd-seekable-format-go/pkg v0.7.3
github.com/alecthomas/chroma/v2 v2.14.0 github.com/alecthomas/chroma/v2 v2.15.0
github.com/aws/aws-sdk-go v1.55.5 github.com/aws/aws-sdk-go-v2/credentials v1.17.62
github.com/aws/aws-sdk-go-v2/credentials v1.17.42 github.com/aws/aws-sdk-go-v2/service/codecommit v1.28.1
github.com/aws/aws-sdk-go-v2/service/codecommit v1.27.3
github.com/blakesmith/ar v0.0.0-20190502131153-809d4375e1fb github.com/blakesmith/ar v0.0.0-20190502131153-809d4375e1fb
github.com/blevesearch/bleve/v2 v2.4.2 github.com/blevesearch/bleve/v2 v2.4.2
github.com/buildkite/terminal-to-html/v3 v3.16.3 github.com/bohde/codel v0.2.0
github.com/caddyserver/certmagic v0.21.4 github.com/buildkite/terminal-to-html/v3 v3.16.8
github.com/caddyserver/certmagic v0.22.0
github.com/charmbracelet/git-lfs-transfer v0.2.0 github.com/charmbracelet/git-lfs-transfer v0.2.0
github.com/chi-middleware/proxy v1.1.1 github.com/chi-middleware/proxy v1.1.1
github.com/dimiro1/reply v0.0.0-20200315094148-d0136a4c9e21 github.com/dimiro1/reply v0.0.0-20200315094148-d0136a4c9e21
@ -42,38 +42,36 @@ require (
github.com/djherbis/nio/v3 v3.0.1 github.com/djherbis/nio/v3 v3.0.1
github.com/dsnet/compress v0.0.2-0.20210315054119-f66993602bf5 github.com/dsnet/compress v0.0.2-0.20210315054119-f66993602bf5
github.com/dustin/go-humanize v1.0.1 github.com/dustin/go-humanize v1.0.1
github.com/editorconfig/editorconfig-core-go/v2 v2.6.2 github.com/editorconfig/editorconfig-core-go/v2 v2.6.3
github.com/emersion/go-imap v1.2.1 github.com/emersion/go-imap v1.2.1
github.com/emirpasic/gods v1.18.1 github.com/emirpasic/gods v1.18.1
github.com/ethantkoenig/rupture v1.0.1 github.com/ethantkoenig/rupture v1.0.1
github.com/felixge/fgprof v0.9.5 github.com/felixge/fgprof v0.9.5
github.com/fsnotify/fsnotify v1.7.0 github.com/fsnotify/fsnotify v1.8.0
github.com/gliderlabs/ssh v0.3.8 github.com/gliderlabs/ssh v0.3.8
github.com/go-ap/activitypub v0.0.0-20240910141749-b4b8c8aa484c github.com/go-ap/activitypub v0.0.0-20250212090640-aeb6499ba581
github.com/go-ap/jsonld v0.0.0-20221030091449-f2a191312c73 github.com/go-ap/jsonld v0.0.0-20221030091449-f2a191312c73
github.com/go-chi/chi/v5 v5.1.0 github.com/go-chi/chi/v5 v5.2.1
github.com/go-chi/cors v1.2.1 github.com/go-chi/cors v1.2.1
github.com/go-co-op/gocron v1.37.0 github.com/go-co-op/gocron v1.37.0
github.com/go-enry/go-enry/v2 v2.9.1 github.com/go-enry/go-enry/v2 v2.9.2
github.com/go-git/go-billy/v5 v5.6.0 github.com/go-git/go-billy/v5 v5.6.2
github.com/go-git/go-git/v5 v5.12.0 github.com/go-git/go-git/v5 v5.14.0
github.com/go-ldap/ldap/v3 v3.4.8 github.com/go-ldap/ldap/v3 v3.4.10
github.com/go-redsync/redsync/v4 v4.13.0 github.com/go-redsync/redsync/v4 v4.13.0
github.com/go-sql-driver/mysql v1.8.1 github.com/go-sql-driver/mysql v1.9.1
github.com/go-swagger/go-swagger v0.31.0 github.com/go-swagger/go-swagger v0.31.0
github.com/go-testfixtures/testfixtures/v3 v3.11.0 github.com/go-webauthn/webauthn v0.12.2
github.com/go-webauthn/webauthn v0.11.2
github.com/gobwas/glob v0.2.3 github.com/gobwas/glob v0.2.3
github.com/gogs/chardet v0.0.0-20211120154057-b7413eaefb8f github.com/gogs/chardet v0.0.0-20211120154057-b7413eaefb8f
github.com/gogs/go-gogs-client v0.0.0-20210131175652-1d7215cd8d85 github.com/gogs/go-gogs-client v0.0.0-20210131175652-1d7215cd8d85
github.com/golang-jwt/jwt/v5 v5.2.1 github.com/golang-jwt/jwt/v5 v5.2.2
github.com/google/go-github/v61 v61.0.0 github.com/google/go-github/v61 v61.0.0
github.com/google/licenseclassifier/v2 v2.0.0 github.com/google/licenseclassifier/v2 v2.0.0
github.com/google/pprof v0.0.0-20241029153458-d1b30febd7db github.com/google/pprof v0.0.0-20250317173921-a4b03ec1a45e
github.com/google/uuid v1.6.0 github.com/google/uuid v1.6.0
github.com/gorilla/feeds v1.2.0 github.com/gorilla/feeds v1.2.0
github.com/gorilla/sessions v1.4.0 github.com/gorilla/sessions v1.4.0
github.com/h2non/gock v1.2.0
github.com/hashicorp/go-version v1.7.0 github.com/hashicorp/go-version v1.7.0
github.com/hashicorp/golang-lru/v2 v2.0.7 github.com/hashicorp/golang-lru/v2 v2.0.7
github.com/huandu/xstrings v1.5.0 github.com/huandu/xstrings v1.5.0
@ -81,96 +79,93 @@ require (
github.com/jhillyerd/enmime v1.3.0 github.com/jhillyerd/enmime v1.3.0
github.com/json-iterator/go v1.1.12 github.com/json-iterator/go v1.1.12
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51
github.com/keybase/go-crypto v0.0.0-20200123153347-de78d2cb44f4 github.com/klauspost/compress v1.18.0
github.com/klauspost/compress v1.17.11 github.com/klauspost/cpuid/v2 v2.2.10
github.com/klauspost/cpuid/v2 v2.2.8
github.com/lib/pq v1.10.9 github.com/lib/pq v1.10.9
github.com/markbates/goth v1.80.0 github.com/markbates/goth v1.80.0
github.com/mattn/go-isatty v0.0.20 github.com/mattn/go-isatty v0.0.20
github.com/mattn/go-sqlite3 v1.14.24 github.com/mattn/go-sqlite3 v1.14.24
github.com/meilisearch/meilisearch-go v0.29.1-0.20241106140435-0bf60fad690a github.com/meilisearch/meilisearch-go v0.31.0
github.com/mholt/archiver/v3 v3.5.1 github.com/mholt/archiver/v3 v3.5.1
github.com/microcosm-cc/bluemonday v1.0.27 github.com/microcosm-cc/bluemonday v1.0.27
github.com/microsoft/go-mssqldb v1.7.2 github.com/microsoft/go-mssqldb v1.8.0
github.com/minio/minio-go/v7 v7.0.80 github.com/minio/minio-go/v7 v7.0.88
github.com/msteinert/pam v1.2.0 github.com/msteinert/pam v1.2.0
github.com/nektos/act v0.2.63 github.com/nektos/act v0.2.63
github.com/niklasfasching/go-org v1.7.0 github.com/niklasfasching/go-org v1.7.0
github.com/olivere/elastic/v7 v7.0.32 github.com/olivere/elastic/v7 v7.0.32
github.com/opencontainers/go-digest v1.0.0 github.com/opencontainers/go-digest v1.0.0
github.com/opencontainers/image-spec v1.1.0 github.com/opencontainers/image-spec v1.1.1
github.com/pkg/errors v0.9.1 github.com/pkg/errors v0.9.1
github.com/pquerna/otp v1.4.0 github.com/pquerna/otp v1.4.0
github.com/prometheus/client_golang v1.20.5 github.com/prometheus/client_golang v1.21.1
github.com/quasoft/websspi v1.1.2 github.com/quasoft/websspi v1.1.2
github.com/redis/go-redis/v9 v9.7.0 github.com/redis/go-redis/v9 v9.7.3
github.com/robfig/cron/v3 v3.0.1 github.com/robfig/cron/v3 v3.0.1
github.com/santhosh-tekuri/jsonschema/v5 v5.3.1 github.com/santhosh-tekuri/jsonschema/v5 v5.3.1
github.com/sassoftware/go-rpmutils v0.4.0 github.com/sassoftware/go-rpmutils v0.4.0
github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3
github.com/shurcooL/vfsgen v0.0.0-20230704071429-0000e147ea92 github.com/shurcooL/vfsgen v0.0.0-20230704071429-0000e147ea92
github.com/stretchr/testify v1.9.0 github.com/stretchr/testify v1.10.0
github.com/syndtr/goleveldb v1.0.0 github.com/syndtr/goleveldb v1.0.0
github.com/tstranex/u2f v1.0.0 github.com/tstranex/u2f v1.0.0
github.com/ulikunitz/xz v0.5.12 github.com/ulikunitz/xz v0.5.12
github.com/urfave/cli/v2 v2.27.5 github.com/urfave/cli/v2 v2.27.6
github.com/wneessen/go-mail v0.5.2 github.com/wneessen/go-mail v0.6.2
github.com/xanzy/go-gitlab v0.112.0
github.com/xeipuuv/gojsonschema v1.2.0 github.com/xeipuuv/gojsonschema v1.2.0
github.com/yohcop/openid-go v1.0.1 github.com/yohcop/openid-go v1.0.1
github.com/yuin/goldmark v1.7.8 github.com/yuin/goldmark v1.7.8
github.com/yuin/goldmark-highlighting/v2 v2.0.0-20230729083705-37449abec8cc github.com/yuin/goldmark-highlighting/v2 v2.0.0-20230729083705-37449abec8cc
github.com/yuin/goldmark-meta v1.1.0 github.com/yuin/goldmark-meta v1.1.0
golang.org/x/crypto v0.31.0 gitlab.com/gitlab-org/api/client-go v0.126.0
golang.org/x/image v0.21.0 golang.org/x/crypto v0.36.0
golang.org/x/net v0.30.0 golang.org/x/image v0.25.0
golang.org/x/oauth2 v0.23.0 golang.org/x/net v0.38.0
golang.org/x/sync v0.10.0 golang.org/x/oauth2 v0.28.0
golang.org/x/sys v0.28.0 golang.org/x/sync v0.12.0
golang.org/x/text v0.21.0 golang.org/x/sys v0.31.0
golang.org/x/tools v0.26.0 golang.org/x/text v0.23.0
google.golang.org/grpc v1.67.1 golang.org/x/tools v0.31.0
google.golang.org/protobuf v1.35.1 google.golang.org/grpc v1.71.0
google.golang.org/protobuf v1.36.5
gopkg.in/ini.v1 v1.67.0 gopkg.in/ini.v1 v1.67.0
gopkg.in/yaml.v3 v3.0.1 gopkg.in/yaml.v3 v3.0.1
mvdan.cc/xurls/v2 v2.5.0 mvdan.cc/xurls/v2 v2.6.0
strk.kbt.io/projects/go/libravatar v0.0.0-20191008002943-06d1c002b251 strk.kbt.io/projects/go/libravatar v0.0.0-20191008002943-06d1c002b251
xorm.io/builder v0.3.13 xorm.io/builder v0.3.13
xorm.io/xorm v1.3.9 xorm.io/xorm v1.3.9
) )
require ( require (
cloud.google.com/go/compute/metadata v0.5.2 // indirect cloud.google.com/go/compute/metadata v0.6.0 // indirect
dario.cat/mergo v1.0.1 // indirect dario.cat/mergo v1.0.1 // indirect
filippo.io/edwards25519 v1.1.0 // indirect filippo.io/edwards25519 v1.1.0 // indirect
git.sr.ht/~mariusor/go-xsd-duration v0.0.0-20220703122237-02e73435a078 // indirect git.sr.ht/~mariusor/go-xsd-duration v0.0.0-20220703122237-02e73435a078 // indirect
github.com/Azure/azure-sdk-for-go/sdk/internal v1.10.0 // indirect github.com/Azure/azure-sdk-for-go/sdk/internal v1.10.0 // indirect
github.com/ClickHouse/ch-go v0.63.1 // indirect
github.com/ClickHouse/clickhouse-go/v2 v2.24.0 // indirect
github.com/DataDog/zstd v1.5.6 // indirect github.com/DataDog/zstd v1.5.6 // indirect
github.com/Masterminds/goutils v1.1.1 // indirect github.com/Masterminds/goutils v1.1.1 // indirect
github.com/Masterminds/semver/v3 v3.3.0 // indirect github.com/Masterminds/semver/v3 v3.3.1 // indirect
github.com/Masterminds/sprig/v3 v3.3.0 // indirect github.com/Masterminds/sprig/v3 v3.3.0 // indirect
github.com/Microsoft/go-winio v0.6.2 // indirect github.com/Microsoft/go-winio v0.6.2 // indirect
github.com/RoaringBitmap/roaring v1.9.4 // indirect github.com/RoaringBitmap/roaring v1.9.4 // indirect
github.com/andybalholm/brotli v1.1.1 // indirect github.com/andybalholm/brotli v1.1.1 // indirect
github.com/andybalholm/cascadia v1.3.2 // indirect github.com/andybalholm/cascadia v1.3.3 // indirect
github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be // indirect github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be // indirect
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect
github.com/aws/aws-sdk-go-v2 v1.32.3 // indirect github.com/aws/aws-sdk-go-v2 v1.36.3 // indirect
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.22 // indirect github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.34 // indirect
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.22 // indirect github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.34 // indirect
github.com/aws/smithy-go v1.22.0 // indirect github.com/aws/smithy-go v1.22.3 // indirect
github.com/aymerick/douceur v0.2.0 // indirect github.com/aymerick/douceur v0.2.0 // indirect
github.com/beorn7/perks v1.0.1 // indirect github.com/beorn7/perks v1.0.1 // indirect
github.com/bits-and-blooms/bitset v1.14.3 // indirect github.com/bits-and-blooms/bitset v1.22.0 // indirect
github.com/blevesearch/bleve_index_api v1.1.12 // indirect github.com/blevesearch/bleve_index_api v1.1.12 // indirect
github.com/blevesearch/geo v0.1.20 // indirect github.com/blevesearch/geo v0.1.20 // indirect
github.com/blevesearch/go-faiss v1.0.23 // indirect github.com/blevesearch/go-faiss v1.0.20 // indirect
github.com/blevesearch/go-porterstemmer v1.0.3 // indirect github.com/blevesearch/go-porterstemmer v1.0.3 // indirect
github.com/blevesearch/gtreap v0.1.1 // indirect github.com/blevesearch/gtreap v0.1.1 // indirect
github.com/blevesearch/mmap-go v1.0.4 // indirect github.com/blevesearch/mmap-go v1.0.4 // indirect
github.com/blevesearch/scorch_segment_api/v2 v2.2.16 // indirect github.com/blevesearch/scorch_segment_api/v2 v2.2.15 // indirect
github.com/blevesearch/segment v0.9.1 // indirect github.com/blevesearch/segment v0.9.1 // indirect
github.com/blevesearch/snowballstem v0.9.0 // indirect github.com/blevesearch/snowballstem v0.9.0 // indirect
github.com/blevesearch/upsidedown_store_api v1.0.2 // indirect github.com/blevesearch/upsidedown_store_api v1.0.2 // indirect
@ -179,69 +174,68 @@ require (
github.com/blevesearch/zapx/v12 v12.3.10 // indirect github.com/blevesearch/zapx/v12 v12.3.10 // indirect
github.com/blevesearch/zapx/v13 v13.3.10 // indirect github.com/blevesearch/zapx/v13 v13.3.10 // indirect
github.com/blevesearch/zapx/v14 v14.3.10 // indirect github.com/blevesearch/zapx/v14 v14.3.10 // indirect
github.com/blevesearch/zapx/v15 v15.3.16 // indirect github.com/blevesearch/zapx/v15 v15.3.13 // indirect
github.com/blevesearch/zapx/v16 v16.1.7 // indirect github.com/blevesearch/zapx/v16 v16.1.5 // indirect
github.com/bmatcuk/doublestar/v4 v4.8.1 // indirect
github.com/boombuler/barcode v1.0.2 // indirect github.com/boombuler/barcode v1.0.2 // indirect
github.com/bradfitz/gomemcache v0.0.0-20230905024940-24af94b03874 // indirect github.com/bradfitz/gomemcache v0.0.0-20230905024940-24af94b03874 // indirect
github.com/caddyserver/zerossl v0.1.3 // indirect github.com/caddyserver/zerossl v0.1.3 // indirect
github.com/cention-sany/utf7 v0.0.0-20170124080048-26cad61bd60a // indirect github.com/cention-sany/utf7 v0.0.0-20170124080048-26cad61bd60a // indirect
github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect
github.com/cloudflare/circl v1.5.0 // indirect github.com/cloudflare/circl v1.6.0 // indirect
github.com/couchbase/go-couchbase v0.1.1 // indirect github.com/couchbase/go-couchbase v0.1.1 // indirect
github.com/couchbase/gomemcached v0.3.2 // indirect github.com/couchbase/gomemcached v0.3.3 // indirect
github.com/couchbase/goutils v0.1.2 // indirect github.com/couchbase/goutils v0.1.2 // indirect
github.com/cpuguy83/go-md2man/v2 v2.0.5 // indirect github.com/cpuguy83/go-md2man/v2 v2.0.6 // indirect
github.com/cyphar/filepath-securejoin v0.3.4 // indirect github.com/cyphar/filepath-securejoin v0.4.1 // indirect
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
github.com/davidmz/go-pageant v1.0.2 // indirect github.com/davidmz/go-pageant v1.0.2 // indirect
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
github.com/dlclark/regexp2 v1.11.4 // indirect github.com/dlclark/regexp2 v1.11.5 // indirect
github.com/emersion/go-sasl v0.0.0-20241020182733-b788ff22d5a6 // indirect github.com/emersion/go-sasl v0.0.0-20241020182733-b788ff22d5a6 // indirect
github.com/fatih/color v1.18.0 // indirect github.com/fatih/color v1.18.0 // indirect
github.com/felixge/httpsnoop v1.0.4 // indirect github.com/felixge/httpsnoop v1.0.4 // indirect
github.com/fxamacker/cbor/v2 v2.7.0 // indirect github.com/fxamacker/cbor/v2 v2.7.0 // indirect
github.com/git-lfs/pktline v0.0.0-20230103162542-ca444d533ef1 // indirect github.com/git-lfs/pktline v0.0.0-20230103162542-ca444d533ef1 // indirect
github.com/go-ap/errors v0.0.0-20240910140019-1e9d33cc1568 // indirect github.com/go-ap/errors v0.0.0-20250124135319-3da8adefd4a9 // indirect
github.com/go-asn1-ber/asn1-ber v1.5.7 // indirect github.com/go-asn1-ber/asn1-ber v1.5.7 // indirect
github.com/go-enry/go-oniguruma v1.2.1 // indirect github.com/go-enry/go-oniguruma v1.2.1 // indirect
github.com/go-faster/city v1.0.1 // indirect
github.com/go-faster/errors v0.7.1 // indirect
github.com/go-fed/httpsig v1.1.1-0.20201223112313-55836744818e // indirect github.com/go-fed/httpsig v1.1.1-0.20201223112313-55836744818e // indirect
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect
github.com/go-ini/ini v1.67.0 // indirect github.com/go-ini/ini v1.67.0 // indirect
github.com/go-openapi/analysis v0.23.0 // indirect github.com/go-openapi/analysis v0.23.0 // indirect
github.com/go-openapi/errors v0.22.0 // indirect github.com/go-openapi/errors v0.22.1 // indirect
github.com/go-openapi/inflect v0.21.0 // indirect github.com/go-openapi/inflect v0.21.2 // indirect
github.com/go-openapi/jsonpointer v0.21.0 // indirect github.com/go-openapi/jsonpointer v0.21.1 // indirect
github.com/go-openapi/jsonreference v0.21.0 // indirect github.com/go-openapi/jsonreference v0.21.0 // indirect
github.com/go-openapi/loads v0.22.0 // indirect github.com/go-openapi/loads v0.22.0 // indirect
github.com/go-openapi/runtime v0.28.0 // indirect github.com/go-openapi/runtime v0.28.0 // indirect
github.com/go-openapi/spec v0.21.0 // indirect github.com/go-openapi/spec v0.21.0 // indirect
github.com/go-openapi/strfmt v0.23.0 // indirect github.com/go-openapi/strfmt v0.23.0 // indirect
github.com/go-openapi/swag v0.23.0 // indirect github.com/go-openapi/swag v0.23.1 // indirect
github.com/go-openapi/validate v0.24.0 // indirect github.com/go-openapi/validate v0.24.0 // indirect
github.com/go-webauthn/x v0.1.15 // indirect github.com/go-viper/mapstructure/v2 v2.2.1 // indirect
github.com/goccy/go-json v0.10.3 // indirect github.com/go-webauthn/x v0.1.19 // indirect
github.com/golang-jwt/jwt/v4 v4.5.1 // indirect github.com/goccy/go-json v0.10.5 // indirect
github.com/golang-jwt/jwt/v4 v4.5.2 // indirect
github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9 // indirect github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9 // indirect
github.com/golang-sql/sqlexp v0.1.0 // indirect github.com/golang-sql/sqlexp v0.1.0 // indirect
github.com/golang/geo v0.0.0-20230421003525-6adc56603217 // indirect github.com/golang/geo v0.0.0-20250321002858-2bb09a976f49 // indirect
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 // indirect
github.com/golang/protobuf v1.5.4 // indirect github.com/golang/protobuf v1.5.4 // indirect
github.com/golang/snappy v0.0.4 // indirect github.com/golang/snappy v1.0.0 // indirect
github.com/google/btree v1.1.3 // indirect github.com/google/btree v1.1.3 // indirect
github.com/google/flatbuffers v25.2.10+incompatible // indirect
github.com/google/go-querystring v1.1.0 // indirect github.com/google/go-querystring v1.1.0 // indirect
github.com/google/go-tpm v0.9.1 // indirect github.com/google/go-tpm v0.9.3 // indirect
github.com/gorilla/css v1.0.1 // indirect github.com/gorilla/css v1.0.1 // indirect
github.com/gorilla/handlers v1.5.2 // indirect github.com/gorilla/handlers v1.5.2 // indirect
github.com/gorilla/mux v1.8.1 // indirect github.com/gorilla/mux v1.8.1 // indirect
github.com/gorilla/securecookie v1.1.2 // indirect github.com/gorilla/securecookie v1.1.2 // indirect
github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542 // indirect
github.com/hashicorp/errwrap v1.1.0 // indirect github.com/hashicorp/errwrap v1.1.0 // indirect
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
github.com/hashicorp/go-multierror v1.1.1 // indirect github.com/hashicorp/go-multierror v1.1.1 // indirect
github.com/hashicorp/go-retryablehttp v0.7.7 // indirect github.com/hashicorp/go-retryablehttp v0.7.7 // indirect
github.com/hashicorp/hcl v1.0.0 // indirect
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect
github.com/jessevdk/go-flags v1.6.1 // indirect github.com/jessevdk/go-flags v1.6.1 // indirect
github.com/josharian/intern v1.0.0 // indirect github.com/josharian/intern v1.0.0 // indirect
@ -249,14 +243,15 @@ require (
github.com/klauspost/pgzip v1.2.6 // indirect github.com/klauspost/pgzip v1.2.6 // indirect
github.com/kr/pretty v0.3.1 // indirect github.com/kr/pretty v0.3.1 // indirect
github.com/kr/text v0.2.0 // indirect github.com/kr/text v0.2.0 // indirect
github.com/libdns/libdns v0.2.2 // indirect github.com/libdns/libdns v0.2.3 // indirect
github.com/magiconair/properties v1.8.7 // indirect github.com/mailru/easyjson v0.9.0 // indirect
github.com/mailru/easyjson v0.7.7 // indirect
github.com/markbates/going v1.0.3 // indirect github.com/markbates/going v1.0.3 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-colorable v0.1.14 // indirect
github.com/mattn/go-runewidth v0.0.16 // indirect github.com/mattn/go-runewidth v0.0.16 // indirect
github.com/mholt/acmez/v2 v2.0.3 // indirect github.com/mattn/go-shellwords v1.0.12 // indirect
github.com/miekg/dns v1.1.62 // indirect github.com/mholt/acmez/v3 v3.1.0 // indirect
github.com/miekg/dns v1.1.64 // indirect
github.com/minio/crc64nvme v1.0.1 // indirect
github.com/minio/md5-simd v1.1.2 // indirect github.com/minio/md5-simd v1.1.2 // indirect
github.com/mitchellh/copystructure v1.2.0 // indirect github.com/mitchellh/copystructure v1.2.0 // indirect
github.com/mitchellh/mapstructure v1.5.0 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect
@ -270,31 +265,28 @@ require (
github.com/oklog/ulid v1.3.1 // indirect github.com/oklog/ulid v1.3.1 // indirect
github.com/olekukonko/tablewriter v0.0.5 // indirect github.com/olekukonko/tablewriter v0.0.5 // indirect
github.com/onsi/ginkgo v1.16.5 // indirect github.com/onsi/ginkgo v1.16.5 // indirect
github.com/paulmach/orb v0.11.1 // indirect
github.com/pelletier/go-toml/v2 v2.2.3 // indirect github.com/pelletier/go-toml/v2 v2.2.3 // indirect
github.com/pierrec/lz4/v4 v4.1.21 // indirect github.com/pierrec/lz4/v4 v4.1.22 // indirect
github.com/pjbgf/sha1cd v0.3.0 // indirect github.com/pjbgf/sha1cd v0.3.2 // indirect
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
github.com/prometheus/client_model v0.6.1 // indirect github.com/prometheus/client_model v0.6.1 // indirect
github.com/prometheus/common v0.60.1 // indirect github.com/prometheus/common v0.63.0 // indirect
github.com/prometheus/procfs v0.15.1 // indirect github.com/prometheus/procfs v0.16.0 // indirect
github.com/rhysd/actionlint v1.7.3 // indirect github.com/rhysd/actionlint v1.7.7 // indirect
github.com/rivo/uniseg v0.4.7 // indirect github.com/rivo/uniseg v0.4.7 // indirect
github.com/rogpeppe/go-internal v1.13.1 // indirect github.com/rogpeppe/go-internal v1.14.1 // indirect
github.com/rs/xid v1.6.0 // indirect github.com/rs/xid v1.6.0 // indirect
github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect
github.com/sagikazarmark/locafero v0.6.0 // indirect github.com/sagikazarmark/locafero v0.8.0 // indirect
github.com/sagikazarmark/slog-shim v0.1.0 // indirect
github.com/segmentio/asm v1.2.0 // indirect
github.com/shopspring/decimal v1.4.0 // indirect github.com/shopspring/decimal v1.4.0 // indirect
github.com/shurcooL/httpfs v0.0.0-20230704072500-f1e31cf0ba5c // indirect github.com/shurcooL/httpfs v0.0.0-20230704072500-f1e31cf0ba5c // indirect
github.com/sirupsen/logrus v1.9.3 // indirect github.com/sirupsen/logrus v1.9.3 // indirect
github.com/skeema/knownhosts v1.3.0 // indirect github.com/skeema/knownhosts v1.3.1 // indirect
github.com/sourcegraph/conc v0.3.0 // indirect github.com/sourcegraph/conc v0.3.0 // indirect
github.com/spf13/afero v1.11.0 // indirect github.com/spf13/afero v1.14.0 // indirect
github.com/spf13/cast v1.7.0 // indirect github.com/spf13/cast v1.7.1 // indirect
github.com/spf13/pflag v1.0.5 // indirect github.com/spf13/pflag v1.0.6 // indirect
github.com/spf13/viper v1.19.0 // indirect github.com/spf13/viper v1.20.0 // indirect
github.com/ssor/bom v0.0.0-20170718123548-6386211fdfcf // indirect github.com/ssor/bom v0.0.0-20170718123548-6386211fdfcf // indirect
github.com/subosito/gotenv v1.6.0 // indirect github.com/subosito/gotenv v1.6.0 // indirect
github.com/toqueteos/webbrowser v1.2.0 // indirect github.com/toqueteos/webbrowser v1.2.0 // indirect
@ -308,17 +300,16 @@ require (
github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 // indirect github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 // indirect
github.com/zeebo/assert v1.3.0 // indirect github.com/zeebo/assert v1.3.0 // indirect
github.com/zeebo/blake3 v0.2.4 // indirect github.com/zeebo/blake3 v0.2.4 // indirect
go.etcd.io/bbolt v1.3.11 // indirect go.etcd.io/bbolt v1.4.0 // indirect
go.mongodb.org/mongo-driver v1.17.1 // indirect go.mongodb.org/mongo-driver v1.17.3 // indirect
go.opentelemetry.io/otel v1.31.0 // indirect
go.opentelemetry.io/otel/trace v1.31.0 // indirect
go.uber.org/atomic v1.11.0 // indirect go.uber.org/atomic v1.11.0 // indirect
go.uber.org/multierr v1.11.0 // indirect go.uber.org/multierr v1.11.0 // indirect
go.uber.org/zap v1.27.0 // indirect go.uber.org/zap v1.27.0 // indirect
golang.org/x/exp v0.0.0-20241009180824-f66d83c29e7c // indirect go.uber.org/zap/exp v0.3.0 // indirect
golang.org/x/mod v0.21.0 // indirect golang.org/x/exp v0.0.0-20250305212735-054e65f0b394 // indirect
golang.org/x/time v0.7.0 // indirect golang.org/x/mod v0.24.0 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20241021214115-324edc3d5d38 // indirect golang.org/x/time v0.11.0 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20250313205543-e70fdf4c4cb4 // indirect
gopkg.in/warnings.v0 v0.1.2 // indirect gopkg.in/warnings.v0 v0.1.2 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect
) )
@ -327,7 +318,7 @@ replace github.com/hashicorp/go-version => github.com/6543/go-version v1.3.1
replace github.com/shurcooL/vfsgen => github.com/lunny/vfsgen v0.0.0-20220105142115-2c99e1ffdfa0 replace github.com/shurcooL/vfsgen => github.com/lunny/vfsgen v0.0.0-20220105142115-2c99e1ffdfa0
replace github.com/nektos/act => gitea.com/gitea/act v0.261.3 replace github.com/nektos/act => gitea.com/gitea/act v0.261.4
// TODO: the only difference is in `PutObject`: the fork doesn't use `NewVerifyingReader(r, sha256.New(), oid, expectedSize)`, need to figure out why // TODO: the only difference is in `PutObject`: the fork doesn't use `NewVerifyingReader(r, sha256.New(), oid, expectedSize)`, need to figure out why
replace github.com/charmbracelet/git-lfs-transfer => gitea.com/gitea/git-lfs-transfer v0.2.0 replace github.com/charmbracelet/git-lfs-transfer => gitea.com/gitea/git-lfs-transfer v0.2.0

548
go.sum

File diff suppressed because it is too large Load Diff

16
main_timezones.go Normal file
View File

@ -0,0 +1,16 @@
// Copyright 2025 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
//go:build windows
package main
// Golang has the ability to load OS's timezone data from most UNIX systems (https://github.com/golang/go/blob/master/src/time/zoneinfo_unix.go)
// Even if the timezone data is missing, users could install the related packages to get it.
// But on Windows, although `zoneinfo_windows.go` tries to load the timezone data from Windows registry,
// some users still suffer from the issue that the timezone data is missing: https://github.com/go-gitea/gitea/issues/33235
// So we import the tzdata package to make sure the timezone data is included in the binary.
//
// For non-Windows package builders, they could still use the "TAGS=timetzdata" to include the tzdata package in the binary.
// If we decided to add the tzdata for other platforms, modify the "go:build" directive above.
import _ "time/tzdata"

View File

@ -48,7 +48,7 @@ type ActionArtifact struct {
ContentEncoding string // The content encoding of the artifact ContentEncoding string // The content encoding of the artifact
ArtifactPath string `xorm:"index unique(runid_name_path)"` // The path to the artifact when runner uploads it ArtifactPath string `xorm:"index unique(runid_name_path)"` // The path to the artifact when runner uploads it
ArtifactName string `xorm:"index unique(runid_name_path)"` // The name of the artifact when runner uploads it ArtifactName string `xorm:"index unique(runid_name_path)"` // The name of the artifact when runner uploads it
Status int64 `xorm:"index"` // The status of the artifact, uploading, expired or need-delete Status ArtifactStatus `xorm:"index"` // The status of the artifact, uploading, expired or need-delete
CreatedUnix timeutil.TimeStamp `xorm:"created"` CreatedUnix timeutil.TimeStamp `xorm:"created"`
UpdatedUnix timeutil.TimeStamp `xorm:"updated index"` UpdatedUnix timeutil.TimeStamp `xorm:"updated index"`
ExpiredUnix timeutil.TimeStamp `xorm:"index"` // The time when the artifact will be expired ExpiredUnix timeutil.TimeStamp `xorm:"index"` // The time when the artifact will be expired
@ -68,7 +68,7 @@ func CreateArtifact(ctx context.Context, t *ActionTask, artifactName, artifactPa
RepoID: t.RepoID, RepoID: t.RepoID,
OwnerID: t.OwnerID, OwnerID: t.OwnerID,
CommitSHA: t.CommitSHA, CommitSHA: t.CommitSHA,
Status: int64(ArtifactStatusUploadPending), Status: ArtifactStatusUploadPending,
ExpiredUnix: timeutil.TimeStamp(time.Now().Unix() + timeutil.Day*expiredDays), ExpiredUnix: timeutil.TimeStamp(time.Now().Unix() + timeutil.Day*expiredDays),
} }
if _, err := db.GetEngine(ctx).Insert(artifact); err != nil { if _, err := db.GetEngine(ctx).Insert(artifact); err != nil {
@ -112,8 +112,15 @@ type FindArtifactsOptions struct {
RunID int64 RunID int64
ArtifactName string ArtifactName string
Status int Status int
FinalizedArtifactsV4 bool
} }
func (opts FindArtifactsOptions) ToOrders() string {
return "id"
}
var _ db.FindOptionsOrder = (*FindArtifactsOptions)(nil)
func (opts FindArtifactsOptions) ToConds() builder.Cond { func (opts FindArtifactsOptions) ToConds() builder.Cond {
cond := builder.NewCond() cond := builder.NewCond()
if opts.RepoID > 0 { if opts.RepoID > 0 {
@ -128,11 +135,15 @@ func (opts FindArtifactsOptions) ToConds() builder.Cond {
if opts.Status > 0 { if opts.Status > 0 {
cond = cond.And(builder.Eq{"status": opts.Status}) cond = cond.And(builder.Eq{"status": opts.Status})
} }
if opts.FinalizedArtifactsV4 {
cond = cond.And(builder.Eq{"status": ArtifactStatusUploadConfirmed}.Or(builder.Eq{"status": ArtifactStatusExpired}))
cond = cond.And(builder.Eq{"content_encoding": "application/zip"})
}
return cond return cond
} }
// ActionArtifactMeta is the meta data of an artifact // ActionArtifactMeta is the meta-data of an artifact
type ActionArtifactMeta struct { type ActionArtifactMeta struct {
ArtifactName string ArtifactName string
FileSize int64 FileSize int64
@ -166,18 +177,18 @@ func ListPendingDeleteArtifacts(ctx context.Context, limit int) ([]*ActionArtifa
// SetArtifactExpired sets an artifact to expired // SetArtifactExpired sets an artifact to expired
func SetArtifactExpired(ctx context.Context, artifactID int64) error { func SetArtifactExpired(ctx context.Context, artifactID int64) error {
_, err := db.GetEngine(ctx).Where("id=? AND status = ?", artifactID, ArtifactStatusUploadConfirmed).Cols("status").Update(&ActionArtifact{Status: int64(ArtifactStatusExpired)}) _, err := db.GetEngine(ctx).Where("id=? AND status = ?", artifactID, ArtifactStatusUploadConfirmed).Cols("status").Update(&ActionArtifact{Status: ArtifactStatusExpired})
return err return err
} }
// SetArtifactNeedDelete sets an artifact to need-delete, cron job will delete it // SetArtifactNeedDelete sets an artifact to need-delete, cron job will delete it
func SetArtifactNeedDelete(ctx context.Context, runID int64, name string) error { func SetArtifactNeedDelete(ctx context.Context, runID int64, name string) error {
_, err := db.GetEngine(ctx).Where("run_id=? AND artifact_name=? AND status = ?", runID, name, ArtifactStatusUploadConfirmed).Cols("status").Update(&ActionArtifact{Status: int64(ArtifactStatusPendingDeletion)}) _, err := db.GetEngine(ctx).Where("run_id=? AND artifact_name=? AND status = ?", runID, name, ArtifactStatusUploadConfirmed).Cols("status").Update(&ActionArtifact{Status: ArtifactStatusPendingDeletion})
return err return err
} }
// SetArtifactDeleted sets an artifact to deleted // SetArtifactDeleted sets an artifact to deleted
func SetArtifactDeleted(ctx context.Context, artifactID int64) error { func SetArtifactDeleted(ctx context.Context, artifactID int64) error {
_, err := db.GetEngine(ctx).ID(artifactID).Cols("status").Update(&ActionArtifact{Status: int64(ArtifactStatusDeleted)}) _, err := db.GetEngine(ctx).ID(artifactID).Cols("status").Update(&ActionArtifact{Status: ArtifactStatusDeleted})
return err return err
} }

View File

@ -5,6 +5,7 @@ package actions
import ( import (
"context" "context"
"errors"
"fmt" "fmt"
"slices" "slices"
"strings" "strings"
@ -88,7 +89,7 @@ func (run *ActionRun) RefLink() string {
if refName.IsPull() { if refName.IsPull() {
return run.Repo.Link() + "/pulls/" + refName.ShortName() return run.Repo.Link() + "/pulls/" + refName.ShortName()
} }
return git.RefURL(run.Repo.Link(), run.Ref) return run.Repo.Link() + "/src/" + refName.RefWebLinkPath()
} }
// PrettyRef return #id for pull ref or ShortName for others // PrettyRef return #id for pull ref or ShortName for others
@ -154,7 +155,7 @@ func (run *ActionRun) GetPushEventPayload() (*api.PushPayload, error) {
} }
func (run *ActionRun) GetPullRequestEventPayload() (*api.PullRequestPayload, error) { func (run *ActionRun) GetPullRequestEventPayload() (*api.PullRequestPayload, error) {
if run.Event == webhook_module.HookEventPullRequest || run.Event == webhook_module.HookEventPullRequestSync { if run.Event.IsPullRequest() {
var payload api.PullRequestPayload var payload api.PullRequestPayload
if err := json.Unmarshal([]byte(run.EventPayload), &payload); err != nil { if err := json.Unmarshal([]byte(run.EventPayload), &payload); err != nil {
return nil, err return nil, err
@ -194,7 +195,7 @@ func updateRepoRunsNumbers(ctx context.Context, repo *repo_model.Repository) err
// CancelPreviousJobs cancels all previous jobs of the same repository, reference, workflow, and event. // CancelPreviousJobs cancels all previous jobs of the same repository, reference, workflow, and event.
// It's useful when a new run is triggered, and all previous runs needn't be continued anymore. // It's useful when a new run is triggered, and all previous runs needn't be continued anymore.
func CancelPreviousJobs(ctx context.Context, repoID int64, ref, workflowID string, event webhook_module.HookEventType) error { func CancelPreviousJobs(ctx context.Context, repoID int64, ref, workflowID string, event webhook_module.HookEventType) ([]*ActionRunJob, error) {
// Find all runs in the specified repository, reference, and workflow with non-final status // Find all runs in the specified repository, reference, and workflow with non-final status
runs, total, err := db.FindAndCount[ActionRun](ctx, FindRunOptions{ runs, total, err := db.FindAndCount[ActionRun](ctx, FindRunOptions{
RepoID: repoID, RepoID: repoID,
@ -204,14 +205,16 @@ func CancelPreviousJobs(ctx context.Context, repoID int64, ref, workflowID strin
Status: []Status{StatusRunning, StatusWaiting, StatusBlocked}, Status: []Status{StatusRunning, StatusWaiting, StatusBlocked},
}) })
if err != nil { if err != nil {
return err return nil, err
} }
// If there are no runs found, there's no need to proceed with cancellation, so return nil. // If there are no runs found, there's no need to proceed with cancellation, so return nil.
if total == 0 { if total == 0 {
return nil return nil, nil
} }
cancelledJobs := make([]*ActionRunJob, 0, total)
// Iterate over each found run and cancel its associated jobs. // Iterate over each found run and cancel its associated jobs.
for _, run := range runs { for _, run := range runs {
// Find all jobs associated with the current run. // Find all jobs associated with the current run.
@ -219,7 +222,7 @@ func CancelPreviousJobs(ctx context.Context, repoID int64, ref, workflowID strin
RunID: run.ID, RunID: run.ID,
}) })
if err != nil { if err != nil {
return err return cancelledJobs, err
} }
// Iterate over each job and attempt to cancel it. // Iterate over each job and attempt to cancel it.
@ -238,27 +241,29 @@ func CancelPreviousJobs(ctx context.Context, repoID int64, ref, workflowID strin
// Update the job's status and stopped time in the database. // Update the job's status and stopped time in the database.
n, err := UpdateRunJob(ctx, job, builder.Eq{"task_id": 0}, "status", "stopped") n, err := UpdateRunJob(ctx, job, builder.Eq{"task_id": 0}, "status", "stopped")
if err != nil { if err != nil {
return err return cancelledJobs, err
} }
// If the update affected 0 rows, it means the job has changed in the meantime, so we need to try again. // If the update affected 0 rows, it means the job has changed in the meantime, so we need to try again.
if n == 0 { if n == 0 {
return fmt.Errorf("job has changed, try again") return cancelledJobs, errors.New("job has changed, try again")
} }
cancelledJobs = append(cancelledJobs, job)
// Continue with the next job. // Continue with the next job.
continue continue
} }
// If the job has an associated task, try to stop the task, effectively cancelling the job. // If the job has an associated task, try to stop the task, effectively cancelling the job.
if err := StopTask(ctx, job.TaskID, StatusCancelled); err != nil { if err := StopTask(ctx, job.TaskID, StatusCancelled); err != nil {
return err return cancelledJobs, err
} }
cancelledJobs = append(cancelledJobs, job)
} }
} }
// Return nil to indicate successful cancellation of all running and waiting jobs. // Return nil to indicate successful cancellation of all running and waiting jobs.
return nil return cancelledJobs, nil
} }
// InsertRun inserts a run // InsertRun inserts a run
@ -275,7 +280,7 @@ func InsertRun(ctx context.Context, run *ActionRun, jobs []*jobparser.SingleWork
return err return err
} }
run.Index = index run.Index = index
run.Title, _ = util.SplitStringAtByteN(run.Title, 255) run.Title = util.EllipsisDisplayString(run.Title, 255)
if err := db.Insert(ctx, run); err != nil { if err := db.Insert(ctx, run); err != nil {
return err return err
@ -308,7 +313,7 @@ func InsertRun(ctx context.Context, run *ActionRun, jobs []*jobparser.SingleWork
} else { } else {
hasWaiting = true hasWaiting = true
} }
job.Name, _ = util.SplitStringAtByteN(job.Name, 255) job.Name = util.EllipsisDisplayString(job.Name, 255)
runJobs = append(runJobs, &ActionRunJob{ runJobs = append(runJobs, &ActionRunJob{
RunID: run.ID, RunID: run.ID,
RepoID: run.RepoID, RepoID: run.RepoID,
@ -402,13 +407,13 @@ func UpdateRun(ctx context.Context, run *ActionRun, cols ...string) error {
if len(cols) > 0 { if len(cols) > 0 {
sess.Cols(cols...) sess.Cols(cols...)
} }
run.Title, _ = util.SplitStringAtByteN(run.Title, 255) run.Title = util.EllipsisDisplayString(run.Title, 255)
affected, err := sess.Update(run) affected, err := sess.Update(run)
if err != nil { if err != nil {
return err return err
} }
if affected == 0 { if affected == 0 {
return fmt.Errorf("run has changed") return errors.New("run has changed")
// It's impossible that the run is not found, since Gitea never deletes runs. // It's impossible that the run is not found, since Gitea never deletes runs.
} }

View File

@ -10,6 +10,7 @@ import (
"time" "time"
"code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/db"
repo_model "code.gitea.io/gitea/models/repo"
"code.gitea.io/gitea/modules/timeutil" "code.gitea.io/gitea/modules/timeutil"
"code.gitea.io/gitea/modules/util" "code.gitea.io/gitea/modules/util"
@ -22,6 +23,7 @@ type ActionRunJob struct {
RunID int64 `xorm:"index"` RunID int64 `xorm:"index"`
Run *ActionRun `xorm:"-"` Run *ActionRun `xorm:"-"`
RepoID int64 `xorm:"index"` RepoID int64 `xorm:"index"`
Repo *repo_model.Repository `xorm:"-"`
OwnerID int64 `xorm:"index"` OwnerID int64 `xorm:"index"`
CommitSHA string `xorm:"index"` CommitSHA string `xorm:"index"`
IsForkPullRequest bool IsForkPullRequest bool
@ -58,6 +60,17 @@ func (job *ActionRunJob) LoadRun(ctx context.Context) error {
return nil return nil
} }
func (job *ActionRunJob) LoadRepo(ctx context.Context) error {
if job.Repo == nil {
repo, err := repo_model.GetRepositoryByID(ctx, job.RepoID)
if err != nil {
return err
}
job.Repo = repo
}
return nil
}
// LoadAttributes load Run if not loaded // LoadAttributes load Run if not loaded
func (job *ActionRunJob) LoadAttributes(ctx context.Context) error { func (job *ActionRunJob) LoadAttributes(ctx context.Context) error {
if job == nil { if job == nil {
@ -83,7 +96,7 @@ func GetRunJobByID(ctx context.Context, id int64) (*ActionRunJob, error) {
return &job, nil return &job, nil
} }
func GetRunJobsByRunID(ctx context.Context, runID int64) ([]*ActionRunJob, error) { func GetRunJobsByRunID(ctx context.Context, runID int64) (ActionJobList, error) {
var jobs []*ActionRunJob var jobs []*ActionRunJob
if err := db.GetEngine(ctx).Where("run_id=?", runID).OrderBy("id").Find(&jobs); err != nil { if err := db.GetEngine(ctx).Where("run_id=?", runID).OrderBy("id").Find(&jobs); err != nil {
return nil, err return nil, err

View File

@ -7,6 +7,7 @@ import (
"context" "context"
"code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/db"
repo_model "code.gitea.io/gitea/models/repo"
"code.gitea.io/gitea/modules/container" "code.gitea.io/gitea/modules/container"
"code.gitea.io/gitea/modules/timeutil" "code.gitea.io/gitea/modules/timeutil"
@ -21,7 +22,33 @@ func (jobs ActionJobList) GetRunIDs() []int64 {
}) })
} }
func (jobs ActionJobList) LoadRepos(ctx context.Context) error {
repoIDs := container.FilterSlice(jobs, func(j *ActionRunJob) (int64, bool) {
return j.RepoID, j.RepoID != 0 && j.Repo == nil
})
if len(repoIDs) == 0 {
return nil
}
repos := make(map[int64]*repo_model.Repository, len(repoIDs))
if err := db.GetEngine(ctx).In("id", repoIDs).Find(&repos); err != nil {
return err
}
for _, j := range jobs {
if j.RepoID > 0 && j.Repo == nil {
j.Repo = repos[j.RepoID]
}
}
return nil
}
func (jobs ActionJobList) LoadRuns(ctx context.Context, withRepo bool) error { func (jobs ActionJobList) LoadRuns(ctx context.Context, withRepo bool) error {
if withRepo {
if err := jobs.LoadRepos(ctx); err != nil {
return err
}
}
runIDs := jobs.GetRunIDs() runIDs := jobs.GetRunIDs()
runs := make(map[int64]*ActionRun, len(runIDs)) runs := make(map[int64]*ActionRun, len(runIDs))
if err := db.GetEngine(ctx).In("id", runIDs).Find(&runs); err != nil { if err := db.GetEngine(ctx).In("id", runIDs).Find(&runs); err != nil {
@ -30,15 +57,9 @@ func (jobs ActionJobList) LoadRuns(ctx context.Context, withRepo bool) error {
for _, j := range jobs { for _, j := range jobs {
if j.RunID > 0 && j.Run == nil { if j.RunID > 0 && j.Run == nil {
j.Run = runs[j.RunID] j.Run = runs[j.RunID]
j.Run.Repo = j.Repo
} }
} }
if withRepo {
var runsList RunList = make([]*ActionRun, 0, len(runs))
for _, r := range runs {
runsList = append(runsList, r)
}
return runsList.LoadRepos(ctx)
}
return nil return nil
} }

View File

@ -69,7 +69,7 @@ func TestAggregateJobStatus(t *testing.T) {
{[]Status{StatusFailure, StatusBlocked}, StatusFailure}, {[]Status{StatusFailure, StatusBlocked}, StatusFailure},
// skipped with other status // skipped with other status
// TODO: need to clarify whether a PR with "skipped" job status is considered as "mergeable" or not. // "all skipped" is also considered as "mergeable" by "services/actions.toCommitStatus", the same as GitHub
{[]Status{StatusSkipped}, StatusSkipped}, {[]Status{StatusSkipped}, StatusSkipped},
{[]Status{StatusSkipped, StatusSuccess}, StatusSuccess}, {[]Status{StatusSkipped, StatusSuccess}, StatusSuccess},
{[]Status{StatusSkipped, StatusFailure}, StatusFailure}, {[]Status{StatusSkipped, StatusFailure}, StatusFailure},

View File

@ -10,6 +10,7 @@ import (
repo_model "code.gitea.io/gitea/models/repo" repo_model "code.gitea.io/gitea/models/repo"
user_model "code.gitea.io/gitea/models/user" user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/container" "code.gitea.io/gitea/modules/container"
"code.gitea.io/gitea/modules/translation"
webhook_module "code.gitea.io/gitea/modules/webhook" webhook_module "code.gitea.io/gitea/modules/webhook"
"xorm.io/builder" "xorm.io/builder"
@ -112,14 +113,14 @@ type StatusInfo struct {
} }
// GetStatusInfoList returns a slice of StatusInfo // GetStatusInfoList returns a slice of StatusInfo
func GetStatusInfoList(ctx context.Context) []StatusInfo { func GetStatusInfoList(ctx context.Context, lang translation.Locale) []StatusInfo {
// same as those in aggregateJobStatus // same as those in aggregateJobStatus
allStatus := []Status{StatusSuccess, StatusFailure, StatusWaiting, StatusRunning} allStatus := []Status{StatusSuccess, StatusFailure, StatusWaiting, StatusRunning}
statusInfoList := make([]StatusInfo, 0, 4) statusInfoList := make([]StatusInfo, 0, 4)
for _, s := range allStatus { for _, s := range allStatus {
statusInfoList = append(statusInfoList, StatusInfo{ statusInfoList = append(statusInfoList, StatusInfo{
Status: int(s), Status: int(s),
DisplayedStatus: s.String(), DisplayedStatus: s.LocaleString(lang),
}) })
} }
return statusInfoList return statusInfoList

View File

@ -14,6 +14,7 @@ import (
"code.gitea.io/gitea/models/shared/types" "code.gitea.io/gitea/models/shared/types"
user_model "code.gitea.io/gitea/models/user" user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/optional" "code.gitea.io/gitea/modules/optional"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/timeutil" "code.gitea.io/gitea/modules/timeutil"
"code.gitea.io/gitea/modules/translation" "code.gitea.io/gitea/modules/translation"
"code.gitea.io/gitea/modules/util" "code.gitea.io/gitea/modules/util"
@ -57,6 +58,8 @@ type ActionRunner struct {
// Store labels defined in state file (default: .runner file) of `act_runner` // Store labels defined in state file (default: .runner file) of `act_runner`
AgentLabels []string `xorm:"TEXT"` AgentLabels []string `xorm:"TEXT"`
// Store if this is a runner that only ever get one single job assigned
Ephemeral bool `xorm:"ephemeral NOT NULL DEFAULT false"`
Created timeutil.TimeStamp `xorm:"created"` Created timeutil.TimeStamp `xorm:"created"`
Updated timeutil.TimeStamp `xorm:"updated"` Updated timeutil.TimeStamp `xorm:"updated"`
@ -84,9 +87,10 @@ func (r *ActionRunner) BelongsToOwnerType() types.OwnerType {
return types.OwnerTypeRepository return types.OwnerTypeRepository
} }
if r.OwnerID != 0 { if r.OwnerID != 0 {
if r.Owner.Type == user_model.UserTypeOrganization { switch r.Owner.Type {
case user_model.UserTypeOrganization:
return types.OwnerTypeOrganization return types.OwnerTypeOrganization
} else if r.Owner.Type == user_model.UserTypeIndividual { case user_model.UserTypeIndividual:
return types.OwnerTypeIndividual return types.OwnerTypeIndividual
} }
} }
@ -120,8 +124,15 @@ func (r *ActionRunner) IsOnline() bool {
return false return false
} }
// Editable checks if the runner is editable by the user // EditableInContext checks if the runner is editable by the "context" owner/repo
func (r *ActionRunner) Editable(ownerID, repoID int64) bool { // ownerID == 0 and repoID == 0 means "admin" context, any runner including global runners could be edited
// ownerID == 0 and repoID != 0 means "repo" context, any runner belonging to the given repo could be edited
// ownerID != 0 and repoID == 0 means "owner(org/user)" context, any runner belonging to the given user/org could be edited
// ownerID != 0 and repoID != 0 means "owner" OR "repo" context, legacy behavior, but we should forbid using it
func (r *ActionRunner) EditableInContext(ownerID, repoID int64) bool {
if ownerID != 0 && repoID != 0 {
setting.PanicInDevOrTesting("ownerID and repoID should not be both set")
}
if ownerID == 0 && repoID == 0 { if ownerID == 0 && repoID == 0 {
return true return true
} }
@ -165,8 +176,15 @@ func init() {
db.RegisterModel(&ActionRunner{}) db.RegisterModel(&ActionRunner{})
} }
// FindRunnerOptions
// ownerID == 0 and repoID == 0 means any runner including global runners
// repoID != 0 and WithAvailable == false means any runner for the given repo
// repoID != 0 and WithAvailable == true means any runner for the given repo, parent user/org, and global runners
// ownerID != 0 and repoID == 0 and WithAvailable == false means any runner for the given user/org
// ownerID != 0 and repoID == 0 and WithAvailable == true means any runner for the given user/org and global runners
type FindRunnerOptions struct { type FindRunnerOptions struct {
db.ListOptions db.ListOptions
IDs []int64
RepoID int64 RepoID int64
OwnerID int64 // it will be ignored if RepoID is set OwnerID int64 // it will be ignored if RepoID is set
Sort string Sort string
@ -178,6 +196,14 @@ type FindRunnerOptions struct {
func (opts FindRunnerOptions) ToConds() builder.Cond { func (opts FindRunnerOptions) ToConds() builder.Cond {
cond := builder.NewCond() cond := builder.NewCond()
if len(opts.IDs) > 0 {
if len(opts.IDs) == 1 {
cond = cond.And(builder.Eq{"id": opts.IDs[0]})
} else {
cond = cond.And(builder.In("id", opts.IDs))
}
}
if opts.RepoID > 0 { if opts.RepoID > 0 {
c := builder.NewCond().And(builder.Eq{"repo_id": opts.RepoID}) c := builder.NewCond().And(builder.Eq{"repo_id": opts.RepoID})
if opts.WithAvailable { if opts.WithAvailable {
@ -252,7 +278,7 @@ func GetRunnerByID(ctx context.Context, id int64) (*ActionRunner, error) {
// UpdateRunner updates runner's information. // UpdateRunner updates runner's information.
func UpdateRunner(ctx context.Context, r *ActionRunner, cols ...string) error { func UpdateRunner(ctx context.Context, r *ActionRunner, cols ...string) error {
e := db.GetEngine(ctx) e := db.GetEngine(ctx)
r.Name, _ = util.SplitStringAtByteN(r.Name, 255) r.Name = util.EllipsisDisplayString(r.Name, 255)
var err error var err error
if len(cols) == 0 { if len(cols) == 0 {
_, err = e.ID(r.ID).AllCols().Update(r) _, err = e.ID(r.ID).AllCols().Update(r)
@ -279,7 +305,7 @@ func CreateRunner(ctx context.Context, t *ActionRunner) error {
// Remove OwnerID to avoid confusion; it's not worth returning an error here. // Remove OwnerID to avoid confusion; it's not worth returning an error here.
t.OwnerID = 0 t.OwnerID = 0
} }
t.Name, _ = util.SplitStringAtByteN(t.Name, 255) t.Name = util.EllipsisDisplayString(t.Name, 255)
return db.Insert(ctx, t) return db.Insert(ctx, t)
} }
@ -328,3 +354,17 @@ func FixRunnersWithoutBelongingRepo(ctx context.Context) (int64, error) {
} }
return res.RowsAffected() return res.RowsAffected()
} }
func CountWrongRepoLevelRunners(ctx context.Context) (int64, error) {
var result int64
_, err := db.GetEngine(ctx).SQL("SELECT count(`id`) FROM `action_runner` WHERE `repo_id` > 0 AND `owner_id` > 0").Get(&result)
return result, err
}
func UpdateWrongRepoLevelRunners(ctx context.Context) (int64, error) {
result, err := db.GetEngine(ctx).Exec("UPDATE `action_runner` SET `owner_id` = 0 WHERE `repo_id` > 0 AND `owner_id` > 0")
if err != nil {
return 0, err
}
return result.RowsAffected()
}

View File

@ -51,7 +51,7 @@ func GetRunnerToken(ctx context.Context, token string) (*ActionRunnerToken, erro
if err != nil { if err != nil {
return nil, err return nil, err
} else if !has { } else if !has {
return nil, fmt.Errorf("runner token %q: %w", token, util.ErrNotExist) return nil, fmt.Errorf(`runner token "%s...": %w`, util.TruncateRunes(token, 3), util.ErrNotExist)
} }
return &runnerToken, nil return &runnerToken, nil
} }
@ -68,19 +68,15 @@ func UpdateRunnerToken(ctx context.Context, r *ActionRunnerToken, cols ...string
return err return err
} }
// NewRunnerToken creates a new active runner token and invalidate all old tokens // NewRunnerTokenWithValue creates a new active runner token and invalidate all old tokens
// ownerID will be ignored and treated as 0 if repoID is non-zero. // ownerID will be ignored and treated as 0 if repoID is non-zero.
func NewRunnerToken(ctx context.Context, ownerID, repoID int64) (*ActionRunnerToken, error) { func NewRunnerTokenWithValue(ctx context.Context, ownerID, repoID int64, token string) (*ActionRunnerToken, error) {
if ownerID != 0 && repoID != 0 { if ownerID != 0 && repoID != 0 {
// It's trying to create a runner token that belongs to a repository, but OwnerID has been set accidentally. // It's trying to create a runner token that belongs to a repository, but OwnerID has been set accidentally.
// Remove OwnerID to avoid confusion; it's not worth returning an error here. // Remove OwnerID to avoid confusion; it's not worth returning an error here.
ownerID = 0 ownerID = 0
} }
token, err := util.CryptoRandomString(40)
if err != nil {
return nil, err
}
runnerToken := &ActionRunnerToken{ runnerToken := &ActionRunnerToken{
OwnerID: ownerID, OwnerID: ownerID,
RepoID: repoID, RepoID: repoID,
@ -95,11 +91,19 @@ func NewRunnerToken(ctx context.Context, ownerID, repoID int64) (*ActionRunnerTo
return err return err
} }
_, err = db.GetEngine(ctx).Insert(runnerToken) _, err := db.GetEngine(ctx).Insert(runnerToken)
return err return err
}) })
} }
func NewRunnerToken(ctx context.Context, ownerID, repoID int64) (*ActionRunnerToken, error) {
token, err := util.CryptoRandomString(40)
if err != nil {
return nil, err
}
return NewRunnerTokenWithValue(ctx, ownerID, repoID, token)
}
// GetLatestRunnerToken returns the latest runner token // GetLatestRunnerToken returns the latest runner token
func GetLatestRunnerToken(ctx context.Context, ownerID, repoID int64) (*ActionRunnerToken, error) { func GetLatestRunnerToken(ctx context.Context, ownerID, repoID int64) (*ActionRunnerToken, error) {
if ownerID != 0 && repoID != 0 { if ownerID != 0 && repoID != 0 {

View File

@ -17,7 +17,7 @@ func TestGetLatestRunnerToken(t *testing.T) {
token := unittest.AssertExistsAndLoadBean(t, &ActionRunnerToken{ID: 3}) token := unittest.AssertExistsAndLoadBean(t, &ActionRunnerToken{ID: 3})
expectedToken, err := GetLatestRunnerToken(db.DefaultContext, 1, 0) expectedToken, err := GetLatestRunnerToken(db.DefaultContext, 1, 0)
assert.NoError(t, err) assert.NoError(t, err)
assert.EqualValues(t, expectedToken, token) assert.Equal(t, expectedToken, token)
} }
func TestNewRunnerToken(t *testing.T) { func TestNewRunnerToken(t *testing.T) {
@ -26,7 +26,7 @@ func TestNewRunnerToken(t *testing.T) {
assert.NoError(t, err) assert.NoError(t, err)
expectedToken, err := GetLatestRunnerToken(db.DefaultContext, 1, 0) expectedToken, err := GetLatestRunnerToken(db.DefaultContext, 1, 0)
assert.NoError(t, err) assert.NoError(t, err)
assert.EqualValues(t, expectedToken, token) assert.Equal(t, expectedToken, token)
} }
func TestUpdateRunnerToken(t *testing.T) { func TestUpdateRunnerToken(t *testing.T) {
@ -36,5 +36,5 @@ func TestUpdateRunnerToken(t *testing.T) {
assert.NoError(t, UpdateRunnerToken(db.DefaultContext, token)) assert.NoError(t, UpdateRunnerToken(db.DefaultContext, token))
expectedToken, err := GetLatestRunnerToken(db.DefaultContext, 1, 0) expectedToken, err := GetLatestRunnerToken(db.DefaultContext, 1, 0)
assert.NoError(t, err) assert.NoError(t, err)
assert.EqualValues(t, expectedToken, token) assert.Equal(t, expectedToken, token)
} }

View File

@ -43,15 +43,12 @@ func init() {
// GetSchedulesMapByIDs returns the schedules by given id slice. // GetSchedulesMapByIDs returns the schedules by given id slice.
func GetSchedulesMapByIDs(ctx context.Context, ids []int64) (map[int64]*ActionSchedule, error) { func GetSchedulesMapByIDs(ctx context.Context, ids []int64) (map[int64]*ActionSchedule, error) {
schedules := make(map[int64]*ActionSchedule, len(ids)) schedules := make(map[int64]*ActionSchedule, len(ids))
if len(ids) == 0 {
return schedules, nil
}
return schedules, db.GetEngine(ctx).In("id", ids).Find(&schedules) return schedules, db.GetEngine(ctx).In("id", ids).Find(&schedules)
} }
// GetReposMapByIDs returns the repos by given id slice.
func GetReposMapByIDs(ctx context.Context, ids []int64) (map[int64]*repo_model.Repository, error) {
repos := make(map[int64]*repo_model.Repository, len(ids))
return repos, db.GetEngine(ctx).In("id", ids).Find(&repos)
}
// CreateScheduleTask creates new schedule task. // CreateScheduleTask creates new schedule task.
func CreateScheduleTask(ctx context.Context, rows []*ActionSchedule) error { func CreateScheduleTask(ctx context.Context, rows []*ActionSchedule) error {
// Return early if there are no rows to insert // Return early if there are no rows to insert
@ -68,7 +65,7 @@ func CreateScheduleTask(ctx context.Context, rows []*ActionSchedule) error {
// Loop through each schedule row // Loop through each schedule row
for _, row := range rows { for _, row := range rows {
row.Title, _ = util.SplitStringAtByteN(row.Title, 255) row.Title = util.EllipsisDisplayString(row.Title, 255)
// Create new schedule row // Create new schedule row
if err = db.Insert(ctx, row); err != nil { if err = db.Insert(ctx, row); err != nil {
return err return err
@ -120,21 +117,22 @@ func DeleteScheduleTaskByRepo(ctx context.Context, id int64) error {
return committer.Commit() return committer.Commit()
} }
func CleanRepoScheduleTasks(ctx context.Context, repo *repo_model.Repository) error { func CleanRepoScheduleTasks(ctx context.Context, repo *repo_model.Repository) ([]*ActionRunJob, error) {
// If actions disabled when there is schedule task, this will remove the outdated schedule tasks // If actions disabled when there is schedule task, this will remove the outdated schedule tasks
// There is no other place we can do this because the app.ini will be changed manually // There is no other place we can do this because the app.ini will be changed manually
if err := DeleteScheduleTaskByRepo(ctx, repo.ID); err != nil { if err := DeleteScheduleTaskByRepo(ctx, repo.ID); err != nil {
return fmt.Errorf("DeleteCronTaskByRepo: %v", err) return nil, fmt.Errorf("DeleteCronTaskByRepo: %v", err)
} }
// cancel running cron jobs of this repository and delete old schedules // cancel running cron jobs of this repository and delete old schedules
if err := CancelPreviousJobs( jobs, err := CancelPreviousJobs(
ctx, ctx,
repo.ID, repo.ID,
repo.DefaultBranch, repo.DefaultBranch,
"", "",
webhook_module.HookEventSchedule, webhook_module.HookEventSchedule,
); err != nil { )
return fmt.Errorf("CancelPreviousJobs: %v", err) if err != nil {
return jobs, fmt.Errorf("CancelPreviousJobs: %v", err)
} }
return nil return jobs, nil
} }

View File

@ -32,7 +32,7 @@ func (specs SpecList) LoadSchedules(ctx context.Context) error {
} }
repoIDs := specs.GetRepoIDs() repoIDs := specs.GetRepoIDs()
repos, err := GetReposMapByIDs(ctx, repoIDs) repos, err := repo_model.GetRepositoriesMapByIDs(ctx, repoIDs)
if err != nil { if err != nil {
return err return err
} }

View File

@ -6,6 +6,7 @@ package actions
import ( import (
"context" "context"
"crypto/subtle" "crypto/subtle"
"errors"
"fmt" "fmt"
"time" "time"
@ -298,7 +299,7 @@ func CreateTaskForRunner(ctx context.Context, runner *ActionRunner) (*ActionTask
if len(workflowJob.Steps) > 0 { if len(workflowJob.Steps) > 0 {
steps := make([]*ActionTaskStep, len(workflowJob.Steps)) steps := make([]*ActionTaskStep, len(workflowJob.Steps))
for i, v := range workflowJob.Steps { for i, v := range workflowJob.Steps {
name, _ := util.SplitStringAtByteN(v.String(), 255) name := util.EllipsisDisplayString(v.String(), 255)
steps[i] = &ActionTaskStep{ steps[i] = &ActionTaskStep{
Name: name, Name: name,
TaskID: task.ID, TaskID: task.ID,
@ -361,7 +362,7 @@ func UpdateTaskByState(ctx context.Context, runnerID int64, state *runnerv1.Task
} else if !has { } else if !has {
return nil, util.ErrNotExist return nil, util.ErrNotExist
} else if runnerID != task.RunnerID { } else if runnerID != task.RunnerID {
return nil, fmt.Errorf("invalid runner for task") return nil, errors.New("invalid runner for task")
} }
if task.Status.IsDone() { if task.Status.IsDone() {

View File

@ -6,10 +6,12 @@ package actions
import ( import (
"context" "context"
"strings" "strings"
"unicode/utf8"
"code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/timeutil" "code.gitea.io/gitea/modules/timeutil"
"code.gitea.io/gitea/modules/util"
"xorm.io/builder" "xorm.io/builder"
) )
@ -32,32 +34,46 @@ type ActionVariable struct {
RepoID int64 `xorm:"INDEX UNIQUE(owner_repo_name)"` RepoID int64 `xorm:"INDEX UNIQUE(owner_repo_name)"`
Name string `xorm:"UNIQUE(owner_repo_name) NOT NULL"` Name string `xorm:"UNIQUE(owner_repo_name) NOT NULL"`
Data string `xorm:"LONGTEXT NOT NULL"` Data string `xorm:"LONGTEXT NOT NULL"`
Description string `xorm:"TEXT"`
CreatedUnix timeutil.TimeStamp `xorm:"created NOT NULL"` CreatedUnix timeutil.TimeStamp `xorm:"created NOT NULL"`
UpdatedUnix timeutil.TimeStamp `xorm:"updated"` UpdatedUnix timeutil.TimeStamp `xorm:"updated"`
} }
const (
VariableDataMaxLength = 65536
VariableDescriptionMaxLength = 4096
)
func init() { func init() {
db.RegisterModel(new(ActionVariable)) db.RegisterModel(new(ActionVariable))
} }
func InsertVariable(ctx context.Context, ownerID, repoID int64, name, data string) (*ActionVariable, error) { func InsertVariable(ctx context.Context, ownerID, repoID int64, name, data, description string) (*ActionVariable, error) {
if ownerID != 0 && repoID != 0 { if ownerID != 0 && repoID != 0 {
// It's trying to create a variable that belongs to a repository, but OwnerID has been set accidentally. // It's trying to create a variable that belongs to a repository, but OwnerID has been set accidentally.
// Remove OwnerID to avoid confusion; it's not worth returning an error here. // Remove OwnerID to avoid confusion; it's not worth returning an error here.
ownerID = 0 ownerID = 0
} }
if utf8.RuneCountInString(data) > VariableDataMaxLength {
return nil, util.NewInvalidArgumentErrorf("data too long")
}
description = util.TruncateRunes(description, VariableDescriptionMaxLength)
variable := &ActionVariable{ variable := &ActionVariable{
OwnerID: ownerID, OwnerID: ownerID,
RepoID: repoID, RepoID: repoID,
Name: strings.ToUpper(name), Name: strings.ToUpper(name),
Data: data, Data: data,
Description: description,
} }
return variable, db.Insert(ctx, variable) return variable, db.Insert(ctx, variable)
} }
type FindVariablesOpts struct { type FindVariablesOpts struct {
db.ListOptions db.ListOptions
IDs []int64
RepoID int64 RepoID int64
OwnerID int64 // it will be ignored if RepoID is set OwnerID int64 // it will be ignored if RepoID is set
Name string Name string
@ -65,6 +81,15 @@ type FindVariablesOpts struct {
func (opts FindVariablesOpts) ToConds() builder.Cond { func (opts FindVariablesOpts) ToConds() builder.Cond {
cond := builder.NewCond() cond := builder.NewCond()
if len(opts.IDs) > 0 {
if len(opts.IDs) == 1 {
cond = cond.And(builder.Eq{"id": opts.IDs[0]})
} else {
cond = cond.And(builder.In("id", opts.IDs))
}
}
// Since we now support instance-level variables, // Since we now support instance-level variables,
// there is no need to check for null values for `owner_id` and `repo_id` // there is no need to check for null values for `owner_id` and `repo_id`
cond = cond.And(builder.Eq{"repo_id": opts.RepoID}) cond = cond.And(builder.Eq{"repo_id": opts.RepoID})
@ -85,12 +110,18 @@ func FindVariables(ctx context.Context, opts FindVariablesOpts) ([]*ActionVariab
return db.Find[ActionVariable](ctx, opts) return db.Find[ActionVariable](ctx, opts)
} }
func UpdateVariable(ctx context.Context, variable *ActionVariable) (bool, error) { func UpdateVariableCols(ctx context.Context, variable *ActionVariable, cols ...string) (bool, error) {
count, err := db.GetEngine(ctx).ID(variable.ID).Cols("name", "data"). if utf8.RuneCountInString(variable.Data) > VariableDataMaxLength {
Update(&ActionVariable{ return false, util.NewInvalidArgumentErrorf("data too long")
Name: variable.Name, }
Data: variable.Data,
}) variable.Description = util.TruncateRunes(variable.Description, VariableDescriptionMaxLength)
variable.Name = strings.ToUpper(variable.Name)
count, err := db.GetEngine(ctx).
ID(variable.ID).
Cols(cols...).
Update(variable)
return count != 0, err return count != 0, err
} }
@ -137,3 +168,17 @@ func GetVariablesOfRun(ctx context.Context, run *ActionRun) (map[string]string,
return variables, nil return variables, nil
} }
func CountWrongRepoLevelVariables(ctx context.Context) (int64, error) {
var result int64
_, err := db.GetEngine(ctx).SQL("SELECT count(`id`) FROM `action_variable` WHERE `repo_id` > 0 AND `owner_id` > 0").Get(&result)
return result, err
}
func UpdateWrongRepoLevelVariables(ctx context.Context) (int64, error) {
result, err := db.GetEngine(ctx).Exec("UPDATE `action_variable` SET `owner_id` = 0 WHERE `repo_id` > 0 AND `owner_id` > 0")
if err != nil {
return 0, err
}
return result.RowsAffected()
}

View File

@ -16,16 +16,14 @@ import (
"code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/db"
issues_model "code.gitea.io/gitea/models/issues" issues_model "code.gitea.io/gitea/models/issues"
"code.gitea.io/gitea/models/organization" "code.gitea.io/gitea/models/organization"
access_model "code.gitea.io/gitea/models/perm/access"
repo_model "code.gitea.io/gitea/models/repo" repo_model "code.gitea.io/gitea/models/repo"
"code.gitea.io/gitea/models/unit"
user_model "code.gitea.io/gitea/models/user" user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/base"
"code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/structs"
"code.gitea.io/gitea/modules/timeutil" "code.gitea.io/gitea/modules/timeutil"
"code.gitea.io/gitea/modules/util"
"xorm.io/builder" "xorm.io/builder"
"xorm.io/xorm/schemas" "xorm.io/xorm/schemas"
@ -72,9 +70,9 @@ func (at ActionType) String() string {
case ActionRenameRepo: case ActionRenameRepo:
return "rename_repo" return "rename_repo"
case ActionStarRepo: case ActionStarRepo:
return "star_repo" return "star_repo" // will not displayed in feeds.tmpl
case ActionWatchRepo: case ActionWatchRepo:
return "watch_repo" return "watch_repo" // will not displayed in feeds.tmpl
case ActionCommitRepo: case ActionCommitRepo:
return "commit_repo" return "commit_repo"
case ActionCreateIssue: case ActionCreateIssue:
@ -174,7 +172,10 @@ func (a *Action) TableIndices() []*schemas.Index {
cuIndex := schemas.NewIndex("c_u", schemas.IndexType) cuIndex := schemas.NewIndex("c_u", schemas.IndexType)
cuIndex.AddColumn("user_id", "is_deleted") cuIndex.AddColumn("user_id", "is_deleted")
indices := []*schemas.Index{actUserIndex, repoIndex, cudIndex, cuIndex} actUserUserIndex := schemas.NewIndex("au_c_u", schemas.IndexType)
actUserUserIndex.AddColumn("act_user_id", "created_unix", "user_id")
indices := []*schemas.Index{actUserIndex, repoIndex, cudIndex, cuIndex, actUserUserIndex}
return indices return indices
} }
@ -200,15 +201,13 @@ func (a *Action) LoadActUser(ctx context.Context) {
} }
} }
func (a *Action) LoadRepo(ctx context.Context) { func (a *Action) LoadRepo(ctx context.Context) error {
if a.Repo != nil { if a.Repo != nil {
return return nil
} }
var err error var err error
a.Repo, err = repo_model.GetRepositoryByID(ctx, a.RepoID) a.Repo, err = repo_model.GetRepositoryByID(ctx, a.RepoID)
if err != nil { return err
log.Error("repo_model.GetRepositoryByID(%d): %v", a.RepoID, err)
}
} }
// GetActFullName gets the action's user full name. // GetActFullName gets the action's user full name.
@ -226,7 +225,7 @@ func (a *Action) GetActUserName(ctx context.Context) string {
// ShortActUserName gets the action's user name trimmed to max 20 // ShortActUserName gets the action's user name trimmed to max 20
// chars. // chars.
func (a *Action) ShortActUserName(ctx context.Context) string { func (a *Action) ShortActUserName(ctx context.Context) string {
return base.EllipsisString(a.GetActUserName(ctx), 20) return util.EllipsisDisplayString(a.GetActUserName(ctx), 20)
} }
// GetActDisplayName gets the action's display name based on DEFAULT_SHOW_FULL_NAME, or falls back to the username if it is blank. // GetActDisplayName gets the action's display name based on DEFAULT_SHOW_FULL_NAME, or falls back to the username if it is blank.
@ -250,7 +249,7 @@ func (a *Action) GetActDisplayNameTitle(ctx context.Context) string {
// GetRepoUserName returns the name of the action repository owner. // GetRepoUserName returns the name of the action repository owner.
func (a *Action) GetRepoUserName(ctx context.Context) string { func (a *Action) GetRepoUserName(ctx context.Context) string {
a.LoadRepo(ctx) _ = a.LoadRepo(ctx)
if a.Repo == nil { if a.Repo == nil {
return "(non-existing-repo)" return "(non-existing-repo)"
} }
@ -260,12 +259,12 @@ func (a *Action) GetRepoUserName(ctx context.Context) string {
// ShortRepoUserName returns the name of the action repository owner // ShortRepoUserName returns the name of the action repository owner
// trimmed to max 20 chars. // trimmed to max 20 chars.
func (a *Action) ShortRepoUserName(ctx context.Context) string { func (a *Action) ShortRepoUserName(ctx context.Context) string {
return base.EllipsisString(a.GetRepoUserName(ctx), 20) return util.EllipsisDisplayString(a.GetRepoUserName(ctx), 20)
} }
// GetRepoName returns the name of the action repository. // GetRepoName returns the name of the action repository.
func (a *Action) GetRepoName(ctx context.Context) string { func (a *Action) GetRepoName(ctx context.Context) string {
a.LoadRepo(ctx) _ = a.LoadRepo(ctx)
if a.Repo == nil { if a.Repo == nil {
return "(non-existing-repo)" return "(non-existing-repo)"
} }
@ -275,7 +274,7 @@ func (a *Action) GetRepoName(ctx context.Context) string {
// ShortRepoName returns the name of the action repository // ShortRepoName returns the name of the action repository
// trimmed to max 33 chars. // trimmed to max 33 chars.
func (a *Action) ShortRepoName(ctx context.Context) string { func (a *Action) ShortRepoName(ctx context.Context) string {
return base.EllipsisString(a.GetRepoName(ctx), 33) return util.EllipsisDisplayString(a.GetRepoName(ctx), 33)
} }
// GetRepoPath returns the virtual path to the action repository. // GetRepoPath returns the virtual path to the action repository.
@ -355,7 +354,7 @@ func (a *Action) GetBranch() string {
// GetRefLink returns the action's ref link. // GetRefLink returns the action's ref link.
func (a *Action) GetRefLink(ctx context.Context) string { func (a *Action) GetRefLink(ctx context.Context) string {
return git.RefURL(a.GetRepoLink(ctx), a.RefName) return a.GetRepoLink(ctx) + "/src/" + git.RefName(a.RefName).RefWebLinkPath()
} }
// GetTag returns the action's repository tag. // GetTag returns the action's repository tag.
@ -446,6 +445,7 @@ type GetFeedsOptions struct {
OnlyPerformedBy bool // only actions performed by requested user OnlyPerformedBy bool // only actions performed by requested user
IncludeDeleted bool // include deleted actions IncludeDeleted bool // include deleted actions
Date string // the day we want activity for: YYYY-MM-DD Date string // the day we want activity for: YYYY-MM-DD
DontCount bool // do counting in GetFeeds
} }
// ActivityReadable return whether doer can read activities of user // ActivityReadable return whether doer can read activities of user
@ -454,6 +454,24 @@ func ActivityReadable(user, doer *user_model.User) bool {
doer != nil && (doer.IsAdmin || user.ID == doer.ID) doer != nil && (doer.IsAdmin || user.ID == doer.ID)
} }
func FeedDateCond(opts GetFeedsOptions) builder.Cond {
cond := builder.NewCond()
if opts.Date == "" {
return cond
}
dateLow, err := time.ParseInLocation("2006-01-02", opts.Date, setting.DefaultUILocation)
if err != nil {
log.Warn("Unable to parse %s, filter not applied: %v", opts.Date, err)
} else {
dateHigh := dateLow.Add(86399000000000) // 23h59m59s
cond = cond.And(builder.Gte{"`action`.created_unix": dateLow.Unix()})
cond = cond.And(builder.Lte{"`action`.created_unix": dateHigh.Unix()})
}
return cond
}
func ActivityQueryCondition(ctx context.Context, opts GetFeedsOptions) (builder.Cond, error) { func ActivityQueryCondition(ctx context.Context, opts GetFeedsOptions) (builder.Cond, error) {
cond := builder.NewCond() cond := builder.NewCond()
@ -511,8 +529,8 @@ func ActivityQueryCondition(ctx context.Context, opts GetFeedsOptions) (builder.
} }
if opts.RequestedTeam != nil { if opts.RequestedTeam != nil {
env := organization.OrgFromUser(opts.RequestedUser).AccessibleTeamReposEnv(ctx, opts.RequestedTeam) env := repo_model.AccessibleTeamReposEnv(organization.OrgFromUser(opts.RequestedUser), opts.RequestedTeam)
teamRepoIDs, err := env.RepoIDs(1, opts.RequestedUser.NumRepos) teamRepoIDs, err := env.RepoIDs(ctx, 1, opts.RequestedUser.NumRepos)
if err != nil { if err != nil {
return nil, fmt.Errorf("GetTeamRepositories: %w", err) return nil, fmt.Errorf("GetTeamRepositories: %w", err)
} }
@ -534,17 +552,7 @@ func ActivityQueryCondition(ctx context.Context, opts GetFeedsOptions) (builder.
cond = cond.And(builder.Eq{"is_deleted": false}) cond = cond.And(builder.Eq{"is_deleted": false})
} }
if opts.Date != "" { cond = cond.And(FeedDateCond(opts))
dateLow, err := time.ParseInLocation("2006-01-02", opts.Date, setting.DefaultUILocation)
if err != nil {
log.Warn("Unable to parse %s, filter not applied: %v", opts.Date, err)
} else {
dateHigh := dateLow.Add(86399000000000) // 23h59m59s
cond = cond.And(builder.Gte{"`action`.created_unix": dateLow.Unix()})
cond = cond.And(builder.Lte{"`action`.created_unix": dateHigh.Unix()})
}
}
return cond, nil return cond, nil
} }
@ -559,130 +567,6 @@ func DeleteOldActions(ctx context.Context, olderThan time.Duration) (err error)
return err return err
} }
// NotifyWatchers creates batch of actions for every watcher.
// It could insert duplicate actions for a repository action, like this:
// * Original action: UserID=1 (the real actor), ActUserID=1
// * Organization action: UserID=100 (the repo's org), ActUserID=1
// * Watcher action: UserID=20 (a user who is watching a repo), ActUserID=1
func NotifyWatchers(ctx context.Context, actions ...*Action) error {
var watchers []*repo_model.Watch
var repo *repo_model.Repository
var err error
var permCode []bool
var permIssue []bool
var permPR []bool
e := db.GetEngine(ctx)
for _, act := range actions {
repoChanged := repo == nil || repo.ID != act.RepoID
if repoChanged {
// Add feeds for user self and all watchers.
watchers, err = repo_model.GetWatchers(ctx, act.RepoID)
if err != nil {
return fmt.Errorf("get watchers: %w", err)
}
}
// Add feed for actioner.
act.UserID = act.ActUserID
if _, err = e.Insert(act); err != nil {
return fmt.Errorf("insert new actioner: %w", err)
}
if repoChanged {
act.LoadRepo(ctx)
repo = act.Repo
// check repo owner exist.
if err := act.Repo.LoadOwner(ctx); err != nil {
return fmt.Errorf("can't get repo owner: %w", err)
}
} else if act.Repo == nil {
act.Repo = repo
}
// Add feed for organization
if act.Repo.Owner.IsOrganization() && act.ActUserID != act.Repo.Owner.ID {
act.ID = 0
act.UserID = act.Repo.Owner.ID
if err = db.Insert(ctx, act); err != nil {
return fmt.Errorf("insert new actioner: %w", err)
}
}
if repoChanged {
permCode = make([]bool, len(watchers))
permIssue = make([]bool, len(watchers))
permPR = make([]bool, len(watchers))
for i, watcher := range watchers {
user, err := user_model.GetUserByID(ctx, watcher.UserID)
if err != nil {
permCode[i] = false
permIssue[i] = false
permPR[i] = false
continue
}
perm, err := access_model.GetUserRepoPermission(ctx, repo, user)
if err != nil {
permCode[i] = false
permIssue[i] = false
permPR[i] = false
continue
}
permCode[i] = perm.CanRead(unit.TypeCode)
permIssue[i] = perm.CanRead(unit.TypeIssues)
permPR[i] = perm.CanRead(unit.TypePullRequests)
}
}
for i, watcher := range watchers {
if act.ActUserID == watcher.UserID {
continue
}
act.ID = 0
act.UserID = watcher.UserID
act.Repo.Units = nil
switch act.OpType {
case ActionCommitRepo, ActionPushTag, ActionDeleteTag, ActionPublishRelease, ActionDeleteBranch:
if !permCode[i] {
continue
}
case ActionCreateIssue, ActionCommentIssue, ActionCloseIssue, ActionReopenIssue:
if !permIssue[i] {
continue
}
case ActionCreatePullRequest, ActionCommentPull, ActionMergePullRequest, ActionClosePullRequest, ActionReopenPullRequest, ActionAutoMergePullRequest:
if !permPR[i] {
continue
}
}
if err = db.Insert(ctx, act); err != nil {
return fmt.Errorf("insert new action: %w", err)
}
}
}
return nil
}
// NotifyWatchersActions creates batch of actions for every watcher.
func NotifyWatchersActions(ctx context.Context, acts []*Action) error {
ctx, committer, err := db.TxContext(ctx)
if err != nil {
return err
}
defer committer.Close()
for _, act := range acts {
if err := NotifyWatchers(ctx, act); err != nil {
return err
}
}
return committer.Commit()
}
// DeleteIssueActions delete all actions related with issueID // DeleteIssueActions delete all actions related with issueID
func DeleteIssueActions(ctx context.Context, repoID, issueID, issueIndex int64) error { func DeleteIssueActions(ctx context.Context, repoID, issueID, issueIndex int64) error {
// delete actions assigned to this issue // delete actions assigned to this issue

View File

@ -5,6 +5,7 @@ package activities
import ( import (
"context" "context"
"errors"
"fmt" "fmt"
"strconv" "strconv"
@ -205,13 +206,35 @@ func (actions ActionList) LoadIssues(ctx context.Context) error {
// GetFeeds returns actions according to the provided options // GetFeeds returns actions according to the provided options
func GetFeeds(ctx context.Context, opts GetFeedsOptions) (ActionList, int64, error) { func GetFeeds(ctx context.Context, opts GetFeedsOptions) (ActionList, int64, error) {
if opts.RequestedUser == nil && opts.RequestedTeam == nil && opts.RequestedRepo == nil { if opts.RequestedUser == nil && opts.RequestedTeam == nil && opts.RequestedRepo == nil {
return nil, 0, fmt.Errorf("need at least one of these filters: RequestedUser, RequestedTeam, RequestedRepo") return nil, 0, errors.New("need at least one of these filters: RequestedUser, RequestedTeam, RequestedRepo")
} }
cond, err := ActivityQueryCondition(ctx, opts) var err error
var cond builder.Cond
// if the actor is the requested user or is an administrator, we can skip the ActivityQueryCondition
if opts.Actor != nil && opts.RequestedUser != nil && (opts.Actor.IsAdmin || opts.Actor.ID == opts.RequestedUser.ID) {
cond = builder.Eq{
"user_id": opts.RequestedUser.ID,
}.And(
FeedDateCond(opts),
)
if !opts.IncludeDeleted {
cond = cond.And(builder.Eq{"is_deleted": false})
}
if !opts.IncludePrivate {
cond = cond.And(builder.Eq{"is_private": false})
}
if opts.OnlyPerformedBy {
cond = cond.And(builder.Eq{"act_user_id": opts.RequestedUser.ID})
}
} else {
cond, err = ActivityQueryCondition(ctx, opts)
if err != nil { if err != nil {
return nil, 0, err return nil, 0, err
} }
}
actions := make([]*Action, 0, opts.PageSize) actions := make([]*Action, 0, opts.PageSize)
var count int64 var count int64
@ -221,7 +244,11 @@ func GetFeeds(ctx context.Context, opts GetFeedsOptions) (ActionList, int64, err
sess := db.GetEngine(ctx).Where(cond) sess := db.GetEngine(ctx).Where(cond)
sess = db.SetSessionPagination(sess, &opts) sess = db.SetSessionPagination(sess, &opts)
if opts.DontCount {
err = sess.Desc("`action`.created_unix").Find(&actions)
} else {
count, err = sess.Desc("`action`.created_unix").FindAndCount(&actions) count, err = sess.Desc("`action`.created_unix").FindAndCount(&actions)
}
if err != nil { if err != nil {
return nil, 0, fmt.Errorf("FindAndCount: %w", err) return nil, 0, fmt.Errorf("FindAndCount: %w", err)
} }
@ -235,12 +262,14 @@ func GetFeeds(ctx context.Context, opts GetFeedsOptions) (ActionList, int64, err
return nil, 0, fmt.Errorf("Find(actionsIDs): %w", err) return nil, 0, fmt.Errorf("Find(actionsIDs): %w", err)
} }
if !opts.DontCount {
count, err = db.GetEngine(ctx).Where(cond). count, err = db.GetEngine(ctx).Where(cond).
Table("action"). Table("action").
Cols("`action`.id").Count() Cols("`action`.id").Count()
if err != nil { if err != nil {
return nil, 0, fmt.Errorf("Count: %w", err) return nil, 0, fmt.Errorf("Count: %w", err)
} }
}
if err := db.GetEngine(ctx).In("`action`.id", actionIDs).Desc("`action`.created_unix").Find(&actions); err != nil { if err := db.GetEngine(ctx).In("`action`.id", actionIDs).Desc("`action`.created_unix").Find(&actions); err != nil {
return nil, 0, fmt.Errorf("Find: %w", err) return nil, 0, fmt.Errorf("Find: %w", err)
@ -253,3 +282,9 @@ func GetFeeds(ctx context.Context, opts GetFeedsOptions) (ActionList, int64, err
return actions, count, nil return actions, count, nil
} }
func CountUserFeeds(ctx context.Context, userID int64) (int64, error) {
return db.GetEngine(ctx).Where("user_id = ?", userID).
And("is_deleted = ?", false).
Count(&Action{})
}

View File

@ -82,43 +82,6 @@ func TestActivityReadable(t *testing.T) {
} }
} }
func TestNotifyWatchers(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase())
action := &activities_model.Action{
ActUserID: 8,
RepoID: 1,
OpType: activities_model.ActionStarRepo,
}
assert.NoError(t, activities_model.NotifyWatchers(db.DefaultContext, action))
// One watchers are inactive, thus action is only created for user 8, 1, 4, 11
unittest.AssertExistsAndLoadBean(t, &activities_model.Action{
ActUserID: action.ActUserID,
UserID: 8,
RepoID: action.RepoID,
OpType: action.OpType,
})
unittest.AssertExistsAndLoadBean(t, &activities_model.Action{
ActUserID: action.ActUserID,
UserID: 1,
RepoID: action.RepoID,
OpType: action.OpType,
})
unittest.AssertExistsAndLoadBean(t, &activities_model.Action{
ActUserID: action.ActUserID,
UserID: 4,
RepoID: action.RepoID,
OpType: action.OpType,
})
unittest.AssertExistsAndLoadBean(t, &activities_model.Action{
ActUserID: action.ActUserID,
UserID: 11,
RepoID: action.RepoID,
OpType: action.OpType,
})
}
func TestConsistencyUpdateAction(t *testing.T) { func TestConsistencyUpdateAction(t *testing.T) {
if !setting.Database.Type.IsSQLite3() { if !setting.Database.Type.IsSQLite3() {
t.Skip("Test is only for SQLite database.") t.Skip("Test is only for SQLite database.")
@ -167,7 +130,7 @@ func TestDeleteIssueActions(t *testing.T) {
// load an issue // load an issue
issue := unittest.AssertExistsAndLoadBean(t, &issue_model.Issue{ID: 4}) issue := unittest.AssertExistsAndLoadBean(t, &issue_model.Issue{ID: 4})
assert.NotEqualValues(t, issue.ID, issue.Index) // it needs to use different ID/Index to test the DeleteIssueActions to delete some actions by IssueIndex assert.NotEqual(t, issue.ID, issue.Index) // it needs to use different ID/Index to test the DeleteIssueActions to delete some actions by IssueIndex
// insert a comment // insert a comment
err := db.Insert(db.DefaultContext, &issue_model.Comment{Type: issue_model.CommentTypeComment, IssueID: issue.ID}) err := db.Insert(db.DefaultContext, &issue_model.Comment{Type: issue_model.CommentTypeComment, IssueID: issue.ID})

View File

@ -44,11 +44,11 @@ func TestNotificationsForUser(t *testing.T) {
assert.NoError(t, err) assert.NoError(t, err)
if assert.Len(t, notfs, 3) { if assert.Len(t, notfs, 3) {
assert.EqualValues(t, 5, notfs[0].ID) assert.EqualValues(t, 5, notfs[0].ID)
assert.EqualValues(t, user.ID, notfs[0].UserID) assert.Equal(t, user.ID, notfs[0].UserID)
assert.EqualValues(t, 4, notfs[1].ID) assert.EqualValues(t, 4, notfs[1].ID)
assert.EqualValues(t, user.ID, notfs[1].UserID) assert.Equal(t, user.ID, notfs[1].UserID)
assert.EqualValues(t, 2, notfs[2].ID) assert.EqualValues(t, 2, notfs[2].ID)
assert.EqualValues(t, user.ID, notfs[2].UserID) assert.Equal(t, user.ID, notfs[2].UserID)
} }
} }
@ -58,7 +58,7 @@ func TestNotification_GetRepo(t *testing.T) {
repo, err := notf.GetRepo(db.DefaultContext) repo, err := notf.GetRepo(db.DefaultContext)
assert.NoError(t, err) assert.NoError(t, err)
assert.Equal(t, repo, notf.Repository) assert.Equal(t, repo, notf.Repository)
assert.EqualValues(t, notf.RepoID, repo.ID) assert.Equal(t, notf.RepoID, repo.ID)
} }
func TestNotification_GetIssue(t *testing.T) { func TestNotification_GetIssue(t *testing.T) {
@ -67,7 +67,7 @@ func TestNotification_GetIssue(t *testing.T) {
issue, err := notf.GetIssue(db.DefaultContext) issue, err := notf.GetIssue(db.DefaultContext)
assert.NoError(t, err) assert.NoError(t, err)
assert.Equal(t, issue, notf.Issue) assert.Equal(t, issue, notf.Issue)
assert.EqualValues(t, notf.IssueID, issue.ID) assert.Equal(t, notf.IssueID, issue.ID)
} }
func TestGetNotificationCount(t *testing.T) { func TestGetNotificationCount(t *testing.T) {
@ -136,5 +136,5 @@ func TestSetIssueReadBy(t *testing.T) {
nt, err := activities_model.GetIssueNotification(db.DefaultContext, user.ID, issue.ID) nt, err := activities_model.GetIssueNotification(db.DefaultContext, user.ID, issue.ID)
assert.NoError(t, err) assert.NoError(t, err)
assert.EqualValues(t, activities_model.NotificationStatusRead, nt.Status) assert.Equal(t, activities_model.NotificationStatusRead, nt.Status)
} }

View File

@ -16,6 +16,7 @@ import (
"code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/gitrepo" "code.gitea.io/gitea/modules/gitrepo"
"xorm.io/builder"
"xorm.io/xorm" "xorm.io/xorm"
) )
@ -337,8 +338,10 @@ func newlyCreatedIssues(ctx context.Context, repoID int64, fromTime time.Time) *
func activeIssues(ctx context.Context, repoID int64, fromTime time.Time) *xorm.Session { func activeIssues(ctx context.Context, repoID int64, fromTime time.Time) *xorm.Session {
sess := db.GetEngine(ctx).Where("issue.repo_id = ?", repoID). sess := db.GetEngine(ctx).Where("issue.repo_id = ?", repoID).
And("issue.is_pull = ?", false). And("issue.is_pull = ?", false).
And("issue.created_unix >= ?", fromTime.Unix()). And(builder.Or(
Or("issue.closed_unix >= ?", fromTime.Unix()) builder.Gte{"issue.created_unix": fromTime.Unix()},
builder.Gte{"issue.closed_unix": fromTime.Unix()},
))
return sess return sess
} }

View File

@ -64,11 +64,9 @@ func TestGetUserHeatmapDataByUser(t *testing.T) {
for _, tc := range testCases { for _, tc := range testCases {
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: tc.userID}) user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: tc.userID})
doer := &user_model.User{ID: tc.doerID} var doer *user_model.User
_, err := unittest.LoadBeanIfExists(doer) if tc.doerID != 0 {
assert.NoError(t, err) doer = unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: tc.doerID})
if tc.doerID == 0 {
doer = nil
} }
// get the action for comparison // get the action for comparison

View File

@ -44,7 +44,7 @@ func init() {
// TranslatableMessage represents JSON struct that can be translated with a Locale // TranslatableMessage represents JSON struct that can be translated with a Locale
type TranslatableMessage struct { type TranslatableMessage struct {
Format string Format string
Args []any `json:"omitempty"` Args []any `json:",omitempty"`
} }
// LoadRepo loads repository of the task // LoadRepo loads repository of the task

View File

@ -25,7 +25,7 @@ func (err ErrKeyUnableVerify) Error() string {
} }
// ErrKeyIsPrivate is returned when the provided key is a private key not a public key // ErrKeyIsPrivate is returned when the provided key is a private key not a public key
var ErrKeyIsPrivate = util.NewSilentWrapErrorf(util.ErrInvalidArgument, "the provided key is a private key") var ErrKeyIsPrivate = util.ErrorWrap(util.ErrInvalidArgument, "the provided key is a private key")
// ErrKeyNotExist represents a "KeyNotExist" kind of error. // ErrKeyNotExist represents a "KeyNotExist" kind of error.
type ErrKeyNotExist struct { type ErrKeyNotExist struct {
@ -132,7 +132,7 @@ func IsErrGPGKeyParsing(err error) bool {
} }
func (err ErrGPGKeyParsing) Error() string { func (err ErrGPGKeyParsing) Error() string {
return fmt.Sprintf("failed to parse gpg key %s", err.ParseError.Error()) return "failed to parse gpg key " + err.ParseError.Error()
} }
// ErrGPGKeyNotExist represents a "GPGKeyNotExist" kind of error. // ErrGPGKeyNotExist represents a "GPGKeyNotExist" kind of error.
@ -217,6 +217,7 @@ func (err ErrGPGKeyAccessDenied) Unwrap() error {
// ErrKeyAccessDenied represents a "KeyAccessDenied" kind of error. // ErrKeyAccessDenied represents a "KeyAccessDenied" kind of error.
type ErrKeyAccessDenied struct { type ErrKeyAccessDenied struct {
UserID int64 UserID int64
RepoID int64
KeyID int64 KeyID int64
Note string Note string
} }
@ -228,8 +229,8 @@ func IsErrKeyAccessDenied(err error) bool {
} }
func (err ErrKeyAccessDenied) Error() string { func (err ErrKeyAccessDenied) Error() string {
return fmt.Sprintf("user does not have access to the key [user_id: %d, key_id: %d, note: %s]", return fmt.Sprintf("user does not have access to the key [user_id: %d, repo_id: %d, key_id: %d, note: %s]",
err.UserID, err.KeyID, err.Note) err.UserID, err.RepoID, err.KeyID, err.Note)
} }
func (err ErrKeyAccessDenied) Unwrap() error { func (err ErrKeyAccessDenied) Unwrap() error {

View File

@ -5,6 +5,7 @@ package asymkey
import ( import (
"context" "context"
"errors"
"fmt" "fmt"
"strings" "strings"
"time" "time"
@ -13,8 +14,8 @@ import (
user_model "code.gitea.io/gitea/models/user" user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/timeutil" "code.gitea.io/gitea/modules/timeutil"
"github.com/keybase/go-crypto/openpgp" "github.com/ProtonMail/go-crypto/openpgp"
"github.com/keybase/go-crypto/openpgp/packet" "github.com/ProtonMail/go-crypto/openpgp/packet"
"xorm.io/builder" "xorm.io/builder"
) )
@ -106,7 +107,7 @@ func GPGKeyToEntity(ctx context.Context, k *GPGKey) (*openpgp.Entity, error) {
if err != nil { if err != nil {
return nil, err return nil, err
} }
keys, err := checkArmoredGPGKeyString(impKey.Content) keys, err := CheckArmoredGPGKeyString(impKey.Content)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -115,7 +116,7 @@ func GPGKeyToEntity(ctx context.Context, k *GPGKey) (*openpgp.Entity, error) {
// parseSubGPGKey parse a sub Key // parseSubGPGKey parse a sub Key
func parseSubGPGKey(ownerID int64, primaryID string, pubkey *packet.PublicKey, expiry time.Time) (*GPGKey, error) { func parseSubGPGKey(ownerID int64, primaryID string, pubkey *packet.PublicKey, expiry time.Time) (*GPGKey, error) {
content, err := base64EncPubKey(pubkey) content, err := Base64EncPubKey(pubkey)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -141,7 +142,11 @@ func parseGPGKey(ctx context.Context, ownerID int64, e *openpgp.Entity, verified
// Parse Subkeys // Parse Subkeys
subkeys := make([]*GPGKey, len(e.Subkeys)) subkeys := make([]*GPGKey, len(e.Subkeys))
for i, k := range e.Subkeys { for i, k := range e.Subkeys {
subs, err := parseSubGPGKey(ownerID, pubkey.KeyIdString(), k.PublicKey, expiry) subkeyExpiry := expiry
if k.Sig.KeyLifetimeSecs != nil {
subkeyExpiry = k.PublicKey.CreationTime.Add(time.Duration(*k.Sig.KeyLifetimeSecs) * time.Second)
}
subs, err := parseSubGPGKey(ownerID, pubkey.KeyIdString(), k.PublicKey, subkeyExpiry)
if err != nil { if err != nil {
return nil, ErrGPGKeyParsing{ParseError: err} return nil, ErrGPGKeyParsing{ParseError: err}
} }
@ -156,7 +161,7 @@ func parseGPGKey(ctx context.Context, ownerID int64, e *openpgp.Entity, verified
emails := make([]*user_model.EmailAddress, 0, len(e.Identities)) emails := make([]*user_model.EmailAddress, 0, len(e.Identities))
for _, ident := range e.Identities { for _, ident := range e.Identities {
if ident.Revocation != nil { if ident.Revoked(time.Now()) {
continue continue
} }
email := strings.ToLower(strings.TrimSpace(ident.UserId.Email)) email := strings.ToLower(strings.TrimSpace(ident.UserId.Email))
@ -179,7 +184,7 @@ func parseGPGKey(ctx context.Context, ownerID int64, e *openpgp.Entity, verified
} }
} }
content, err := base64EncPubKey(pubkey) content, err := Base64EncPubKey(pubkey)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -203,7 +208,7 @@ func parseGPGKey(ctx context.Context, ownerID int64, e *openpgp.Entity, verified
// deleteGPGKey does the actual key deletion // deleteGPGKey does the actual key deletion
func deleteGPGKey(ctx context.Context, keyID string) (int64, error) { func deleteGPGKey(ctx context.Context, keyID string) (int64, error) {
if keyID == "" { if keyID == "" {
return 0, fmt.Errorf("empty KeyId forbidden") // Should never happen but just to be sure return 0, errors.New("empty KeyId forbidden") // Should never happen but just to be sure
} }
// Delete imported key // Delete imported key
n, err := db.GetEngine(ctx).Where("key_id=?", keyID).Delete(new(GPGKeyImport)) n, err := db.GetEngine(ctx).Where("key_id=?", keyID).Delete(new(GPGKeyImport))
@ -236,32 +241,9 @@ func DeleteGPGKey(ctx context.Context, doer *user_model.User, id int64) (err err
return committer.Commit() return committer.Commit()
} }
func checkKeyEmails(ctx context.Context, email string, keys ...*GPGKey) (bool, string) { func FindGPGKeyWithSubKeys(ctx context.Context, keyID string) ([]*GPGKey, error) {
uid := int64(0) return db.Find[GPGKey](ctx, FindGPGKeyOptions{
var userEmails []*user_model.EmailAddress KeyID: keyID,
var user *user_model.User IncludeSubKeys: true,
for _, key := range keys { })
for _, e := range key.Emails {
if e.IsActivated && (email == "" || strings.EqualFold(e.Email, email)) {
return true, e.Email
}
}
if key.Verified && key.OwnerID != 0 {
if uid != key.OwnerID {
userEmails, _ = user_model.GetEmailAddresses(ctx, key.OwnerID)
uid = key.OwnerID
user = &user_model.User{ID: uid}
_, _ = user_model.GetUser(ctx, user)
}
for _, e := range userEmails {
if e.IsActivated && (email == "" || strings.EqualFold(e.Email, email)) {
return true, e.Email
}
}
if user.KeepEmailPrivate && strings.EqualFold(email, user.GetEmail()) {
return true, user.GetEmail()
}
}
}
return false, email
} }

View File

@ -10,7 +10,7 @@ import (
"code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/log"
"github.com/keybase/go-crypto/openpgp" "github.com/ProtonMail/go-crypto/openpgp"
) )
// __________________ ________ ____ __. // __________________ ________ ____ __.
@ -67,7 +67,7 @@ func addGPGSubKey(ctx context.Context, key *GPGKey) (err error) {
// AddGPGKey adds new public key to database. // AddGPGKey adds new public key to database.
func AddGPGKey(ctx context.Context, ownerID int64, content, token, signature string) ([]*GPGKey, error) { func AddGPGKey(ctx context.Context, ownerID int64, content, token, signature string) ([]*GPGKey, error) {
ekeys, err := checkArmoredGPGKeyString(content) ekeys, err := CheckArmoredGPGKeyString(content)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -83,12 +83,12 @@ func AddGPGKey(ctx context.Context, ownerID int64, content, token, signature str
verified := false verified := false
// Handle provided signature // Handle provided signature
if signature != "" { if signature != "" {
signer, err := openpgp.CheckArmoredDetachedSignature(ekeys, strings.NewReader(token), strings.NewReader(signature)) signer, err := openpgp.CheckArmoredDetachedSignature(ekeys, strings.NewReader(token), strings.NewReader(signature), nil)
if err != nil { if err != nil {
signer, err = openpgp.CheckArmoredDetachedSignature(ekeys, strings.NewReader(token+"\n"), strings.NewReader(signature)) signer, err = openpgp.CheckArmoredDetachedSignature(ekeys, strings.NewReader(token+"\n"), strings.NewReader(signature), nil)
} }
if err != nil { if err != nil {
signer, err = openpgp.CheckArmoredDetachedSignature(ekeys, strings.NewReader(token+"\r\n"), strings.NewReader(signature)) signer, err = openpgp.CheckArmoredDetachedSignature(ekeys, strings.NewReader(token+"\r\n"), strings.NewReader(signature), nil)
} }
if err != nil { if err != nil {
log.Error("Unable to validate token signature. Error: %v", err) log.Error("Unable to validate token signature. Error: %v", err)

View File

@ -4,19 +4,15 @@
package asymkey package asymkey
import ( import (
"context" "errors"
"fmt" "fmt"
"hash" "hash"
"strings"
"code.gitea.io/gitea/models/db"
repo_model "code.gitea.io/gitea/models/repo" repo_model "code.gitea.io/gitea/models/repo"
user_model "code.gitea.io/gitea/models/user" user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting"
"github.com/keybase/go-crypto/openpgp/packet" "github.com/ProtonMail/go-crypto/openpgp/packet"
) )
// __________________ ________ ____ __. // __________________ ________ ____ __.
@ -70,267 +66,10 @@ const (
NoKeyFound = "gpg.error.no_gpg_keys_found" NoKeyFound = "gpg.error.no_gpg_keys_found"
) )
// ParseCommitsWithSignature checks if signaute of commits are corresponding to users gpg keys.
func ParseCommitsWithSignature(ctx context.Context, oldCommits []*user_model.UserCommit, repoTrustModel repo_model.TrustModelType, isOwnerMemberCollaborator func(*user_model.User) (bool, error)) []*SignCommit {
newCommits := make([]*SignCommit, 0, len(oldCommits))
keyMap := map[string]bool{}
for _, c := range oldCommits {
signCommit := &SignCommit{
UserCommit: c,
Verification: ParseCommitWithSignature(ctx, c.Commit),
}
_ = CalculateTrustStatus(signCommit.Verification, repoTrustModel, isOwnerMemberCollaborator, &keyMap)
newCommits = append(newCommits, signCommit)
}
return newCommits
}
// ParseCommitWithSignature check if signature is good against keystore.
func ParseCommitWithSignature(ctx context.Context, c *git.Commit) *CommitVerification {
var committer *user_model.User
if c.Committer != nil {
var err error
// Find Committer account
committer, err = user_model.GetUserByEmail(ctx, c.Committer.Email) // This finds the user by primary email or activated email so commit will not be valid if email is not
if err != nil { // Skipping not user for committer
committer = &user_model.User{
Name: c.Committer.Name,
Email: c.Committer.Email,
}
// We can expect this to often be an ErrUserNotExist. in the case
// it is not, however, it is important to log it.
if !user_model.IsErrUserNotExist(err) {
log.Error("GetUserByEmail: %v", err)
return &CommitVerification{
CommittingUser: committer,
Verified: false,
Reason: "gpg.error.no_committer_account",
}
}
}
}
// If no signature just report the committer
if c.Signature == nil {
return &CommitVerification{
CommittingUser: committer,
Verified: false, // Default value
Reason: "gpg.error.not_signed_commit", // Default value
}
}
// If this a SSH signature handle it differently
if strings.HasPrefix(c.Signature.Signature, "-----BEGIN SSH SIGNATURE-----") {
return ParseCommitWithSSHSignature(ctx, c, committer)
}
// Parsing signature
sig, err := extractSignature(c.Signature.Signature)
if err != nil { // Skipping failed to extract sign
log.Error("SignatureRead err: %v", err)
return &CommitVerification{
CommittingUser: committer,
Verified: false,
Reason: "gpg.error.extract_sign",
}
}
keyID := tryGetKeyIDFromSignature(sig)
defaultReason := NoKeyFound
// First check if the sig has a keyID and if so just look at that
if commitVerification := hashAndVerifyForKeyID(
ctx,
sig,
c.Signature.Payload,
committer,
keyID,
setting.AppName,
""); commitVerification != nil {
if commitVerification.Reason == BadSignature {
defaultReason = BadSignature
} else {
return commitVerification
}
}
// Now try to associate the signature with the committer, if present
if committer.ID != 0 {
keys, err := db.Find[GPGKey](ctx, FindGPGKeyOptions{
OwnerID: committer.ID,
})
if err != nil { // Skipping failed to get gpg keys of user
log.Error("ListGPGKeys: %v", err)
return &CommitVerification{
CommittingUser: committer,
Verified: false,
Reason: "gpg.error.failed_retrieval_gpg_keys",
}
}
if err := GPGKeyList(keys).LoadSubKeys(ctx); err != nil {
log.Error("LoadSubKeys: %v", err)
return &CommitVerification{
CommittingUser: committer,
Verified: false,
Reason: "gpg.error.failed_retrieval_gpg_keys",
}
}
committerEmailAddresses, _ := user_model.GetEmailAddresses(ctx, committer.ID)
activated := false
for _, e := range committerEmailAddresses {
if e.IsActivated && strings.EqualFold(e.Email, c.Committer.Email) {
activated = true
break
}
}
for _, k := range keys {
// Pre-check (& optimization) that emails attached to key can be attached to the committer email and can validate
canValidate := false
email := ""
if k.Verified && activated {
canValidate = true
email = c.Committer.Email
}
if !canValidate {
for _, e := range k.Emails {
if e.IsActivated && strings.EqualFold(e.Email, c.Committer.Email) {
canValidate = true
email = e.Email
break
}
}
}
if !canValidate {
continue // Skip this key
}
commitVerification := hashAndVerifyWithSubKeysCommitVerification(sig, c.Signature.Payload, k, committer, committer, email)
if commitVerification != nil {
return commitVerification
}
}
}
if setting.Repository.Signing.SigningKey != "" && setting.Repository.Signing.SigningKey != "default" && setting.Repository.Signing.SigningKey != "none" {
// OK we should try the default key
gpgSettings := git.GPGSettings{
Sign: true,
KeyID: setting.Repository.Signing.SigningKey,
Name: setting.Repository.Signing.SigningName,
Email: setting.Repository.Signing.SigningEmail,
}
if err := gpgSettings.LoadPublicKeyContent(); err != nil {
log.Error("Error getting default signing key: %s %v", gpgSettings.KeyID, err)
} else if commitVerification := verifyWithGPGSettings(ctx, &gpgSettings, sig, c.Signature.Payload, committer, keyID); commitVerification != nil {
if commitVerification.Reason == BadSignature {
defaultReason = BadSignature
} else {
return commitVerification
}
}
}
defaultGPGSettings, err := c.GetRepositoryDefaultPublicGPGKey(false)
if err != nil {
log.Error("Error getting default public gpg key: %v", err)
} else if defaultGPGSettings == nil {
log.Warn("Unable to get defaultGPGSettings for unattached commit: %s", c.ID.String())
} else if defaultGPGSettings.Sign {
if commitVerification := verifyWithGPGSettings(ctx, defaultGPGSettings, sig, c.Signature.Payload, committer, keyID); commitVerification != nil {
if commitVerification.Reason == BadSignature {
defaultReason = BadSignature
} else {
return commitVerification
}
}
}
return &CommitVerification{ // Default at this stage
CommittingUser: committer,
Verified: false,
Warning: defaultReason != NoKeyFound,
Reason: defaultReason,
SigningKey: &GPGKey{
KeyID: keyID,
},
}
}
func verifyWithGPGSettings(ctx context.Context, gpgSettings *git.GPGSettings, sig *packet.Signature, payload string, committer *user_model.User, keyID string) *CommitVerification {
// First try to find the key in the db
if commitVerification := hashAndVerifyForKeyID(ctx, sig, payload, committer, gpgSettings.KeyID, gpgSettings.Name, gpgSettings.Email); commitVerification != nil {
return commitVerification
}
// Otherwise we have to parse the key
ekeys, err := checkArmoredGPGKeyString(gpgSettings.PublicKeyContent)
if err != nil {
log.Error("Unable to get default signing key: %v", err)
return &CommitVerification{
CommittingUser: committer,
Verified: false,
Reason: "gpg.error.generate_hash",
}
}
for _, ekey := range ekeys {
pubkey := ekey.PrimaryKey
content, err := base64EncPubKey(pubkey)
if err != nil {
return &CommitVerification{
CommittingUser: committer,
Verified: false,
Reason: "gpg.error.generate_hash",
}
}
k := &GPGKey{
Content: content,
CanSign: pubkey.CanSign(),
KeyID: pubkey.KeyIdString(),
}
for _, subKey := range ekey.Subkeys {
content, err := base64EncPubKey(subKey.PublicKey)
if err != nil {
return &CommitVerification{
CommittingUser: committer,
Verified: false,
Reason: "gpg.error.generate_hash",
}
}
k.SubsKey = append(k.SubsKey, &GPGKey{
Content: content,
CanSign: subKey.PublicKey.CanSign(),
KeyID: subKey.PublicKey.KeyIdString(),
})
}
if commitVerification := hashAndVerifyWithSubKeysCommitVerification(sig, payload, k, committer, &user_model.User{
Name: gpgSettings.Name,
Email: gpgSettings.Email,
}, gpgSettings.Email); commitVerification != nil {
return commitVerification
}
if keyID == k.KeyID {
// This is a bad situation ... We have a key id that matches our default key but the signature doesn't match.
return &CommitVerification{
CommittingUser: committer,
Verified: false,
Warning: true,
Reason: BadSignature,
}
}
}
return nil
}
func verifySign(s *packet.Signature, h hash.Hash, k *GPGKey) error { func verifySign(s *packet.Signature, h hash.Hash, k *GPGKey) error {
// Check if key can sign // Check if key can sign
if !k.CanSign { if !k.CanSign {
return fmt.Errorf("key can not sign") return errors.New("key can not sign")
} }
// Decode key // Decode key
pkey, err := base64DecPubKey(k.Content) pkey, err := base64DecPubKey(k.Content)
@ -369,7 +108,7 @@ func hashAndVerifyWithSubKeys(sig *packet.Signature, payload string, k *GPGKey)
return nil, nil return nil, nil
} }
func hashAndVerifyWithSubKeysCommitVerification(sig *packet.Signature, payload string, k *GPGKey, committer, signer *user_model.User, email string) *CommitVerification { func HashAndVerifyWithSubKeysCommitVerification(sig *packet.Signature, payload string, k *GPGKey, committer, signer *user_model.User, email string) *CommitVerification {
key, err := hashAndVerifyWithSubKeys(sig, payload, k) key, err := hashAndVerifyWithSubKeys(sig, payload, k)
if err != nil { // Skipping failed to generate hash if err != nil { // Skipping failed to generate hash
return &CommitVerification{ return &CommitVerification{
@ -392,78 +131,6 @@ func hashAndVerifyWithSubKeysCommitVerification(sig *packet.Signature, payload s
return nil return nil
} }
func hashAndVerifyForKeyID(ctx context.Context, sig *packet.Signature, payload string, committer *user_model.User, keyID, name, email string) *CommitVerification {
if keyID == "" {
return nil
}
keys, err := db.Find[GPGKey](ctx, FindGPGKeyOptions{
KeyID: keyID,
IncludeSubKeys: true,
})
if err != nil {
log.Error("GetGPGKeysByKeyID: %v", err)
return &CommitVerification{
CommittingUser: committer,
Verified: false,
Reason: "gpg.error.failed_retrieval_gpg_keys",
}
}
if len(keys) == 0 {
return nil
}
for _, key := range keys {
var primaryKeys []*GPGKey
if key.PrimaryKeyID != "" {
primaryKeys, err = db.Find[GPGKey](ctx, FindGPGKeyOptions{
KeyID: key.PrimaryKeyID,
IncludeSubKeys: true,
})
if err != nil {
log.Error("GetGPGKeysByKeyID: %v", err)
return &CommitVerification{
CommittingUser: committer,
Verified: false,
Reason: "gpg.error.failed_retrieval_gpg_keys",
}
}
}
activated, email := checkKeyEmails(ctx, email, append([]*GPGKey{key}, primaryKeys...)...)
if !activated {
continue
}
signer := &user_model.User{
Name: name,
Email: email,
}
if key.OwnerID != 0 {
owner, err := user_model.GetUserByID(ctx, key.OwnerID)
if err == nil {
signer = owner
} else if !user_model.IsErrUserNotExist(err) {
log.Error("Failed to user_model.GetUserByID: %d for key ID: %d (%s) %v", key.OwnerID, key.ID, key.KeyID, err)
return &CommitVerification{
CommittingUser: committer,
Verified: false,
Reason: "gpg.error.no_committer_account",
}
}
}
commitVerification := hashAndVerifyWithSubKeysCommitVerification(sig, payload, key, committer, signer, email)
if commitVerification != nil {
return commitVerification
}
}
// This is a bad situation ... We have a key id that is in our database but the signature doesn't match.
return &CommitVerification{
CommittingUser: committer,
Verified: false,
Warning: true,
Reason: BadSignature,
}
}
// CalculateTrustStatus will calculate the TrustStatus for a commit verification within a repository // CalculateTrustStatus will calculate the TrustStatus for a commit verification within a repository
// There are several trust models in Gitea // There are several trust models in Gitea
func CalculateTrustStatus(verification *CommitVerification, repoTrustModel repo_model.TrustModelType, isOwnerMemberCollaborator func(*user_model.User) (bool, error), keyMap *map[string]bool) error { func CalculateTrustStatus(verification *CommitVerification, repoTrustModel repo_model.TrustModelType, isOwnerMemberCollaborator func(*user_model.User) (bool, error), keyMap *map[string]bool) error {

View File

@ -7,15 +7,16 @@ import (
"bytes" "bytes"
"crypto" "crypto"
"encoding/base64" "encoding/base64"
"errors"
"fmt" "fmt"
"hash" "hash"
"io" "io"
"strings" "strings"
"time" "time"
"github.com/keybase/go-crypto/openpgp" "github.com/ProtonMail/go-crypto/openpgp"
"github.com/keybase/go-crypto/openpgp/armor" "github.com/ProtonMail/go-crypto/openpgp/armor"
"github.com/keybase/go-crypto/openpgp/packet" "github.com/ProtonMail/go-crypto/openpgp/packet"
) )
// __________________ ________ ____ __. // __________________ ________ ____ __.
@ -33,9 +34,9 @@ import (
// This file provides common functions relating to GPG Keys // This file provides common functions relating to GPG Keys
// checkArmoredGPGKeyString checks if the given key string is a valid GPG armored key. // CheckArmoredGPGKeyString checks if the given key string is a valid GPG armored key.
// The function returns the actual public key on success // The function returns the actual public key on success
func checkArmoredGPGKeyString(content string) (openpgp.EntityList, error) { func CheckArmoredGPGKeyString(content string) (openpgp.EntityList, error) {
list, err := openpgp.ReadArmoredKeyRing(strings.NewReader(content)) list, err := openpgp.ReadArmoredKeyRing(strings.NewReader(content))
if err != nil { if err != nil {
return nil, ErrGPGKeyParsing{err} return nil, ErrGPGKeyParsing{err}
@ -43,8 +44,8 @@ func checkArmoredGPGKeyString(content string) (openpgp.EntityList, error) {
return list, nil return list, nil
} }
// base64EncPubKey encode public key content to base 64 // Base64EncPubKey encode public key content to base 64
func base64EncPubKey(pubkey *packet.PublicKey) (string, error) { func Base64EncPubKey(pubkey *packet.PublicKey) (string, error) {
var w bytes.Buffer var w bytes.Buffer
err := pubkey.Serialize(&w) err := pubkey.Serialize(&w)
if err != nil { if err != nil {
@ -75,12 +76,12 @@ func base64DecPubKey(content string) (*packet.PublicKey, error) {
// Check type // Check type
pkey, ok := p.(*packet.PublicKey) pkey, ok := p.(*packet.PublicKey)
if !ok { if !ok {
return nil, fmt.Errorf("key is not a public key") return nil, errors.New("key is not a public key")
} }
return pkey, nil return pkey, nil
} }
// getExpiryTime extract the expire time of primary key based on sig // getExpiryTime extract the expiry time of primary key based on sig
func getExpiryTime(e *openpgp.Entity) time.Time { func getExpiryTime(e *openpgp.Entity) time.Time {
expiry := time.Time{} expiry := time.Time{}
// Extract self-sign for expire date based on : https://github.com/golang/crypto/blob/master/openpgp/keys.go#L165 // Extract self-sign for expire date based on : https://github.com/golang/crypto/blob/master/openpgp/keys.go#L165
@ -88,12 +89,12 @@ func getExpiryTime(e *openpgp.Entity) time.Time {
for _, ident := range e.Identities { for _, ident := range e.Identities {
if selfSig == nil { if selfSig == nil {
selfSig = ident.SelfSignature selfSig = ident.SelfSignature
} else if ident.SelfSignature.IsPrimaryId != nil && *ident.SelfSignature.IsPrimaryId { } else if ident.SelfSignature != nil && ident.SelfSignature.IsPrimaryId != nil && *ident.SelfSignature.IsPrimaryId {
selfSig = ident.SelfSignature selfSig = ident.SelfSignature
break break
} }
} }
if selfSig.KeyLifetimeSecs != nil { if selfSig != nil && selfSig.KeyLifetimeSecs != nil {
expiry = e.PrimaryKey.CreationTime.Add(time.Duration(*selfSig.KeyLifetimeSecs) * time.Second) expiry = e.PrimaryKey.CreationTime.Add(time.Duration(*selfSig.KeyLifetimeSecs) * time.Second)
} }
return expiry return expiry
@ -119,23 +120,23 @@ func readArmoredSign(r io.Reader) (body io.Reader, err error) {
return block.Body, nil return block.Body, nil
} }
func extractSignature(s string) (*packet.Signature, error) { func ExtractSignature(s string) (*packet.Signature, error) {
r, err := readArmoredSign(strings.NewReader(s)) r, err := readArmoredSign(strings.NewReader(s))
if err != nil { if err != nil {
return nil, fmt.Errorf("Failed to read signature armor") return nil, errors.New("Failed to read signature armor")
} }
p, err := packet.Read(r) p, err := packet.Read(r)
if err != nil { if err != nil {
return nil, fmt.Errorf("Failed to read signature packet") return nil, errors.New("Failed to read signature packet")
} }
sig, ok := p.(*packet.Signature) sig, ok := p.(*packet.Signature)
if !ok { if !ok {
return nil, fmt.Errorf("Packet is not a signature") return nil, errors.New("Packet is not a signature")
} }
return sig, nil return sig, nil
} }
func tryGetKeyIDFromSignature(sig *packet.Signature) string { func TryGetKeyIDFromSignature(sig *packet.Signature) string {
if sig.IssuerKeyId != nil && (*sig.IssuerKeyId) != 0 { if sig.IssuerKeyId != nil && (*sig.IssuerKeyId) != 0 {
return fmt.Sprintf("%016X", *sig.IssuerKeyId) return fmt.Sprintf("%016X", *sig.IssuerKeyId)
} }

View File

@ -13,8 +13,10 @@ import (
"code.gitea.io/gitea/modules/timeutil" "code.gitea.io/gitea/modules/timeutil"
"code.gitea.io/gitea/modules/util" "code.gitea.io/gitea/modules/util"
"github.com/keybase/go-crypto/openpgp/packet" "github.com/ProtonMail/go-crypto/openpgp"
"github.com/ProtonMail/go-crypto/openpgp/packet"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
) )
func TestCheckArmoredGPGKeyString(t *testing.T) { func TestCheckArmoredGPGKeyString(t *testing.T) {
@ -49,7 +51,7 @@ MkM/fdpyc2hY7Dl/+qFmN5MG5yGmMpQcX+RNNR222ibNC1D3wg==
=i9b7 =i9b7
-----END PGP PUBLIC KEY BLOCK-----` -----END PGP PUBLIC KEY BLOCK-----`
key, err := checkArmoredGPGKeyString(testGPGArmor) key, err := CheckArmoredGPGKeyString(testGPGArmor)
assert.NoError(t, err, "Could not parse a valid GPG public armored rsa key", key) assert.NoError(t, err, "Could not parse a valid GPG public armored rsa key", key)
// TODO verify value of key // TODO verify value of key
} }
@ -70,7 +72,7 @@ OyjLLnFQiVmq7kEA/0z0CQe3ZQiQIq5zrs7Nh1XRkFAo8GlU/SGC9XFFi722
=ZiSe =ZiSe
-----END PGP PUBLIC KEY BLOCK-----` -----END PGP PUBLIC KEY BLOCK-----`
key, err := checkArmoredGPGKeyString(testGPGArmor) key, err := CheckArmoredGPGKeyString(testGPGArmor)
assert.NoError(t, err, "Could not parse a valid GPG public armored brainpoolP256r1 key", key) assert.NoError(t, err, "Could not parse a valid GPG public armored brainpoolP256r1 key", key)
// TODO verify value of key // TODO verify value of key
} }
@ -106,15 +108,14 @@ Av844q/BfRuVsJsK1NDNG09LC30B0l3LKBqlrRmRTUMHtgchdX2dY+p7GPOoSzlR
MkM/fdpyc2hY7Dl/+qFmN5MG5yGmMpQcX+RNNR222ibNC1D3wg== MkM/fdpyc2hY7Dl/+qFmN5MG5yGmMpQcX+RNNR222ibNC1D3wg==
=i9b7 =i9b7
-----END PGP PUBLIC KEY BLOCK-----` -----END PGP PUBLIC KEY BLOCK-----`
keys, err := checkArmoredGPGKeyString(testGPGArmor) keys, err := CheckArmoredGPGKeyString(testGPGArmor)
if !assert.NotEmpty(t, keys) { require.NotEmpty(t, keys)
return
}
ekey := keys[0] ekey := keys[0]
assert.NoError(t, err, "Could not parse a valid GPG armored key", ekey) assert.NoError(t, err, "Could not parse a valid GPG armored key", ekey)
pubkey := ekey.PrimaryKey pubkey := ekey.PrimaryKey
content, err := base64EncPubKey(pubkey) content, err := Base64EncPubKey(pubkey)
assert.NoError(t, err, "Could not base64 encode a valid PublicKey content", ekey) assert.NoError(t, err, "Could not base64 encode a valid PublicKey content", ekey)
key := &GPGKey{ key := &GPGKey{
@ -175,9 +176,9 @@ committer Antoine GIRARD <sapk@sapk.fr> 1489013107 +0100
Unknown GPG key with good email Unknown GPG key with good email
` `
// Reading Sign // Reading Sign
goodSig, err := extractSignature(testGoodSigArmor) goodSig, err := ExtractSignature(testGoodSigArmor)
assert.NoError(t, err, "Could not parse a valid GPG armored signature", testGoodSigArmor) assert.NoError(t, err, "Could not parse a valid GPG armored signature", testGoodSigArmor)
badSig, err := extractSignature(testBadSigArmor) badSig, err := ExtractSignature(testBadSigArmor)
assert.NoError(t, err, "Could not parse a valid GPG armored signature", testBadSigArmor) assert.NoError(t, err, "Could not parse a valid GPG armored signature", testBadSigArmor)
// Generating hash of commit // Generating hash of commit
@ -385,7 +386,7 @@ epiDVQ==
=VSKJ =VSKJ
-----END PGP PUBLIC KEY BLOCK----- -----END PGP PUBLIC KEY BLOCK-----
` `
keys, err := checkArmoredGPGKeyString(testIssue6599) keys, err := CheckArmoredGPGKeyString(testIssue6599)
assert.NoError(t, err) assert.NoError(t, err)
if assert.NotEmpty(t, keys) { if assert.NotEmpty(t, keys) {
ekey := keys[0] ekey := keys[0]
@ -395,11 +396,33 @@ epiDVQ==
} }
func TestTryGetKeyIDFromSignature(t *testing.T) { func TestTryGetKeyIDFromSignature(t *testing.T) {
assert.Empty(t, tryGetKeyIDFromSignature(&packet.Signature{})) assert.Empty(t, TryGetKeyIDFromSignature(&packet.Signature{}))
assert.Equal(t, "038D1A3EADDBEA9C", tryGetKeyIDFromSignature(&packet.Signature{ assert.Equal(t, "038D1A3EADDBEA9C", TryGetKeyIDFromSignature(&packet.Signature{
IssuerKeyId: util.ToPointer(uint64(0x38D1A3EADDBEA9C)), IssuerKeyId: util.ToPointer(uint64(0x38D1A3EADDBEA9C)),
})) }))
assert.Equal(t, "038D1A3EADDBEA9C", tryGetKeyIDFromSignature(&packet.Signature{ assert.Equal(t, "038D1A3EADDBEA9C", TryGetKeyIDFromSignature(&packet.Signature{
IssuerFingerprint: []uint8{0xb, 0x23, 0x24, 0xc7, 0xe6, 0xfe, 0x4f, 0x3a, 0x6, 0x26, 0xc1, 0x21, 0x3, 0x8d, 0x1a, 0x3e, 0xad, 0xdb, 0xea, 0x9c}, IssuerFingerprint: []uint8{0xb, 0x23, 0x24, 0xc7, 0xe6, 0xfe, 0x4f, 0x3a, 0x6, 0x26, 0xc1, 0x21, 0x3, 0x8d, 0x1a, 0x3e, 0xad, 0xdb, 0xea, 0x9c},
})) }))
} }
func TestParseGPGKey(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase())
assert.NoError(t, db.Insert(db.DefaultContext, &user_model.EmailAddress{UID: 1, Email: "email1@example.com", IsActivated: true}))
// create a key for test email
e, err := openpgp.NewEntity("name", "comment", "email1@example.com", nil)
require.NoError(t, err)
k, err := parseGPGKey(db.DefaultContext, 1, e, true)
require.NoError(t, err)
assert.NotEmpty(t, k.KeyID)
assert.NotEmpty(t, k.Emails) // the key is valid, matches the email
// then revoke the key
for _, id := range e.Identities {
id.Revocations = append(id.Revocations, &packet.Signature{RevocationReason: util.ToPointer(packet.KeyCompromised)})
}
k, err = parseGPGKey(db.DefaultContext, 1, e, true)
require.NoError(t, err)
assert.NotEmpty(t, k.KeyID)
assert.Empty(t, k.Emails) // the key is revoked, matches no email
}

View File

@ -50,7 +50,7 @@ func VerifyGPGKey(ctx context.Context, ownerID int64, keyID, token, signature st
return "", err return "", err
} }
sig, err := extractSignature(signature) sig, err := ExtractSignature(signature)
if err != nil { if err != nil {
return "", ErrGPGInvalidTokenSignature{ return "", ErrGPGInvalidTokenSignature{
ID: key.KeyID, ID: key.KeyID,

View File

@ -1,80 +0,0 @@
// Copyright 2021 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package asymkey
import (
"bytes"
"context"
"fmt"
"strings"
"code.gitea.io/gitea/models/db"
user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/log"
"github.com/42wim/sshsig"
)
// ParseCommitWithSSHSignature check if signature is good against keystore.
func ParseCommitWithSSHSignature(ctx context.Context, c *git.Commit, committer *user_model.User) *CommitVerification {
// Now try to associate the signature with the committer, if present
if committer.ID != 0 {
keys, err := db.Find[PublicKey](ctx, FindPublicKeyOptions{
OwnerID: committer.ID,
NotKeytype: KeyTypePrincipal,
})
if err != nil { // Skipping failed to get ssh keys of user
log.Error("ListPublicKeys: %v", err)
return &CommitVerification{
CommittingUser: committer,
Verified: false,
Reason: "gpg.error.failed_retrieval_gpg_keys",
}
}
committerEmailAddresses, err := user_model.GetEmailAddresses(ctx, committer.ID)
if err != nil {
log.Error("GetEmailAddresses: %v", err)
}
activated := false
for _, e := range committerEmailAddresses {
if e.IsActivated && strings.EqualFold(e.Email, c.Committer.Email) {
activated = true
break
}
}
for _, k := range keys {
if k.Verified && activated {
commitVerification := verifySSHCommitVerification(c.Signature.Signature, c.Signature.Payload, k, committer, committer, c.Committer.Email)
if commitVerification != nil {
return commitVerification
}
}
}
}
return &CommitVerification{
CommittingUser: committer,
Verified: false,
Reason: NoKeyFound,
}
}
func verifySSHCommitVerification(sig, payload string, k *PublicKey, committer, signer *user_model.User, email string) *CommitVerification {
if err := sshsig.Verify(bytes.NewBuffer([]byte(payload)), []byte(sig), []byte(k.Content), "git"); err != nil {
return nil
}
return &CommitVerification{ // Everything is ok
CommittingUser: committer,
Verified: true,
Reason: fmt.Sprintf("%s / %s", signer.Name, k.Fingerprint),
SigningUser: signer,
SigningSSHKey: k,
SigningEmail: email,
}
}

View File

@ -6,27 +6,13 @@ package asymkey
import ( import (
"context" "context"
"fmt" "fmt"
"strings"
"code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/process"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/util"
"golang.org/x/crypto/ssh" "golang.org/x/crypto/ssh"
"xorm.io/builder" "xorm.io/builder"
) )
// ___________.__ .__ __
// \_ _____/|__| ____ ____ ________________________|__| _____/ |_
// | __) | |/ \ / ___\_/ __ \_ __ \____ \_ __ \ |/ \ __\
// | \ | | | \/ /_/ > ___/| | \/ |_> > | \/ | | \ |
// \___ / |__|___| /\___ / \___ >__| | __/|__| |__|___| /__|
// \/ \//_____/ \/ |__| \/
//
// This file contains functions for fingerprinting SSH keys
//
// The database is used in checkKeyFingerprint however most of these functions probably belong in a module // The database is used in checkKeyFingerprint however most of these functions probably belong in a module
// checkKeyFingerprint only checks if key fingerprint has been used as public key, // checkKeyFingerprint only checks if key fingerprint has been used as public key,
@ -41,29 +27,6 @@ func checkKeyFingerprint(ctx context.Context, fingerprint string) error {
return nil return nil
} }
func calcFingerprintSSHKeygen(publicKeyContent string) (string, error) {
// Calculate fingerprint.
tmpPath, err := writeTmpKeyFile(publicKeyContent)
if err != nil {
return "", err
}
defer func() {
if err := util.Remove(tmpPath); err != nil {
log.Warn("Unable to remove temporary key file: %s: Error: %v", tmpPath, err)
}
}()
stdout, stderr, err := process.GetManager().Exec("AddPublicKey", "ssh-keygen", "-lf", tmpPath)
if err != nil {
if strings.Contains(stderr, "is not a public key file") {
return "", ErrKeyUnableVerify{stderr}
}
return "", util.NewInvalidArgumentErrorf("'ssh-keygen -lf %s' failed with error '%s': %s", tmpPath, err, stderr)
} else if len(stdout) < 2 {
return "", util.NewInvalidArgumentErrorf("not enough output for calculating fingerprint: %s", stdout)
}
return strings.Split(stdout, " ")[1], nil
}
func calcFingerprintNative(publicKeyContent string) (string, error) { func calcFingerprintNative(publicKeyContent string) (string, error) {
// Calculate fingerprint. // Calculate fingerprint.
pk, _, _, _, err := ssh.ParseAuthorizedKey([]byte(publicKeyContent)) pk, _, _, _, err := ssh.ParseAuthorizedKey([]byte(publicKeyContent))
@ -75,15 +38,12 @@ func calcFingerprintNative(publicKeyContent string) (string, error) {
// CalcFingerprint calculate public key's fingerprint // CalcFingerprint calculate public key's fingerprint
func CalcFingerprint(publicKeyContent string) (string, error) { func CalcFingerprint(publicKeyContent string) (string, error) {
// Call the method based on configuration fp, err := calcFingerprintNative(publicKeyContent)
useNative := setting.SSH.KeygenPath == ""
calcFn := util.Iif(useNative, calcFingerprintNative, calcFingerprintSSHKeygen)
fp, err := calcFn(publicKeyContent)
if err != nil { if err != nil {
if IsErrKeyUnableVerify(err) { if IsErrKeyUnableVerify(err) {
return "", err return "", err
} }
return "", fmt.Errorf("CalcFingerprint(%s): %w", util.Iif(useNative, "native", "ssh-keygen"), err) return "", fmt.Errorf("CalcFingerprint: %w", err)
} }
return fp, nil return fp, nil
} }

View File

@ -10,14 +10,12 @@ import (
"encoding/base64" "encoding/base64"
"encoding/binary" "encoding/binary"
"encoding/pem" "encoding/pem"
"errors"
"fmt" "fmt"
"math/big" "math/big"
"os"
"strconv"
"strings" "strings"
"code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/process"
"code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/util" "code.gitea.io/gitea/modules/util"
@ -93,7 +91,7 @@ func parseKeyString(content string) (string, error) {
block, _ := pem.Decode([]byte(content)) block, _ := pem.Decode([]byte(content))
if block == nil { if block == nil {
return "", fmt.Errorf("failed to parse PEM block containing the public key") return "", errors.New("failed to parse PEM block containing the public key")
} }
if strings.Contains(block.Type, "PRIVATE") { if strings.Contains(block.Type, "PRIVATE") {
return "", ErrKeyIsPrivate return "", ErrKeyIsPrivate
@ -174,20 +172,9 @@ func CheckPublicKeyString(content string) (_ string, err error) {
return content, nil return content, nil
} }
var ( keyType, length, err := SSHNativeParsePublicKey(content)
fnName string
keyType string
length int
)
if len(setting.SSH.KeygenPath) == 0 {
fnName = "SSHNativeParsePublicKey"
keyType, length, err = SSHNativeParsePublicKey(content)
} else {
fnName = "SSHKeyGenParsePublicKey"
keyType, length, err = SSHKeyGenParsePublicKey(content)
}
if err != nil { if err != nil {
return "", fmt.Errorf("%s: %w", fnName, err) return "", fmt.Errorf("SSHNativeParsePublicKey: %w", err)
} }
log.Trace("Key info [native: %v]: %s-%d", setting.SSH.StartBuiltinServer, keyType, length) log.Trace("Key info [native: %v]: %s-%d", setting.SSH.StartBuiltinServer, keyType, length)
@ -257,56 +244,3 @@ func SSHNativeParsePublicKey(keyLine string) (string, int, error) {
} }
return "", 0, fmt.Errorf("unsupported key length detection for type: %s", pkey.Type()) return "", 0, fmt.Errorf("unsupported key length detection for type: %s", pkey.Type())
} }
// writeTmpKeyFile writes key content to a temporary file
// and returns the name of that file, along with any possible errors.
func writeTmpKeyFile(content string) (string, error) {
tmpFile, err := os.CreateTemp(setting.SSH.KeyTestPath, "gitea_keytest")
if err != nil {
return "", fmt.Errorf("TempFile: %w", err)
}
defer tmpFile.Close()
if _, err = tmpFile.WriteString(content); err != nil {
return "", fmt.Errorf("WriteString: %w", err)
}
return tmpFile.Name(), nil
}
// SSHKeyGenParsePublicKey extracts key type and length using ssh-keygen.
func SSHKeyGenParsePublicKey(key string) (string, int, error) {
tmpName, err := writeTmpKeyFile(key)
if err != nil {
return "", 0, fmt.Errorf("writeTmpKeyFile: %w", err)
}
defer func() {
if err := util.Remove(tmpName); err != nil {
log.Warn("Unable to remove temporary key file: %s: Error: %v", tmpName, err)
}
}()
keygenPath := setting.SSH.KeygenPath
if len(keygenPath) == 0 {
keygenPath = "ssh-keygen"
}
stdout, stderr, err := process.GetManager().Exec("SSHKeyGenParsePublicKey", keygenPath, "-lf", tmpName)
if err != nil {
return "", 0, fmt.Errorf("fail to parse public key: %s - %s", err, stderr)
}
if strings.Contains(stdout, "is not a public key file") {
return "", 0, ErrKeyUnableVerify{stdout}
}
fields := strings.Split(stdout, " ")
if len(fields) < 4 {
return "", 0, fmt.Errorf("invalid public key line: %s", stdout)
}
keyType := strings.Trim(fields[len(fields)-1], "()\r\n")
length, err := strconv.ParseInt(fields[0], 10, 32)
if err != nil {
return "", 0, err
}
return strings.ToLower(keyType), int(length), nil
}

View File

@ -42,29 +42,7 @@ func Test_SSHParsePublicKey(t *testing.T) {
keyTypeN, lengthN, err := SSHNativeParsePublicKey(tc.content) keyTypeN, lengthN, err := SSHNativeParsePublicKey(tc.content)
assert.NoError(t, err) assert.NoError(t, err)
assert.Equal(t, tc.keyType, keyTypeN) assert.Equal(t, tc.keyType, keyTypeN)
assert.EqualValues(t, tc.length, lengthN) assert.Equal(t, tc.length, lengthN)
})
if tc.skipSSHKeygen {
return
}
t.Run("SSHKeygen", func(t *testing.T) {
keyTypeK, lengthK, err := SSHKeyGenParsePublicKey(tc.content)
if err != nil {
// Some servers do not support ecdsa format.
if !strings.Contains(err.Error(), "line 1 too long:") {
assert.FailNow(t, "%v", err)
}
}
assert.Equal(t, tc.keyType, keyTypeK)
assert.EqualValues(t, tc.length, lengthK)
})
t.Run("SSHParseKeyNative", func(t *testing.T) {
keyTypeK, lengthK, err := SSHNativeParsePublicKey(tc.content)
if err != nil {
assert.FailNow(t, "%v", err)
}
assert.Equal(t, tc.keyType, keyTypeK)
assert.EqualValues(t, tc.length, lengthK)
}) })
}) })
} }
@ -186,14 +164,6 @@ func Test_calcFingerprint(t *testing.T) {
assert.NoError(t, err) assert.NoError(t, err)
assert.Equal(t, tc.fp, fpN) assert.Equal(t, tc.fp, fpN)
}) })
if tc.skipSSHKeygen {
return
}
t.Run("SSHKeygen", func(t *testing.T) {
fpK, err := calcFingerprintSSHKeygen(tc.content)
assert.NoError(t, err)
assert.Equal(t, tc.fp, fpK)
})
}) })
} }
} }

View File

@ -4,8 +4,8 @@
package asymkey package asymkey
import ( import (
"bytes"
"context" "context"
"strings"
"code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/log"
@ -30,11 +30,11 @@ func VerifySSHKey(ctx context.Context, ownerID int64, fingerprint, token, signat
return "", ErrKeyNotExist{} return "", ErrKeyNotExist{}
} }
err = sshsig.Verify(bytes.NewBuffer([]byte(token)), []byte(signature), []byte(key.Content), "gitea") err = sshsig.Verify(strings.NewReader(token), []byte(signature), []byte(key.Content), "gitea")
if err != nil { if err != nil {
// edge case for Windows based shells that will add CR LF if piped to ssh-keygen command // edge case for Windows based shells that will add CR LF if piped to ssh-keygen command
// see https://github.com/PowerShell/PowerShell/issues/5974 // see https://github.com/PowerShell/PowerShell/issues/5974
if sshsig.Verify(bytes.NewBuffer([]byte(token+"\r\n")), []byte(signature), []byte(key.Content), "gitea") != nil { if sshsig.Verify(strings.NewReader(token+"\r\n"), []byte(signature), []byte(key.Content), "gitea") != nil {
log.Error("Unable to validate token signature. Error: %v", err) log.Error("Unable to validate token signature. Error: %v", err)
return "", ErrSSHInvalidTokenSignature{ return "", ErrSSHInvalidTokenSignature{
Fingerprint: key.Fingerprint, Fingerprint: key.Fingerprint,

View File

@ -5,6 +5,7 @@ package auth
import ( import (
"fmt" "fmt"
"slices"
"strings" "strings"
"code.gitea.io/gitea/models/perm" "code.gitea.io/gitea/models/perm"
@ -14,7 +15,7 @@ import (
type AccessTokenScopeCategory int type AccessTokenScopeCategory int
const ( const (
AccessTokenScopeCategoryActivityPub = iota AccessTokenScopeCategoryActivityPub AccessTokenScopeCategory = iota
AccessTokenScopeCategoryAdmin AccessTokenScopeCategoryAdmin
AccessTokenScopeCategoryMisc // WARN: this is now just a placeholder, don't remove it which will change the following values AccessTokenScopeCategoryMisc // WARN: this is now just a placeholder, don't remove it which will change the following values
AccessTokenScopeCategoryNotification AccessTokenScopeCategoryNotification
@ -193,6 +194,14 @@ var accessTokenScopes = map[AccessTokenScopeLevel]map[AccessTokenScopeCategory]A
}, },
} }
func GetAccessTokenCategories() (res []string) {
for _, cat := range accessTokenScopes[Read] {
res = append(res, strings.TrimPrefix(string(cat), "read:"))
}
slices.Sort(res)
return res
}
// GetRequiredScopes gets the specific scopes for a given level and categories // GetRequiredScopes gets the specific scopes for a given level and categories
func GetRequiredScopes(level AccessTokenScopeLevel, scopeCategories ...AccessTokenScopeCategory) []AccessTokenScope { func GetRequiredScopes(level AccessTokenScopeLevel, scopeCategories ...AccessTokenScopeCategory) []AccessTokenScope {
scopes := make([]AccessTokenScope, 0, len(scopeCategories)) scopes := make([]AccessTokenScope, 0, len(scopeCategories))
@ -270,6 +279,9 @@ func (s AccessTokenScope) parse() (accessTokenScopeBitmap, error) {
// StringSlice returns the AccessTokenScope as a []string // StringSlice returns the AccessTokenScope as a []string
func (s AccessTokenScope) StringSlice() []string { func (s AccessTokenScope) StringSlice() []string {
if s == "" {
return nil
}
return strings.Split(string(s), ",") return strings.Split(string(s), ",")
} }
@ -283,6 +295,10 @@ func (s AccessTokenScope) Normalize() (AccessTokenScope, error) {
return bitmap.toScope(), nil return bitmap.toScope(), nil
} }
func (s AccessTokenScope) HasPermissionScope() bool {
return s != "" && s != AccessTokenScopePublicOnly
}
// PublicOnly checks if this token scope is limited to public resources // PublicOnly checks if this token scope is limited to public resources
func (s AccessTokenScope) PublicOnly() (bool, error) { func (s AccessTokenScope) PublicOnly() (bool, error) {
bitmap, err := s.parse() bitmap, err := s.parse()

View File

@ -17,6 +17,7 @@ type scopeTestNormalize struct {
} }
func TestAccessTokenScope_Normalize(t *testing.T) { func TestAccessTokenScope_Normalize(t *testing.T) {
assert.Equal(t, []string{"activitypub", "admin", "issue", "misc", "notification", "organization", "package", "repository", "user"}, GetAccessTokenCategories())
tests := []scopeTestNormalize{ tests := []scopeTestNormalize{
{"", "", nil}, {"", "", nil},
{"write:misc,write:notification,read:package,write:notification,public-only", "public-only,write:misc,write:notification,read:package", nil}, {"write:misc,write:notification,read:package,write:notification,public-only", "public-only,write:misc,write:notification,read:package", nil},
@ -25,13 +26,13 @@ func TestAccessTokenScope_Normalize(t *testing.T) {
{"write:activitypub,write:admin,write:misc,write:notification,write:organization,write:package,write:issue,write:repository,write:user,public-only", "public-only,all", nil}, {"write:activitypub,write:admin,write:misc,write:notification,write:organization,write:package,write:issue,write:repository,write:user,public-only", "public-only,all", nil},
} }
for _, scope := range []string{"activitypub", "admin", "misc", "notification", "organization", "package", "issue", "repository", "user"} { for _, scope := range GetAccessTokenCategories() {
tests = append(tests, tests = append(tests,
scopeTestNormalize{AccessTokenScope(fmt.Sprintf("read:%s", scope)), AccessTokenScope(fmt.Sprintf("read:%s", scope)), nil}, scopeTestNormalize{AccessTokenScope("read:" + scope), AccessTokenScope("read:" + scope), nil},
scopeTestNormalize{AccessTokenScope(fmt.Sprintf("write:%s", scope)), AccessTokenScope(fmt.Sprintf("write:%s", scope)), nil}, scopeTestNormalize{AccessTokenScope("write:" + scope), AccessTokenScope("write:" + scope), nil},
scopeTestNormalize{AccessTokenScope(fmt.Sprintf("write:%[1]s,read:%[1]s", scope)), AccessTokenScope(fmt.Sprintf("write:%s", scope)), nil}, scopeTestNormalize{AccessTokenScope(fmt.Sprintf("write:%[1]s,read:%[1]s", scope)), AccessTokenScope("write:" + scope), nil},
scopeTestNormalize{AccessTokenScope(fmt.Sprintf("read:%[1]s,write:%[1]s", scope)), AccessTokenScope(fmt.Sprintf("write:%s", scope)), nil}, scopeTestNormalize{AccessTokenScope(fmt.Sprintf("read:%[1]s,write:%[1]s", scope)), AccessTokenScope("write:" + scope), nil},
scopeTestNormalize{AccessTokenScope(fmt.Sprintf("read:%[1]s,write:%[1]s,write:%[1]s", scope)), AccessTokenScope(fmt.Sprintf("write:%s", scope)), nil}, scopeTestNormalize{AccessTokenScope(fmt.Sprintf("read:%[1]s,write:%[1]s,write:%[1]s", scope)), AccessTokenScope("write:" + scope), nil},
) )
} }
@ -59,23 +60,23 @@ func TestAccessTokenScope_HasScope(t *testing.T) {
{"public-only", "read:issue", false, nil}, {"public-only", "read:issue", false, nil},
} }
for _, scope := range []string{"activitypub", "admin", "misc", "notification", "organization", "package", "issue", "repository", "user"} { for _, scope := range GetAccessTokenCategories() {
tests = append(tests, tests = append(tests,
scopeTestHasScope{ scopeTestHasScope{
AccessTokenScope(fmt.Sprintf("read:%s", scope)), AccessTokenScope("read:" + scope),
AccessTokenScope(fmt.Sprintf("read:%s", scope)), true, nil, AccessTokenScope("read:" + scope), true, nil,
}, },
scopeTestHasScope{ scopeTestHasScope{
AccessTokenScope(fmt.Sprintf("write:%s", scope)), AccessTokenScope("write:" + scope),
AccessTokenScope(fmt.Sprintf("write:%s", scope)), true, nil, AccessTokenScope("write:" + scope), true, nil,
}, },
scopeTestHasScope{ scopeTestHasScope{
AccessTokenScope(fmt.Sprintf("write:%s", scope)), AccessTokenScope("write:" + scope),
AccessTokenScope(fmt.Sprintf("read:%s", scope)), true, nil, AccessTokenScope("read:" + scope), true, nil,
}, },
scopeTestHasScope{ scopeTestHasScope{
AccessTokenScope(fmt.Sprintf("read:%s", scope)), AccessTokenScope("read:" + scope),
AccessTokenScope(fmt.Sprintf("write:%s", scope)), false, nil, AccessTokenScope("write:" + scope), false, nil,
}, },
) )
} }

View File

@ -25,7 +25,7 @@ func TestOAuth2Application_GenerateClientSecret(t *testing.T) {
func BenchmarkOAuth2Application_GenerateClientSecret(b *testing.B) { func BenchmarkOAuth2Application_GenerateClientSecret(b *testing.B) {
assert.NoError(b, unittest.PrepareTestDatabase()) assert.NoError(b, unittest.PrepareTestDatabase())
app := unittest.AssertExistsAndLoadBean(b, &auth_model.OAuth2Application{ID: 1}) app := unittest.AssertExistsAndLoadBean(b, &auth_model.OAuth2Application{ID: 1})
for i := 0; i < b.N; i++ { for b.Loop() {
_, _ = app.GenerateClientSecret(db.DefaultContext) _, _ = app.GenerateClientSecret(db.DefaultContext)
} }
} }
@ -126,7 +126,7 @@ func TestOAuth2Application_CreateGrant(t *testing.T) {
assert.NotNil(t, grant) assert.NotNil(t, grant)
assert.Equal(t, int64(2), grant.UserID) assert.Equal(t, int64(2), grant.UserID)
assert.Equal(t, int64(1), grant.ApplicationID) assert.Equal(t, int64(1), grant.ApplicationID)
assert.Equal(t, "", grant.Scope) assert.Empty(t, grant.Scope)
} }
//////////////////// Grant //////////////////// Grant

View File

@ -13,6 +13,8 @@ import (
"code.gitea.io/gitea/modules/json" "code.gitea.io/gitea/modules/json"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"xorm.io/xorm"
"xorm.io/xorm/schemas" "xorm.io/xorm/schemas"
) )
@ -54,7 +56,8 @@ func TestDumpAuthSource(t *testing.T) {
sb := new(strings.Builder) sb := new(strings.Builder)
db.DumpTables([]*schemas.Table{authSourceSchema}, sb) // TODO: this test is quite hacky, it should use a low-level "select" (without model processors) but not a database dump
engine := db.GetEngine(db.DefaultContext).(*xorm.Engine)
require.NoError(t, engine.DumpTables([]*schemas.Table{authSourceSchema}, sb))
assert.Contains(t, sb.String(), `"Provider":"ConvertibleSourceName"`) assert.Contains(t, sb.String(), `"Provider":"ConvertibleSourceName"`)
} }

View File

@ -44,7 +44,7 @@ func TestWebAuthnCredential_UpdateSignCount(t *testing.T) {
cred := unittest.AssertExistsAndLoadBean(t, &auth_model.WebAuthnCredential{ID: 1}) cred := unittest.AssertExistsAndLoadBean(t, &auth_model.WebAuthnCredential{ID: 1})
cred.SignCount = 1 cred.SignCount = 1
assert.NoError(t, cred.UpdateSignCount(db.DefaultContext)) assert.NoError(t, cred.UpdateSignCount(db.DefaultContext))
unittest.AssertExistsIf(t, true, &auth_model.WebAuthnCredential{ID: 1, SignCount: 1}) unittest.AssertExistsAndLoadBean(t, &auth_model.WebAuthnCredential{ID: 1, SignCount: 1})
} }
func TestWebAuthnCredential_UpdateLargeCounter(t *testing.T) { func TestWebAuthnCredential_UpdateLargeCounter(t *testing.T) {
@ -52,7 +52,7 @@ func TestWebAuthnCredential_UpdateLargeCounter(t *testing.T) {
cred := unittest.AssertExistsAndLoadBean(t, &auth_model.WebAuthnCredential{ID: 1}) cred := unittest.AssertExistsAndLoadBean(t, &auth_model.WebAuthnCredential{ID: 1})
cred.SignCount = 0xffffffff cred.SignCount = 0xffffffff
assert.NoError(t, cred.UpdateSignCount(db.DefaultContext)) assert.NoError(t, cred.UpdateSignCount(db.DefaultContext))
unittest.AssertExistsIf(t, true, &auth_model.WebAuthnCredential{ID: 1, SignCount: 0xffffffff}) unittest.AssertExistsAndLoadBean(t, &auth_model.WebAuthnCredential{ID: 1, SignCount: 0xffffffff})
} }
func TestCreateCredential(t *testing.T) { func TestCreateCredential(t *testing.T) {
@ -63,5 +63,5 @@ func TestCreateCredential(t *testing.T) {
assert.Equal(t, "WebAuthn Created Credential", res.Name) assert.Equal(t, "WebAuthn Created Credential", res.Name)
assert.Equal(t, []byte("Test"), res.CredentialID) assert.Equal(t, []byte("Test"), res.CredentialID)
unittest.AssertExistsIf(t, true, &auth_model.WebAuthnCredential{Name: "WebAuthn Created Credential", UserID: 1}) unittest.AssertExistsAndLoadBean(t, &auth_model.WebAuthnCredential{Name: "WebAuthn Created Credential", UserID: 1})
} }

View File

@ -140,7 +140,7 @@ func CheckCollations(x *xorm.Engine) (*CheckCollationsResult, error) {
} }
func CheckCollationsDefaultEngine() (*CheckCollationsResult, error) { func CheckCollationsDefaultEngine() (*CheckCollationsResult, error) {
return CheckCollations(x) return CheckCollations(xormEngine)
} }
func alterDatabaseCollation(x *xorm.Engine, collation string) error { func alterDatabaseCollation(x *xorm.Engine, collation string) error {

View File

@ -94,7 +94,7 @@ func GetEngine(ctx context.Context) Engine {
if e := getExistingEngine(ctx); e != nil { if e := getExistingEngine(ctx); e != nil {
return e return e
} }
return x.Context(ctx) return xormEngine.Context(ctx)
} }
// getExistingEngine gets an existing db Engine/Statement from this context or returns nil // getExistingEngine gets an existing db Engine/Statement from this context or returns nil
@ -155,7 +155,7 @@ func TxContext(parentCtx context.Context) (*Context, Committer, error) {
return newContext(parentCtx, sess), &halfCommitter{committer: sess}, nil return newContext(parentCtx, sess), &halfCommitter{committer: sess}, nil
} }
sess := x.NewSession() sess := xormEngine.NewSession()
if err := sess.Begin(); err != nil { if err := sess.Begin(); err != nil {
_ = sess.Close() _ = sess.Close()
return nil, nil, err return nil, nil, err
@ -179,7 +179,7 @@ func WithTx(parentCtx context.Context, f func(ctx context.Context) error) error
} }
func txWithNoCheck(parentCtx context.Context, f func(ctx context.Context) error) error { func txWithNoCheck(parentCtx context.Context, f func(ctx context.Context) error) error {
sess := x.NewSession() sess := xormEngine.NewSession()
defer sess.Close() defer sess.Close()
if err := sess.Begin(); err != nil { if err := sess.Begin(); err != nil {
return err return err
@ -289,6 +289,9 @@ func FindIDs(ctx context.Context, tableName, idCol string, cond builder.Cond) ([
// DecrByIDs decreases the given column for entities of the "bean" type with one of the given ids by one // DecrByIDs decreases the given column for entities of the "bean" type with one of the given ids by one
// Timestamps of the entities won't be updated // Timestamps of the entities won't be updated
func DecrByIDs(ctx context.Context, ids []int64, decrCol string, bean any) error { func DecrByIDs(ctx context.Context, ids []int64, decrCol string, bean any) error {
if len(ids) == 0 {
return nil
}
_, err := GetEngine(ctx).Decr(decrCol).In("id", ids).NoAutoCondition().NoAutoTime().Update(bean) _, err := GetEngine(ctx).Decr(decrCol).In("id", ids).NoAutoCondition().NoAutoTime().Update(bean)
return err return err
} }
@ -322,7 +325,7 @@ func CountByBean(ctx context.Context, bean any) (int64, error) {
// TableName returns the table name according a bean object // TableName returns the table name according a bean object
func TableName(bean any) string { func TableName(bean any) string {
return x.TableName(bean) return xormEngine.TableName(bean)
} }
// InTransaction returns true if the engine is in a transaction otherwise return false // InTransaction returns true if the engine is in a transaction otherwise return false

Some files were not shown because too many files have changed in this diff Show More