Compare commits

..

76 Commits

Author SHA1 Message Date
Lunny Xiao
eaa916a786 release notes for 1.25.2 (#35986)
~Wait #35988~

---------

Signed-off-by: wxiaoguang <wxiaoguang@gmail.com>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2025-11-22 11:05:00 -08:00
Lunny Xiao
91901c2a60 Allow empty commit when merging pull request with squash style (#35989) (#36003) 2025-11-22 09:17:28 -08:00
Lunny Xiao
20cf4b7849 Fix various permission & login related bugs (#36002) (#36004)
Backport #36002 

Permission & protection check:

- Fix Delete Release permission check
- Fix Update Pull Request with rebase branch protection check
- Fix Issue Dependency permission check
- Fix Delete Comment History ID check

Information leaking:

- Show unified message for non-existing user and invalid password
    - Fix #35984
- Don't expose release draft to non-writer users.
- Make API returns signature's email address instead of the user
profile's.

Auth & Login:

- Avoid GCM OAuth2 attempt when OAuth2 is disabled
    - Fix #35510

---------

Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2025-11-22 12:33:48 +00:00
Lunny Xiao
5e7207d428 upgrade golang.org/x/crypto to 0.45.0 (#35988) 2025-11-20 17:25:35 -05:00
Giteabot
e3bfee80dd Change project default column icon to 'star' (#35967) (#35979)
Backport #35967 by @DrMaxNix

Consistently use a `star` icon to highlight the default column of a
project.
The icon is both shown while viewing the project, as well as while
changing the default status of this column.

<img width="1065" height="370" alt="image"
src="https://github.com/user-attachments/assets/1ca5773d-8eec-4b90-ad0b-22b1f4bd4cfd"
/>

Co-authored-by: DrMaxNix <git@drmaxnix.de>
2025-11-19 10:43:48 +01:00
Giteabot
f93e2cf301 Misc CSS fixes (#35888) (#35981)
Backport #35888 by @silverwind

Fixes: https://github.com/go-gitea/gitea/issues/35913
Fixes: https://github.com/go-gitea/gitea/issues/35942

Contains a number of minor CSS fixes.

Fix missing border on targeted speech bubble
<img width="158" height="90" alt="Screenshot 2025-11-06 at 22 43 31"
src="https://github.com/user-attachments/assets/94696191-353a-4782-a998-2a3d5552ab71"
/>

Add padding to inline comments, slightly more padding around emoji
button
<img width="823" height="301" alt="Screenshot 2025-11-06 at 22 38 39"
src="https://github.com/user-attachments/assets/3ed8f113-13d2-4fad-9d12-81a670540e0b"
/>

Center text on header in code search results
<img width="1328" height="295" alt="Screenshot 2025-11-06 at 22 08 01"
src="https://github.com/user-attachments/assets/41e3d279-8504-4435-9347-e9b969cdfaa2"
/>

Tweak emoji selector, reducing font size primarily
<img width="251" height="219" alt="Screenshot 2025-11-06 at 22 29 46"
src="https://github.com/user-attachments/assets/e892646e-129f-44fd-8333-7a8e14863f03"
/>

Minor tweaks to repo sidebar, reduce font size by 1px, center "Release"
text with label.
<img width="390" height="586" alt="image"
src="https://github.com/user-attachments/assets/397dc36b-11e6-42df-bcdf-e97f4280a90e"
/>

Fix issue comment buttons being misaligned on mobile
<img width="757" height="160" alt="Screenshot 2025-11-06 at 22 50 19"
src="https://github.com/user-attachments/assets/1609d104-1bfe-4913-bfa0-6f4739716d61"
/>

Add highlight to actions re-run icon
<img width="116" height="106" alt="Screenshot 2025-11-06 at 23 04 30"
src="https://github.com/user-attachments/assets/0daed0ac-ef59-432a-b534-b4256d38393b"
/>

Fix actions re-run button overflow
<img width="214" height="125" alt="image"
src="https://github.com/user-attachments/assets/d5c79ce6-ad31-4c06-a411-d79eefb72d02"
/>

Signed-off-by: silverwind <me@silverwind.io>
Co-authored-by: silverwind <me@silverwind.io>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2025-11-19 08:16:54 +01:00
Giteabot
1b01d6de82 Fix container push tag overwriting (#35936) (#35954)
Backport #35936 by wxiaoguang

Fix #35853

Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2025-11-14 12:22:23 +08:00
Giteabot
d67cd622d0 Fix corrupted external render content (#35946) (#35950)
Backport #35946 by wxiaoguang

Fix #35944

Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2025-11-14 02:15:36 +00:00
Giteabot
15f3e9d5a5 Don't show unnecessary error message to end users for DeleteBranchAfterMerge (#35937) (#35941)
Backport #35937 by wxiaoguang

Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2025-11-12 23:31:05 +00:00
Giteabot
01fa8b2b7e Limit read bytes instead of ReadAll (#35928) (#35934)
Backport #35928 by wxiaoguang

Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2025-11-13 02:26:27 +08:00
Giteabot
1d9ae7ac23 Load jQuery as early as possible to support custom scripts (#35926) (#35929)
Backport #35926 by wxiaoguang

Fix #35923

Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2025-11-12 07:24:21 +08:00
Giteabot
01873a99c1 Allow to display embed images/pdfs when SERVE_DIRECT was enabled on MinIO storage (#35882) (#35917)
Backport #35882 by lifegpc

Co-authored-by: lifegpc <g1710431395@gmail.com>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2025-11-11 02:24:06 +00:00
Giteabot
ce70863793 Use correct form field for allowed force push users in branch protection API (#35894) (#35908)
Backport #35894 by zorrobiwan

Signed-off-by: Alberty Pascal <github@albertyorban.be>
Co-authored-by: Alberty Pascal <github@albertyorban.be>
2025-11-11 01:39:35 +00:00
Giteabot
327f2207dc Make OAuth2 issuer configurable (#35915) (#35916)
Backport #35915 by wxiaoguang
2025-11-10 16:12:25 +00:00
Giteabot
db876d8f17 Fix #35763: Add proper page title for project pages (#35773) (#35909)
Backport #35773 by @mithileshgupta12

Co-authored-by: Mithilesh Gupta <mithileshgupta059@gmail.com>
Co-authored-by: Mithilesh Gupta <guptamithilesh@protonmail.com>
2025-11-10 09:42:14 +02:00
Giteabot
2b71bf283b Display source code downloads last for release attachments (#35897) (#35903)
Backport #35897 by lutinglt

Typically, you want to download the binaries, not the source code.

Co-authored-by: 鲁汀 <131967983+lutinglt@users.noreply.github.com>
Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
2025-11-09 14:51:36 +08:00
Giteabot
1ca4fef611 Fix team member access check (#35899) (#35905)
Backport #35899 by wxiaoguang

Fix #35499

Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2025-11-09 03:44:53 +00:00
Giteabot
70ee6b9029 Fix conda null depend issue (#35900) (#35902)
Backport #35900 by Luohaothu

This fixes issue #35895

Co-authored-by: Luohao Wang <luohaothu@live.com>
2025-11-08 16:37:00 +00:00
wxiaoguang
e5b404ec53 Fix avatar upload error handling (#35887) (#35890)
Backport #35887
2025-11-07 11:25:34 +08:00
Giteabot
5842cd23a6 Contribution heatmap improvements (#35876) (#35880)
Backport #35876 by @silverwind

1. Set a fixed height on the element, preventing the content after the
element from shifting on page load. This uses CSS [container query
length
units](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_containment/Container_queries#container_query_length_units)
as I saw no other way because of the non-linear scaling of the element.
2. Move the "total-contributions" text into the existing vue slot,
eliminating the need for absolute positioning.

Co-authored-by: silverwind <me@silverwind.io>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2025-11-06 08:51:49 +00:00
Giteabot
289bd9694b Remove padding override on .ui .sha.label (#35864) (#35873)
Backport #35864 by @silverwind

Since upgrading to v1.25, I noticed the SHA labels have slightly
different padding than before. I can't pinpoint exactly which change it
was. Fix it by removing the padding override on `.ui .sha.label` and
make the one on`.ui.label` (`2px 6px`) take effect which matches 1.24
rendering.

Before:

<img width="135" height="172" alt="image"
src="https://github.com/user-attachments/assets/2781a854-be08-4a11-bde0-d3699b2b7454"
/>

After:

<img width="139" height="162" alt="image"
src="https://github.com/user-attachments/assets/5c864fa3-c1f9-4452-ae58-5411dd445865"
/>

Co-authored-by: silverwind <me@silverwind.io>
2025-11-06 06:06:36 +00:00
Giteabot
154d7521a5 fix(api/repo/contents): set the dates to now when not specified by the caller (#35861) (#35874)
Backport #35861 by @divyun

Since 1.25.0, the dates get set to `2001-01-01T00:00:00Z`, when not
specified by the caller.

Fixes #35860

Co-authored-by: Divyun Raje Vaid <mail@divyun.com>
2025-11-06 13:08:06 +08:00
Giteabot
24189dcced Fix pull description code label background (#35865) (#35870)
Backport #35865 by @silverwind

Fix visual regression from https://github.com/go-gitea/gitea/pull/35567:

Before:

<img width="612" height="33" alt="image"
src="https://github.com/user-attachments/assets/aee4017c-b8b9-4ac2-9809-9d3eb3fda56c"
/>

After:

<img width="613" height="32" alt="image"
src="https://github.com/user-attachments/assets/ee6624da-b417-4e3b-8773-88c77c2cd672"
/>

Co-authored-by: silverwind <me@silverwind.io>
2025-11-05 17:29:06 +00:00
wxiaoguang
f84bf259ad Fix gogit ListEntriesRecursiveWithSize (#35862)
It needs to use full git path. Fix #35852.
2025-11-05 19:19:47 +02:00
Lunny Xiao
470b21056a Add changelog for 1.25.1 and add missing chagnelog for 1.24.x (#35838) 2025-11-04 11:17:59 -08:00
Zettat123
61011f1648 Add a doctor command to fix inconsistent run status (#35840) (#35845)
Backport #35840

#35783 fixes an actions rerun bug. Due to this bug, some runs may be
incorrectly marked as `StatusWaiting` even though all the jobs are in
done status. These runs cannot be run or cancelled. This PR adds a new
doctor command to fix the inconsistent run status.

```
gitea doctor check --run fix-actions-unfinished-run-status --fix
```
2025-11-04 11:16:36 -08:00
Giteabot
7ea9722c1d Make ACME email optional (#35849) (#35857)
Backport #35849 by @wxiaoguang

Fix a regression from #33668

Fix #35847

Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2025-11-04 10:22:26 -08:00
Giteabot
297f63af42 Remove wrong code (#35846) (#35856)
Backport #35846 by @lunny

Follow #35821
Fix https://github.com/go-gitea/gitea/pull/35844#issuecomment-3483521045

The reviewed file numbers and progress have been set from backend so
that we don't need to update the numbers when clicking `load more`.

Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
2025-11-04 20:04:08 +02:00
Lunny Xiao
6a55749359 Fix incorrect pull request counter (#35819) (#35841)
Fix #35781, #27472
Backport #35819 

The PR will not correct the wrong numbers automatically.

There is a cron task `check_repo_stats` which will be run when Gitea
start or midnight. It will correct the numbers.
2025-11-04 01:49:47 +00:00
Lunny Xiao
8116742e2d Fix viewed files number is not right if not all files loaded (#35821) (#35844)
Fix #35803
Backport #35821

Signed-off-by: silverwind <me@silverwind.io>
Co-authored-by: silverwind <me@silverwind.io>
2025-11-03 17:19:50 -08:00
Giteabot
0a9cbf3228 upgrade go mail to 0.7.2 and fix the bug (#35833) (#35837)
Backport #35833 by @lunny

patch from
https://github.com/wneessen/go-mail/issues/504#issuecomment-3477890515.
Thanks to @wneessen

Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
2025-11-03 20:28:12 +00:00
Giteabot
74dfadb543 Fix circular spin animation direction (#35785) (#35823)
Backport #35785 by @lutinglt

Wait for the status icon to rotate clockwise instead of counterclockwise

before:
![GIF 2025-10-30
10-50-07](https://github.com/user-attachments/assets/3771b0bf-44e4-45a0-bde5-1b2b3dd8ba2a)

after:
![GIF 2025-10-30
10-50-43](https://github.com/user-attachments/assets/c45307fe-39a4-4e60-b48e-9d922c407565)

This can be merged to 1.25

Signed-off-by: 鲁汀 <131967983+lutinglt@users.noreply.github.com>
Signed-off-by: wxiaoguang <wxiaoguang@gmail.com>
Co-authored-by: 鲁汀 <131967983+lutinglt@users.noreply.github.com>
Co-authored-by: lutinglt <lutinglt@users.noreply.github.com>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2025-11-03 09:37:01 +00:00
Giteabot
8ffc1fbfbf Revert gomail to v0.7.0 to fix sending mail failed (#35816) (#35824)
Backport #35816 by @lunny

Revert gomail to the last work version to fix #35794

There is a problem between go mail v0.7.1 to prevent sending email work.
https://github.com/wneessen/go-mail/compare/v0.7.0...v0.7.1

Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
2025-11-03 09:08:13 +00:00
Giteabot
e95378329b Fix clone mixed bug (#35810) (#35822) 2025-11-02 10:20:27 -08:00
Giteabot
fddf6cd63f Fix cli "Before" handling (#35797) (#35808)
Backport #35797 by @wxiaoguang

Regression of #34973

Fix #35796

Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2025-10-31 22:00:14 +01:00
Giteabot
d253e2055b Fix file extension on gogs.png (#35793) (#35799)
Backport #35793 by @silverwind

During https://github.com/go-gitea/gitea/issues/35790, it was noticed
that this PNG image had the wrong file extension. I also verified
`dingtalk.ico` and that one is actually an `.ico`.

Co-authored-by: silverwind <me@silverwind.io>
2025-10-31 03:33:27 +01:00
Giteabot
e194d89c74 Improve and fix markup code preview rendering (#35777) (#35787)
Backport #35777 by @silverwind

1. Add the color on the link to the referenced file, which is the more
likely thing the user wants to click
2. Use monospace font on the SHA
3. Tweak text colors
4. Change SHA link to go to the commit instead of the repo root with
commit filter set
5. Added the repo name to the file link text
6. Fix broken line numbering rendering

The only major difference to GitHub is now the missing line numbers.

Before:

<img width="286" height="162" alt="Screenshot 2025-10-29 at 19 09 59"
src="https://github.com/user-attachments/assets/f16b4eec-caf2-4c31-a2b5-ae5f41747d4b"
/>

After:

<img width="378" height="157" alt="image"
src="https://github.com/user-attachments/assets/0c91dfd3-0910-4b2d-a43b-8c87cfbb933e"
/>

For comparison, GitHub rendering:

<img width="286" height="177" alt="image"
src="https://github.com/user-attachments/assets/8a9a07b7-9153-4415-9d7a-5685853e472a"
/>

Co-authored-by: silverwind <me@silverwind.io>
2025-10-30 09:06:44 +00:00
Zettat123
04b6f90889 Fix actions rerun bug (#35783) (#35784)
Backport #35783

Fix #35780, fix #35782 

Rerunning a job or a run is only allowed when the job is done and the
run is done.

Related PR: #34970


98ff7d0773/routers/web/repo/actions/view.go (L239)

We don't need to check run status again in `rerunJob` because the run
status has been changed before `rerunJob`.

---

In fact, the bug described in the above issues will not occur on the
main branch. Because `getRunJobs` is called before updating the run.


98ff7d0773/routers/web/repo/actions/view.go (L425-L435)

So the run status that `rerunJob` checks is the old status.

---------

Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2025-10-30 09:31:42 +01:00
Giteabot
65a37572f3 add pnpm to Snapcraft (#35778) (#35779)
Backport #35778 by techknowlogick

Co-authored-by: techknowlogick <techknowlogick@gitea.com>
2025-10-29 19:35:18 +01:00
Giteabot
f85cd7aeb5 Fix actions schedule update issue (#35767) (#35774)
Backport #35767 by @Zettat123

Fix #34472

Add integration tests for actions schedule update.

---------

Co-authored-by: Zettat123 <zettat123@gmail.com>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2025-10-29 18:51:16 +01:00
Lunny Xiao
cf644d565d Update release notes for 1.25.0 (#35769)
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2025-10-29 09:14:32 -07:00
Giteabot
88a8571b93 Update tab title when navigating file tree (#35757) (#35772)
Backport #35757 by bytedream
2025-10-29 14:04:19 +00:00
Giteabot
45a88e09af Fix "ref-issue" handling in markup (#35739) (#35771)
Backport #35739 by wxiaoguang

This is a follow up for #35662, and also fix #31181, help #30275, fix
#31161

Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2025-10-29 19:03:02 +08:00
Lunny Xiao
6aa1a1e54d Upgrade go mail to 0.7.2 (#35748) (#35750)
backport #35748
2025-10-27 16:50:15 +00:00
Giteabot
18cc3160b5 Revert #18491, fix oauth2 client link account (#35745) (#35751)
Backport #35745 by @wxiaoguang

Fix #35744 by reverting #18491

* "OpenID" options don't mean "OAuth2Client" options
* "OAuth2(server)" options don't mean "OAuth2Client" options

Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2025-10-26 15:26:40 -07:00
Lunny Xiao
123c8d2b81 Fix review request webhook bug (#35339) (#35596)
Frontport from #35339
2025-10-24 19:10:50 +00:00
wxiaoguang
b2f2f8528a Fix external render, make iframe render work (#35727, #35730) (#35731)
Backport #35727 and #35730

---------

Signed-off-by: wxiaoguang <wxiaoguang@gmail.com>
2025-10-23 16:07:17 +08:00
Giteabot
0925089b5e Honor delete branch on merge repo setting when using merge API (#35488) (#35726)
Backport #35488 by @kemzeb

Fix #35463.

---------

Co-authored-by: Kemal Zebari <60799661+kemzeb@users.noreply.github.com>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2025-10-22 09:41:40 -07:00
Giteabot
c84d17b1bb Don't block site admin's operation if SECRET_KEY is lost (#35721) (#35724)
Backport #35721 by wxiaoguang

Related: #24573

Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2025-10-22 05:02:47 +00:00
Giteabot
cb338a2ba1 fix attachment file size limit in server backend (#35519) (#35720)
Backport #35519 by @a1012112796

fix #35512

Co-authored-by: a1012112796 <1012112796@qq.com>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2025-10-21 18:01:59 +00:00
Giteabot
16f4f0d473 Make restricted users can access public repositories (#35693) (#35719)
Backport #35693 by wxiaoguang

Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2025-10-21 15:35:41 +00:00
Giteabot
387a4e72f7 Fix various trivial problems (#35714) (#35718)
Backport #35714 by wxiaoguang

Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2025-10-21 18:02:57 +08:00
Giteabot
ac6d38e4b7 Refactor legacy code (#35708) (#35716)
Backport #35708 by wxiaoguang

Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2025-10-21 05:47:37 +00:00
Giteabot
6df51d4ef5 Avoid emoji mismatch and allow to only enable chosen emojis (#35692) (#35705)
Backport #35692 by wxiaoguang

Fix #23635

Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2025-10-20 08:29:02 +08:00
ChristopherHX
46f695ac65 Fix workflow run event status while rerunning a failed job (#35689) (#35703)
The event reported a completion status instead of requested, therefore
sent an email

Backport #35689
2025-10-19 10:49:20 -07:00
Giteabot
4af1d58c86 Fix various bugs (#35684) (#35696)
Backport #35684 by wxiaoguang
2025-10-19 02:26:03 +08:00
Giteabot
f71df88a6b Use LFS object size instead of blob size when viewing a LFS file (#35679) (#35680)
Backport #35679 by surya-purohit

shows the main LFS filesize instead of the pointer filesize when viewing
a file

Co-authored-by: Surya Purohit <suryaprakash.sharma@sourcefuse.com>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2025-10-16 22:41:24 +08:00
Lunny Xiao
18b178e63f Creating push comments before invoke pull request checking (#35647) (#35668)
Backport #35647 

This PR moved the creation of pushing comments before pull request
mergeable checking. So that when the pull request status changed, the
comments should have been created.

Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2025-10-15 17:42:52 +00:00
Lunny Xiao
1644b8743c Fix build (#35674)
backport #35656
2025-10-15 12:55:30 +00:00
wxiaoguang
53a2aaee35 Fix missing Close when error occurs and abused connection pool (#35658) (#35670)
Backport #35658
2025-10-15 09:56:53 +00:00
Giteabot
5ae9bb4df9 Fix a bug missed return (#35655) (#35667)
Backport #35655 by @lunny

Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
2025-10-15 07:40:31 +02:00
Giteabot
ae2e8c1f00 Always create Actions logs stepsContainer (#35654) (#35672)
Backport #35654 by wxiaoguang

Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2025-10-15 04:16:06 +00:00
techknowlogick
602af1499e bump archives&rar dep (#35637) (#35638) 2025-10-12 05:48:39 +02:00
Giteabot
f4512426a1 Fix code tag style problem and LFS view bug (#35628) (#35636)
Backport #35628 by lutinglt

Signed-off-by: 鲁汀 <131967983+lutinglt@users.noreply.github.com>
Co-authored-by: 鲁汀 <131967983+lutinglt@users.noreply.github.com>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2025-10-11 20:25:03 +00:00
Giteabot
a3458c669a The status icon of the Action step is consistent with GitHub (#35618) (#35621)
Backport #35618 by @lutinglt

#35616
Before:
running:
<img width="45" height="34" alt="image"
src="https://github.com/user-attachments/assets/e2508f98-2f1f-4b7e-a80c-30b406f42531"
/>
waiting:
<img width="44" height="33" alt="image"
src="https://github.com/user-attachments/assets/e7c8164e-fdc3-4546-b088-31166544edb0"
/>

---
After:
running:
<img width="49" height="43" alt="image"
src="https://github.com/user-attachments/assets/b5a9b245-a995-458a-af23-d1723daa3692"
/>
waiting:
<img width="42" height="44" alt="image"
src="https://github.com/user-attachments/assets/ff72551e-cfb5-4665-af52-938ef0cf8f1c"
/>

`gitea-running.svg` is not an icon from the @ primer/octicon library,
extracted from the Github page. Github did not assign a clear class name
to this icon

Signed-off-by: 鲁汀 <131967983+lutinglt@users.noreply.github.com>
Co-authored-by: 鲁汀 <131967983+lutinglt@users.noreply.github.com>
Co-authored-by: lutinglt <lutinglt@users.noreply.github.com>
2025-10-10 12:12:21 -07:00
Giteabot
609d88f029 Fix inputing review comment will remove reviewer (#35591) (#35615)
Backport #35591 by @lunny

Fix #34617

Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
2025-10-10 08:28:44 +00:00
Giteabot
3c78598217 Mock external service in hcaptcha TestCaptcha (#35604) (#35614)
Backport #35604 by silverwind

The test calls out to a web service which may be down or unreachable as
seen in the linked issue. It's better for tests to not have such
external dependencies to make them absolutely stable.

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

Co-authored-by: silverwind <me@silverwind.io>
2025-10-10 04:49:20 +00:00
Giteabot
b7bb0fa538 Fix diffpatch API endpoint (#35610) (#35613)
Backport #35610 by @surya-purohit

Updates the swagger documentation for the `diffpatch` API endpoint.

The request body is corrected from the outdated `UpdateFileOptions` to
the current `ApplyDiffPatchOptions` to match the code implementation.

Closes [issue#35602](https://github.com/go-gitea/gitea/issues/35602)

---------

Co-authored-by: Surya Purohit <suryaprakash.sharma@sourcefuse.com>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
2025-10-10 03:28:40 +00:00
Giteabot
6de2151607 Fixing issue #35530: Password Leak in Log Messages (#35584) (#35609)
Backport #35584 by @shashank-netapp

# Summary
The Gitea codebase was logging `Elasticsearch` and `Meilisearch`
connection strings directly to log files without sanitizing them. Since
connection strings often contain credentials in the format
`protocol://username:password@host:port`, this resulted in passwords
being exposed in plain text in log output.

Fix:
- wrapped all instances of setting.Indexer.RepoConnStr and
setting.Indexer.IssueConnStr with the `util.SanitizeCredentialURLs()`
function before logging them.

Fixes: #35530

Co-authored-by: shashank-netapp <108022276+shashank-netapp@users.noreply.github.com>
Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
2025-10-09 11:00:40 +02:00
Giteabot
a99761d466 Use inputs context when parsing workflows (#35590) (#35595)
Backport #35590 by @Zettat123

Depends on [gitea/act#143](https://gitea.com/gitea/act/pulls/143)

The [`inputs`
context](https://docs.github.com/en/actions/reference/workflows-and-actions/contexts#inputs-context)
is used when parsing workflows so that `run-name` like `run-name: Deploy
to ${{ inputs.deploy_target }}` can be parsed correctly.

Co-authored-by: Zettat123 <zettat123@gmail.com>
2025-10-06 22:28:17 +00:00
Giteabot
8d1c04bda4 Fix creating pull request failure when the target branch name is the same as some tag (#35552) (#35582)
Backport #35552 by @lunny

Use full reference name in the git command to avoid ambiguity.

Fix #35470

Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
2025-10-06 06:10:52 +02:00
Giteabot
aa57531aac fix: auto-expand and auto-scroll for actions logs (#35583) (#35586)
Backport #35583 by ita004

Co-authored-by: Shafi Ahmed <98274448+ita004@users.noreply.github.com>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2025-10-05 12:06:41 +08:00
Giteabot
006fe2a907 Add rebase push display wrong comments bug (#35560) (#35580)
Backport #35560 by @lunny

Fix #35518

Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2025-10-04 10:28:32 +02:00
Giteabot
d94faf6d7e fix(webhook): prevent tag events from bypassing branch filters targets (#35567) (#35577)
Backport #35567 by Exgene

Co-authored-by: Kausthubh J Rao <105716675+Exgene@users.noreply.github.com>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
Co-authored-by: silverwind <me@silverwind.io>
2025-10-03 17:49:16 +00:00
Giteabot
6c8879b832 Fix markup init after issue comment editing (#35536) (#35537)
Backport #35536 by wxiaoguang

Fix #35533

Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2025-09-26 07:11:21 +08:00
Lunny Xiao
94a6da3bc8 Add changelog for 1.25.0-rc0 (#35531) 2025-09-25 09:32:30 -07:00
2276 changed files with 128545 additions and 162011 deletions

View File

@@ -4,7 +4,7 @@ tmp_dir = ".air"
[build] [build]
pre_cmd = ["killall -9 gitea 2>/dev/null || true"] # kill off potential zombie processes from previous runs pre_cmd = ["killall -9 gitea 2>/dev/null || true"] # kill off potential zombie processes from previous runs
cmd = "make --no-print-directory backend" cmd = "make --no-print-directory backend"
entrypoint = ["./gitea"] bin = "gitea"
delay = 2000 delay = 2000
include_ext = ["go", "tmpl"] include_ext = ["go", "tmpl"]
include_file = ["main.go"] include_file = ["main.go"]

View File

@@ -13,13 +13,14 @@
"ghcr.io/devcontainers/features/git-lfs:1.2.5": {}, "ghcr.io/devcontainers/features/git-lfs:1.2.5": {},
"ghcr.io/jsburckhardt/devcontainer-features/uv:1": {}, "ghcr.io/jsburckhardt/devcontainer-features/uv:1": {},
"ghcr.io/devcontainers/features/python:1": { "ghcr.io/devcontainers/features/python:1": {
"version": "3.14" "version": "3.13"
}, },
"ghcr.io/warrenbuckley/codespace-features/sqlite:1": {} "ghcr.io/warrenbuckley/codespace-features/sqlite:1": {}
}, },
"customizations": { "customizations": {
"vscode": { "vscode": {
"settings": {}, "settings": {},
// same extensions as Gitpod, should match /.gitpod.yml
"extensions": [ "extensions": [
"editorconfig.editorconfig", "editorconfig.editorconfig",
"dbaeumer.vscode-eslint", "dbaeumer.vscode-eslint",

View File

@@ -74,9 +74,6 @@ cpu.out
/VERSION /VERSION
/.air /.air
/.go-licenses /.go-licenses
/Dockerfile
/Dockerfile.rootless
/.venv
# Files and folders that were previously generated # Files and folders that were previously generated
/public/assets/img/webpack /public/assets/img/webpack

1
.gitattributes vendored
View File

@@ -8,4 +8,3 @@
/vendor/** -text -eol linguist-vendored /vendor/** -text -eol linguist-vendored
/web_src/js/vendor/** -text -eol linguist-vendored /web_src/js/vendor/** -text -eol linguist-vendored
Dockerfile.* linguist-language=Dockerfile Dockerfile.* linguist-language=Dockerfile
Makefile.* linguist-language=Makefile

View File

@@ -1,10 +0,0 @@
version: 2
updates:
- package-ecosystem: github-actions
labels: [modifies/dependencies]
directory: /
schedule:
interval: daily
cooldown:
default-days: 5

8
.github/labeler.yml vendored
View File

@@ -43,13 +43,15 @@ modifies/internal:
- ".editorconfig" - ".editorconfig"
- ".eslintrc.cjs" - ".eslintrc.cjs"
- ".golangci.yml" - ".golangci.yml"
- ".gitpod.yml"
- ".markdownlint.yaml" - ".markdownlint.yaml"
- ".spectral.yaml" - ".spectral.yaml"
- "stylelint.config.*" - "stylelint.config.js"
- ".yamllint.yaml" - ".yamllint.yaml"
- ".github/**" - ".github/**"
- ".gitea/**" - ".gitea/**"
- ".devcontainer/**" - ".devcontainer/**"
- "build.go"
- "build/**" - "build/**"
- "contrib/**" - "contrib/**"
@@ -83,9 +85,9 @@ docs-update-needed:
topic/code-linting: topic/code-linting:
- changed-files: - changed-files:
- any-glob-to-any-file: - any-glob-to-any-file:
- ".eslintrc.cjs"
- ".golangci.yml" - ".golangci.yml"
- ".markdownlint.yaml" - ".markdownlint.yaml"
- ".spectral.yaml" - ".spectral.yaml"
- ".yamllint.yaml" - ".yamllint.yaml"
- "eslint*.config.*" - "stylelint.config.js"
- "stylelint.config.*"

View File

@@ -1,22 +0,0 @@
name: cron-flake-updater
on:
workflow_dispatch:
schedule:
- cron: '0 0 * * 0' # runs weekly on Sunday at 00:00
jobs:
nix-flake-update:
permissions:
contents: write
issues: write
pull-requests: write
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: DeterminateSystems/determinate-nix-action@v3
- uses: DeterminateSystems/update-flake-lock@main
with:
pr-title: "Update Nix flake"
pr-labels: |
dependencies

View File

@@ -9,18 +9,16 @@ jobs:
cron-licenses: cron-licenses:
runs-on: ubuntu-latest runs-on: ubuntu-latest
if: github.repository == 'go-gitea/gitea' if: github.repository == 'go-gitea/gitea'
permissions:
contents: write
steps: steps:
- uses: actions/checkout@v6 - uses: actions/checkout@v4
- uses: actions/setup-go@v6 - uses: actions/setup-go@v5
with: with:
go-version-file: go.mod go-version-file: go.mod
check-latest: true check-latest: true
- run: make 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@v1.2.0 uses: appleboy/git-push-action@v0.0.3
with: with:
author_email: "teabot@gitea.io" author_email: "teabot@gitea.io"
author_name: GiteaBot author_name: GiteaBot

View File

@@ -9,11 +9,9 @@ jobs:
crowdin-pull: crowdin-pull:
runs-on: ubuntu-latest runs-on: ubuntu-latest
if: github.repository == 'go-gitea/gitea' if: github.repository == 'go-gitea/gitea'
permissions:
contents: write
steps: steps:
- uses: actions/checkout@v6 - uses: actions/checkout@v4
- uses: crowdin/github-action@v2 - uses: crowdin/github-action@v1
with: with:
upload_sources: true upload_sources: true
upload_translations: false upload_translations: false
@@ -29,7 +27,7 @@ jobs:
- name: update locales - name: update locales
run: ./build/update-locales.sh run: ./build/update-locales.sh
- name: push translations to repo - name: push translations to repo
uses: appleboy/git-push-action@v1.2.0 uses: appleboy/git-push-action@v0.0.3
with: with:
author_email: "teabot@gitea.io" author_email: "teabot@gitea.io"
author_name: GiteaBot author_name: GiteaBot

View File

@@ -19,15 +19,11 @@ on:
value: ${{ jobs.detect.outputs.swagger }} value: ${{ jobs.detect.outputs.swagger }}
yaml: yaml:
value: ${{ jobs.detect.outputs.yaml }} value: ${{ jobs.detect.outputs.yaml }}
json:
value: ${{ jobs.detect.outputs.json }}
jobs: jobs:
detect: detect:
runs-on: ubuntu-latest runs-on: ubuntu-latest
timeout-minutes: 3 timeout-minutes: 3
permissions:
contents: read
outputs: outputs:
backend: ${{ steps.changes.outputs.backend }} backend: ${{ steps.changes.outputs.backend }}
frontend: ${{ steps.changes.outputs.frontend }} frontend: ${{ steps.changes.outputs.frontend }}
@@ -37,10 +33,9 @@ jobs:
docker: ${{ steps.changes.outputs.docker }} docker: ${{ steps.changes.outputs.docker }}
swagger: ${{ steps.changes.outputs.swagger }} swagger: ${{ steps.changes.outputs.swagger }}
yaml: ${{ steps.changes.outputs.yaml }} yaml: ${{ steps.changes.outputs.yaml }}
json: ${{ steps.changes.outputs.json }}
steps: steps:
- uses: actions/checkout@v6 - uses: actions/checkout@v4
- uses: dorny/paths-filter@v4 - uses: dorny/paths-filter@v3
id: changes id: changes
with: with:
filters: | filters: |
@@ -53,7 +48,7 @@ jobs:
- "Makefile" - "Makefile"
- ".golangci.yml" - ".golangci.yml"
- ".editorconfig" - ".editorconfig"
- "options/locale/locale_en-US.json" - "options/locale/locale_en-US.ini"
frontend: frontend:
- "*.js" - "*.js"
@@ -85,7 +80,6 @@ jobs:
- "uv.lock" - "uv.lock"
docker: docker:
- ".github/workflows/pull-docker-dryrun.yml"
- "Dockerfile" - "Dockerfile"
- "Dockerfile.rootless" - "Dockerfile.rootless"
- "docker/**" - "docker/**"
@@ -104,6 +98,3 @@ jobs:
- "**/*.yaml" - "**/*.yaml"
- ".yamllint.yaml" - ".yamllint.yaml"
- "pyproject.toml" - "pyproject.toml"
json:
- "**/*.json"

View File

@@ -10,18 +10,14 @@ concurrency:
jobs: jobs:
files-changed: files-changed:
uses: ./.github/workflows/files-changed.yml uses: ./.github/workflows/files-changed.yml
permissions:
contents: read
lint-backend: lint-backend:
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
runs-on: ubuntu-latest runs-on: ubuntu-latest
permissions:
contents: read
steps: steps:
- uses: actions/checkout@v6 - uses: actions/checkout@v4
- uses: actions/setup-go@v6 - uses: actions/setup-go@v5
with: with:
go-version-file: go.mod go-version-file: go.mod
check-latest: true check-latest: true
@@ -34,18 +30,14 @@ jobs:
if: needs.files-changed.outputs.templates == 'true' if: needs.files-changed.outputs.templates == 'true'
needs: files-changed needs: files-changed
runs-on: ubuntu-latest runs-on: ubuntu-latest
permissions:
contents: read
steps: steps:
- uses: actions/checkout@v6 - uses: actions/checkout@v4
- uses: astral-sh/setup-uv@v8.0.0 - uses: astral-sh/setup-uv@v6
- run: uv python install 3.14 - run: uv python install 3.12
- uses: pnpm/action-setup@v5 - uses: pnpm/action-setup@v4
- uses: actions/setup-node@v6 - uses: actions/setup-node@v5
with: with:
node-version: 24 node-version: 24
cache: pnpm
cache-dependency-path: pnpm-lock.yaml
- run: make deps-py - run: make deps-py
- run: make deps-frontend - run: make deps-frontend
- run: make lint-templates - run: make lint-templates
@@ -54,44 +46,23 @@ jobs:
if: needs.files-changed.outputs.yaml == 'true' if: needs.files-changed.outputs.yaml == 'true'
needs: files-changed needs: files-changed
runs-on: ubuntu-latest runs-on: ubuntu-latest
permissions:
contents: read
steps: steps:
- uses: actions/checkout@v6 - uses: actions/checkout@v4
- uses: astral-sh/setup-uv@v8.0.0 - uses: astral-sh/setup-uv@v6
- run: uv python install 3.14 - run: uv python install 3.12
- run: make deps-py - run: make deps-py
- run: make lint-yaml - run: make lint-yaml
lint-json:
if: needs.files-changed.outputs.json == 'true'
needs: files-changed
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- uses: actions/checkout@v6
- uses: pnpm/action-setup@v5
- uses: actions/setup-node@v5
with:
node-version: 24
- run: make deps-frontend
- run: make lint-json
lint-swagger: lint-swagger:
if: needs.files-changed.outputs.swagger == 'true' if: needs.files-changed.outputs.swagger == 'true'
needs: files-changed needs: files-changed
runs-on: ubuntu-latest runs-on: ubuntu-latest
permissions:
contents: read
steps: steps:
- uses: actions/checkout@v6 - uses: actions/checkout@v4
- uses: pnpm/action-setup@v5 - uses: pnpm/action-setup@v4
- uses: actions/setup-node@v6 - uses: actions/setup-node@v5
with: with:
node-version: 24 node-version: 24
cache: pnpm
cache-dependency-path: pnpm-lock.yaml
- run: make deps-frontend - run: make deps-frontend
- run: make lint-swagger - run: make lint-swagger
@@ -99,11 +70,9 @@ jobs:
if: needs.files-changed.outputs.backend == 'true' || needs.files-changed.outputs.frontend == 'true' || needs.files-changed.outputs.actions == 'true' || needs.files-changed.outputs.docs == 'true' || needs.files-changed.outputs.templates == 'true' if: needs.files-changed.outputs.backend == 'true' || needs.files-changed.outputs.frontend == 'true' || needs.files-changed.outputs.actions == 'true' || needs.files-changed.outputs.docs == 'true' || needs.files-changed.outputs.templates == 'true'
needs: files-changed needs: files-changed
runs-on: ubuntu-latest runs-on: ubuntu-latest
permissions:
contents: read
steps: steps:
- uses: actions/checkout@v6 - uses: actions/checkout@v4
- uses: actions/setup-go@v6 - uses: actions/setup-go@v5
with: with:
go-version-file: go.mod go-version-file: go.mod
check-latest: true check-latest: true
@@ -113,16 +82,14 @@ jobs:
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
runs-on: ubuntu-latest runs-on: ubuntu-latest
permissions:
contents: read
steps: steps:
- uses: actions/checkout@v6 - uses: actions/checkout@v4
- uses: actions/setup-go@v6 - uses: actions/setup-go@v5
with: with:
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 - 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
@@ -132,11 +99,9 @@ jobs:
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
runs-on: ubuntu-latest runs-on: ubuntu-latest
permissions:
contents: read
steps: steps:
- uses: actions/checkout@v6 - uses: actions/checkout@v4
- uses: actions/setup-go@v6 - uses: actions/setup-go@v5
with: with:
go-version-file: go.mod go-version-file: go.mod
check-latest: true check-latest: true
@@ -149,11 +114,9 @@ jobs:
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
runs-on: ubuntu-latest runs-on: ubuntu-latest
permissions:
contents: read
steps: steps:
- uses: actions/checkout@v6 - uses: actions/checkout@v4
- uses: actions/setup-go@v6 - uses: actions/setup-go@v5
with: with:
go-version-file: go.mod go-version-file: go.mod
check-latest: true check-latest: true
@@ -164,16 +127,12 @@ jobs:
if: needs.files-changed.outputs.frontend == 'true' || needs.files-changed.outputs.actions == 'true' if: needs.files-changed.outputs.frontend == 'true' || needs.files-changed.outputs.actions == 'true'
needs: files-changed needs: files-changed
runs-on: ubuntu-latest runs-on: ubuntu-latest
permissions:
contents: read
steps: steps:
- uses: actions/checkout@v6 - uses: actions/checkout@v4
- uses: pnpm/action-setup@v5 - uses: pnpm/action-setup@v4
- uses: actions/setup-node@v6 - uses: actions/setup-node@v5
with: with:
node-version: 24 node-version: 24
cache: pnpm
cache-dependency-path: pnpm-lock.yaml
- run: make deps-frontend - run: make deps-frontend
- run: make lint-frontend - run: make lint-frontend
- run: make checks-frontend - run: make checks-frontend
@@ -184,11 +143,9 @@ jobs:
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
runs-on: ubuntu-latest runs-on: ubuntu-latest
permissions:
contents: read
steps: steps:
- uses: actions/checkout@v6 - uses: actions/checkout@v4
- uses: actions/setup-go@v6 - uses: actions/setup-go@v5
with: with:
go-version-file: go.mod go-version-file: go.mod
check-latest: true check-latest: true
@@ -218,16 +175,12 @@ jobs:
if: needs.files-changed.outputs.docs == 'true' || needs.files-changed.outputs.actions == 'true' if: needs.files-changed.outputs.docs == 'true' || needs.files-changed.outputs.actions == 'true'
needs: files-changed needs: files-changed
runs-on: ubuntu-latest runs-on: ubuntu-latest
permissions:
contents: read
steps: steps:
- uses: actions/checkout@v6 - uses: actions/checkout@v4
- uses: pnpm/action-setup@v5 - uses: pnpm/action-setup@v4
- uses: actions/setup-node@v6 - uses: actions/setup-node@v5
with: with:
node-version: 24 node-version: 24
cache: pnpm
cache-dependency-path: pnpm-lock.yaml
- run: make deps-frontend - run: make deps-frontend
- run: make lint-md - run: make lint-md
@@ -235,11 +188,9 @@ jobs:
if: needs.files-changed.outputs.actions == 'true' || needs.files-changed.outputs.actions == 'true' if: needs.files-changed.outputs.actions == 'true' || needs.files-changed.outputs.actions == 'true'
needs: files-changed needs: files-changed
runs-on: ubuntu-latest runs-on: ubuntu-latest
permissions:
contents: read
steps: steps:
- uses: actions/checkout@v6 - uses: actions/checkout@v4
- uses: actions/setup-go@v6 - uses: actions/setup-go@v5
with: with:
go-version-file: go.mod go-version-file: go.mod
check-latest: true check-latest: true

View File

@@ -10,15 +10,11 @@ concurrency:
jobs: jobs:
files-changed: files-changed:
uses: ./.github/workflows/files-changed.yml uses: ./.github/workflows/files-changed.yml
permissions:
contents: read
test-pgsql: test-pgsql:
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
runs-on: ubuntu-latest runs-on: ubuntu-latest
permissions:
contents: read
services: services:
pgsql: pgsql:
image: postgres:14 image: postgres:14
@@ -42,8 +38,8 @@ jobs:
ports: ports:
- "9000:9000" - "9000:9000"
steps: steps:
- uses: actions/checkout@v6 - uses: actions/checkout@v4
- uses: actions/setup-go@v6 - uses: actions/setup-go@v5
with: with:
go-version-file: go.mod go-version-file: go.mod
check-latest: true check-latest: true
@@ -63,39 +59,37 @@ jobs:
RACE_ENABLED: true RACE_ENABLED: true
TEST_TAGS: gogit TEST_TAGS: gogit
TEST_LDAP: 1 TEST_LDAP: 1
USE_REPO_TEST_DIR: 1
test-sqlite: test-sqlite:
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
runs-on: ubuntu-latest runs-on: ubuntu-latest
permissions:
contents: read
steps: steps:
- uses: actions/checkout@v6 - uses: actions/checkout@v4
- uses: actions/setup-go@v6 - uses: actions/setup-go@v5
with: with:
go-version-file: go.mod go-version-file: go.mod
check-latest: true check-latest: true
- run: make deps-backend - run: make deps-backend
- run: GOEXPERIMENT='' make backend - run: make backend
env: env:
TAGS: bindata gogit sqlite sqlite_unlock_notify TAGS: bindata gogit sqlite sqlite_unlock_notify
- name: run migration tests - name: run migration tests
run: make test-sqlite-migration run: make test-sqlite-migration
- name: run tests - name: run tests
run: GOEXPERIMENT='' make test-sqlite run: make test-sqlite
timeout-minutes: 50 timeout-minutes: 50
env: env:
TAGS: bindata gogit sqlite sqlite_unlock_notify TAGS: bindata gogit sqlite sqlite_unlock_notify
RACE_ENABLED: true RACE_ENABLED: true
TEST_TAGS: gogit sqlite sqlite_unlock_notify TEST_TAGS: gogit sqlite sqlite_unlock_notify
USE_REPO_TEST_DIR: 1
test-unit: test-unit:
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
runs-on: ubuntu-latest runs-on: ubuntu-latest
permissions:
contents: read
services: services:
elasticsearch: elasticsearch:
image: elasticsearch:7.5.0 image: elasticsearch:7.5.0
@@ -130,8 +124,8 @@ jobs:
ports: ports:
- 10000:10000 - 10000:10000
steps: steps:
- uses: actions/checkout@v6 - uses: actions/checkout@v4
- uses: actions/setup-go@v6 - uses: actions/setup-go@v5
with: with:
go-version-file: go.mod go-version-file: go.mod
check-latest: true check-latest: true
@@ -148,7 +142,7 @@ jobs:
RACE_ENABLED: true RACE_ENABLED: true
GITHUB_READ_TOKEN: ${{ secrets.GITHUB_READ_TOKEN }} GITHUB_READ_TOKEN: ${{ secrets.GITHUB_READ_TOKEN }}
- name: unit-tests-gogit - name: unit-tests-gogit
run: GOEXPERIMENT='' make unit-test-coverage test-check run: make unit-test-coverage test-check
env: env:
TAGS: bindata gogit TAGS: bindata gogit
RACE_ENABLED: true RACE_ENABLED: true
@@ -158,8 +152,6 @@ jobs:
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
runs-on: ubuntu-latest runs-on: ubuntu-latest
permissions:
contents: read
services: services:
mysql: mysql:
# the bitnami mysql image has more options than the official one, it's easier to customize # the bitnami mysql image has more options than the official one, it's easier to customize
@@ -185,8 +177,8 @@ jobs:
- "587:587" - "587:587"
- "993:993" - "993:993"
steps: steps:
- uses: actions/checkout@v6 - uses: actions/checkout@v4
- uses: actions/setup-go@v6 - uses: actions/setup-go@v5
with: with:
go-version-file: go.mod go-version-file: go.mod
check-latest: true check-latest: true
@@ -204,14 +196,13 @@ jobs:
env: env:
TAGS: bindata TAGS: bindata
RACE_ENABLED: true RACE_ENABLED: true
USE_REPO_TEST_DIR: 1
TEST_INDEXER_CODE_ES_URL: "http://elastic:changeme@elasticsearch:9200" TEST_INDEXER_CODE_ES_URL: "http://elastic:changeme@elasticsearch:9200"
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
runs-on: ubuntu-latest runs-on: ubuntu-latest
permissions:
contents: read
services: services:
mssql: mssql:
image: mcr.microsoft.com/mssql/server:2019-latest image: mcr.microsoft.com/mssql/server:2019-latest
@@ -226,8 +217,8 @@ jobs:
ports: ports:
- 10000:10000 - 10000:10000
steps: steps:
- uses: actions/checkout@v6 - uses: actions/checkout@v4
- uses: actions/setup-go@v6 - uses: actions/setup-go@v5
with: with:
go-version-file: go.mod go-version-file: go.mod
check-latest: true check-latest: true
@@ -243,3 +234,4 @@ jobs:
timeout-minutes: 50 timeout-minutes: 50
env: env:
TAGS: bindata TAGS: bindata
USE_REPO_TEST_DIR: 1

View File

@@ -10,31 +10,26 @@ concurrency:
jobs: jobs:
files-changed: files-changed:
uses: ./.github/workflows/files-changed.yml uses: ./.github/workflows/files-changed.yml
permissions:
contents: read
container: regular:
if: needs.files-changed.outputs.docker == 'true' if: needs.files-changed.outputs.docker == 'true' || needs.files-changed.outputs.actions == 'true'
needs: files-changed needs: files-changed
runs-on: ubuntu-latest runs-on: ubuntu-latest
permissions:
contents: read
steps: steps:
- uses: actions/checkout@v6 - uses: docker/setup-buildx-action@v3
- uses: docker/setup-qemu-action@v4 - uses: docker/build-push-action@v5
- uses: docker/setup-buildx-action@v4
- name: Build regular container image
uses: docker/build-push-action@v7
with: with:
context: .
platforms: linux/amd64,linux/arm64,linux/riscv64
push: false push: false
cache-from: type=registry,ref=ghcr.io/go-gitea/gitea:buildcache-rootful tags: gitea/gitea:linux-amd64
- name: Build rootless container image
uses: docker/build-push-action@v7 rootless:
if: needs.files-changed.outputs.docker == 'true' || needs.files-changed.outputs.actions == 'true'
needs: files-changed
runs-on: ubuntu-latest
steps:
- uses: docker/setup-buildx-action@v3
- uses: docker/build-push-action@v5
with: with:
context: .
push: false push: false
platforms: linux/amd64,linux/arm64,linux/riscv64
file: Dockerfile.rootless file: Dockerfile.rootless
cache-from: type=registry,ref=ghcr.io/go-gitea/gitea:buildcache-rootless tags: gitea/gitea:linux-amd64

View File

@@ -10,34 +10,26 @@ concurrency:
jobs: jobs:
files-changed: files-changed:
uses: ./.github/workflows/files-changed.yml uses: ./.github/workflows/files-changed.yml
permissions:
contents: read
test-e2e: test-e2e:
if: needs.files-changed.outputs.backend == 'true' || needs.files-changed.outputs.frontend == 'true' # the "test-e2e" won't pass, and it seems that there is no useful test, so skip
# if: needs.files-changed.outputs.backend == 'true' || needs.files-changed.outputs.frontend == 'true' || needs.files-changed.outputs.actions == 'true'
if: false
needs: files-changed needs: files-changed
runs-on: ubuntu-latest runs-on: ubuntu-latest
permissions:
contents: read
steps: steps:
- uses: actions/checkout@v6 - uses: actions/checkout@v4
- uses: actions/setup-go@v6 - uses: actions/setup-go@v5
with: with:
go-version-file: go.mod go-version-file: go.mod
check-latest: true check-latest: true
- uses: pnpm/action-setup@v5 - uses: pnpm/action-setup@v4
- uses: actions/setup-node@v6 - uses: actions/setup-node@v5
with: with:
node-version: 24 node-version: 24
cache: pnpm - run: make deps-frontend frontend deps-backend
cache-dependency-path: pnpm-lock.yaml - run: pnpm exec playwright install --with-deps
- run: make deps-frontend - run: make test-e2e-sqlite
- run: make frontend timeout-minutes: 40
- run: make deps-backend
- run: make gitea-e2e
- run: make playwright
- run: make test-e2e
timeout-minutes: 10
env: env:
FORCE_COLOR: 1 USE_REPO_TEST_DIR: 1
GITEA_TEST_E2E_DEBUG: 1

View File

@@ -15,6 +15,6 @@ jobs:
contents: read contents: read
pull-requests: write pull-requests: write
steps: steps:
- uses: actions/labeler@v6 - uses: actions/labeler@v5
with: with:
sync-labels: true sync-labels: true

View File

@@ -11,23 +11,19 @@ concurrency:
jobs: jobs:
nightly-binary: nightly-binary:
runs-on: namespace-profile-gitea-release-binary runs-on: namespace-profile-gitea-release-binary
permissions:
contents: read
steps: steps:
- uses: actions/checkout@v6 - 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
# fetch all tags to ensure that "git describe" reports expected Gitea version, eg. v1.21.0-dev-1-g1234567 # fetch all tags to ensure that "git describe" reports expected Gitea version, eg. v1.21.0-dev-1-g1234567
- run: git fetch --unshallow --quiet --tags --force - run: git fetch --unshallow --quiet --tags --force
- uses: actions/setup-go@v6 - uses: actions/setup-go@v5
with: with:
go-version-file: go.mod go-version-file: go.mod
check-latest: true check-latest: true
- uses: pnpm/action-setup@v5 - uses: pnpm/action-setup@v4
- uses: actions/setup-node@v6 - uses: actions/setup-node@v5
with: with:
node-version: 24 node-version: 24
cache: pnpm
cache-dependency-path: pnpm-lock.yaml
- run: make deps-frontend deps-backend - run: make deps-frontend deps-backend
# xgo build # xgo build
- run: make release - run: make release
@@ -35,7 +31,7 @@ jobs:
TAGS: bindata sqlite sqlite_unlock_notify TAGS: bindata sqlite sqlite_unlock_notify
- name: import gpg key - name: import gpg key
id: import_gpg id: import_gpg
uses: crazy-max/ghaction-import-gpg@v7 uses: crazy-max/ghaction-import-gpg@v6
with: with:
gpg_private_key: ${{ secrets.GPGSIGN_KEY }} gpg_private_key: ${{ secrets.GPGSIGN_KEY }}
passphrase: ${{ secrets.GPGSIGN_PASSPHRASE }} passphrase: ${{ secrets.GPGSIGN_PASSPHRASE }}
@@ -52,7 +48,7 @@ jobs:
echo "Cleaned name is ${REF_NAME}" echo "Cleaned name is ${REF_NAME}"
echo "branch=${REF_NAME}-nightly" >> "$GITHUB_OUTPUT" echo "branch=${REF_NAME}-nightly" >> "$GITHUB_OUTPUT"
- name: configure aws - name: configure aws
uses: aws-actions/configure-aws-credentials@v6 uses: aws-actions/configure-aws-credentials@v4
with: with:
aws-region: ${{ secrets.AWS_REGION }} aws-region: ${{ secrets.AWS_REGION }}
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
@@ -60,76 +56,88 @@ jobs:
- name: upload binaries to s3 - name: upload binaries to s3
run: | run: |
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-container:
runs-on: namespace-profile-gitea-release-docker runs-on: namespace-profile-gitea-release-docker
permissions: permissions:
contents: read
packages: write # to publish to ghcr.io packages: write # to publish to ghcr.io
steps: steps:
- uses: actions/checkout@v6 - 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
# fetch all tags to ensure that "git describe" reports expected Gitea version, eg. v1.21.0-dev-1-g1234567 # fetch all tags to ensure that "git describe" reports expected Gitea version, eg. v1.21.0-dev-1-g1234567
- run: git fetch --unshallow --quiet --tags --force - run: git fetch --unshallow --quiet --tags --force
- uses: docker/setup-qemu-action@v4 - uses: actions/setup-go@v5
- uses: docker/setup-buildx-action@v4 with:
go-version-file: go.mod
check-latest: true
- uses: docker/setup-qemu-action@v3
- uses: docker/setup-buildx-action@v3
- name: Get cleaned branch name - name: Get cleaned branch name
id: clean_name id: clean_name
run: | run: |
REF_NAME=$(echo "${{ github.ref }}" | sed -e 's/refs\/heads\///' -e 's/refs\/tags\///' -e 's/release\/v//') REF_NAME=$(echo "${{ github.ref }}" | sed -e 's/refs\/heads\///' -e 's/refs\/tags\///' -e 's/release\/v//')
echo "branch=${REF_NAME}-nightly" >> "$GITHUB_OUTPUT" echo "branch=${REF_NAME}-nightly" >> "$GITHUB_OUTPUT"
- uses: docker/metadata-action@v6
id: meta
with:
images: |-
gitea/gitea
ghcr.io/go-gitea/gitea
tags: |
type=raw,value=${{ steps.clean_name.outputs.branch }}
annotations: |
org.opencontainers.image.authors="maintainers@gitea.io"
- uses: docker/metadata-action@v6
id: meta_rootless
with:
images: |-
gitea/gitea
ghcr.io/go-gitea/gitea
# each tag below will have the suffix of -rootless
flavor: |
suffix=-rootless
tags: |
type=raw,value=${{ steps.clean_name.outputs.branch }}
annotations: |
org.opencontainers.image.authors="maintainers@gitea.io"
- name: Login to Docker Hub - name: Login to Docker Hub
uses: docker/login-action@v4 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 - name: Login to GHCR using PAT
uses: docker/login-action@v4 uses: docker/login-action@v3
with: with:
registry: ghcr.io registry: ghcr.io
username: ${{ github.repository_owner }} username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }} password: ${{ secrets.GITHUB_TOKEN }}
- name: build regular docker image - name: fetch go modules
uses: docker/build-push-action@v7 run: make vendor
- name: build rootful docker image
uses: docker/build-push-action@v5
with: with:
context: . context: .
platforms: linux/amd64,linux/arm64,linux/riscv64 platforms: linux/amd64,linux/arm64,linux/riscv64
push: true push: true
tags: ${{ steps.meta.outputs.tags }} tags: |-
annotations: ${{ steps.meta.outputs.annotations }} gitea/gitea:${{ steps.clean_name.outputs.branch }}
cache-from: type=registry,ref=ghcr.io/go-gitea/gitea:buildcache-rootful ghcr.io/go-gitea/gitea:${{ steps.clean_name.outputs.branch }}
cache-to: type=registry,ref=ghcr.io/go-gitea/gitea:buildcache-rootful,mode=max nightly-docker-rootless:
runs-on: namespace-profile-gitea-release-docker
permissions:
packages: write # to publish to ghcr.io
steps:
- 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 tags to ensure that "git describe" reports expected Gitea version, eg. v1.21.0-dev-1-g1234567
- run: git fetch --unshallow --quiet --tags --force
- uses: actions/setup-go@v5
with:
go-version-file: go.mod
check-latest: true
- uses: docker/setup-qemu-action@v3
- uses: docker/setup-buildx-action@v3
- name: Get cleaned branch name
id: clean_name
run: |
REF_NAME=$(echo "${{ github.ref }}" | sed -e 's/refs\/heads\///' -e 's/refs\/tags\///' -e 's/release\/v//')
echo "branch=${REF_NAME}-nightly" >> "$GITHUB_OUTPUT"
- name: Login to Docker Hub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
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
run: make vendor
- name: build rootless docker image - name: build rootless docker image
uses: docker/build-push-action@v7 uses: docker/build-push-action@v5
with: with:
context: . context: .
platforms: linux/amd64,linux/arm64,linux/riscv64 platforms: linux/amd64,linux/arm64
push: true push: true
file: Dockerfile.rootless file: Dockerfile.rootless
tags: ${{ steps.meta_rootless.outputs.tags }} tags: |-
annotations: ${{ steps.meta_rootless.outputs.annotations }} gitea/gitea:${{ steps.clean_name.outputs.branch }}-rootless
cache-from: type=registry,ref=ghcr.io/go-gitea/gitea:buildcache-rootless ghcr.io/go-gitea/gitea:${{ steps.clean_name.outputs.branch }}-rootless
cache-to: type=registry,ref=ghcr.io/go-gitea/gitea:buildcache-rootless,mode=max

View File

@@ -12,23 +12,19 @@ concurrency:
jobs: jobs:
binary: binary:
runs-on: namespace-profile-gitea-release-binary runs-on: namespace-profile-gitea-release-binary
permissions:
contents: read
steps: steps:
- uses: actions/checkout@v6 - 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
# fetch all tags to ensure that "git describe" reports expected Gitea version, eg. v1.21.0-dev-1-g1234567 # fetch all tags to ensure that "git describe" reports expected Gitea version, eg. v1.21.0-dev-1-g1234567
- run: git fetch --unshallow --quiet --tags --force - run: git fetch --unshallow --quiet --tags --force
- uses: actions/setup-go@v6 - uses: actions/setup-go@v5
with: with:
go-version-file: go.mod go-version-file: go.mod
check-latest: true check-latest: true
- uses: pnpm/action-setup@v5 - uses: pnpm/action-setup@v4
- uses: actions/setup-node@v6 - uses: actions/setup-node@v5
with: with:
node-version: 24 node-version: 24
cache: pnpm
cache-dependency-path: pnpm-lock.yaml
- run: make deps-frontend deps-backend - run: make deps-frontend deps-backend
# xgo build # xgo build
- run: make release - run: make release
@@ -36,7 +32,7 @@ jobs:
TAGS: bindata sqlite sqlite_unlock_notify TAGS: bindata sqlite sqlite_unlock_notify
- name: import gpg key - name: import gpg key
id: import_gpg id: import_gpg
uses: crazy-max/ghaction-import-gpg@v7 uses: crazy-max/ghaction-import-gpg@v6
with: with:
gpg_private_key: ${{ secrets.GPGSIGN_KEY }} gpg_private_key: ${{ secrets.GPGSIGN_KEY }}
passphrase: ${{ secrets.GPGSIGN_PASSPHRASE }} passphrase: ${{ secrets.GPGSIGN_PASSPHRASE }}
@@ -53,7 +49,7 @@ jobs:
echo "Cleaned name is ${REF_NAME}" echo "Cleaned name is ${REF_NAME}"
echo "branch=${REF_NAME}" >> "$GITHUB_OUTPUT" echo "branch=${REF_NAME}" >> "$GITHUB_OUTPUT"
- name: configure aws - name: configure aws
uses: aws-actions/configure-aws-credentials@v6 uses: aws-actions/configure-aws-credentials@v4
with: with:
aws-region: ${{ secrets.AWS_REGION }} aws-region: ${{ secrets.AWS_REGION }}
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
@@ -62,7 +58,7 @@ jobs:
run: | run: |
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
- name: Install GH CLI - name: Install GH CLI
uses: dev-hanz-ops/install-gh-cli-action@v0.2.1 uses: dev-hanz-ops/install-gh-cli-action@v0.1.0
with: with:
gh-cli-version: 2.39.1 gh-cli-version: 2.39.1
- name: create github release - name: create github release
@@ -70,20 +66,18 @@ jobs:
gh release create ${{ github.ref_name }} --title ${{ github.ref_name }} --draft --notes-from-tag dist/release/* gh release create ${{ github.ref_name }} --title ${{ github.ref_name }} --draft --notes-from-tag dist/release/*
env: env:
GITHUB_TOKEN: ${{ secrets.RELEASE_TOKEN }} GITHUB_TOKEN: ${{ secrets.RELEASE_TOKEN }}
docker-rootful:
container:
runs-on: namespace-profile-gitea-release-docker runs-on: namespace-profile-gitea-release-docker
permissions: permissions:
contents: read
packages: write # to publish to ghcr.io packages: write # to publish to ghcr.io
steps: steps:
- uses: actions/checkout@v6 - 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
# fetch all tags to ensure that "git describe" reports expected Gitea version, eg. v1.21.0-dev-1-g1234567 # fetch all tags to ensure that "git describe" reports expected Gitea version, eg. v1.21.0-dev-1-g1234567
- run: git fetch --unshallow --quiet --tags --force - run: git fetch --unshallow --quiet --tags --force
- uses: docker/setup-qemu-action@v4 - uses: docker/setup-qemu-action@v3
- uses: docker/setup-buildx-action@v4 - uses: docker/setup-buildx-action@v3
- uses: docker/metadata-action@v6 - uses: docker/metadata-action@v5
id: meta id: meta
with: with:
images: |- images: |-
@@ -94,10 +88,38 @@ jobs:
# 1.2.3-rc0 # 1.2.3-rc0
tags: | tags: |
type=semver,pattern={{version}} type=semver,pattern={{version}}
annotations: | - name: Login to Docker Hub
org.opencontainers.image.authors="maintainers@gitea.io" uses: docker/login-action@v3
- uses: docker/metadata-action@v6 with:
id: meta_rootless username: ${{ secrets.DOCKERHUB_USERNAME }}
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
uses: docker/build-push-action@v5
with:
context: .
platforms: linux/amd64,linux/arm64,linux/riscv64
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
docker-rootless:
runs-on: namespace-profile-gitea-release-docker
permissions:
packages: write # to publish to ghcr.io
steps:
- 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 tags to ensure that "git describe" reports expected Gitea version, eg. v1.21.0-dev-1-g1234567
- run: git fetch --unshallow --quiet --tags --force
- uses: docker/setup-qemu-action@v3
- uses: docker/setup-buildx-action@v3
- uses: docker/metadata-action@v5
id: meta
with: with:
images: |- images: |-
gitea/gitea gitea/gitea
@@ -109,33 +131,23 @@ jobs:
# 1.2.3-rc0 # 1.2.3-rc0
tags: | tags: |
type=semver,pattern={{version}} type=semver,pattern={{version}}
annotations: |
org.opencontainers.image.authors="maintainers@gitea.io"
- name: Login to Docker Hub - name: Login to Docker Hub
uses: docker/login-action@v4 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 - name: Login to GHCR using PAT
uses: docker/login-action@v4 uses: docker/login-action@v3
with: with:
registry: ghcr.io registry: ghcr.io
username: ${{ github.repository_owner }} username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }} password: ${{ secrets.GITHUB_TOKEN }}
- name: build regular container image - name: build rootless docker image
uses: docker/build-push-action@v7 uses: docker/build-push-action@v5
with:
context: .
platforms: linux/amd64,linux/arm64,linux/riscv64
push: true
tags: ${{ steps.meta.outputs.tags }}
annotations: ${{ steps.meta.outputs.annotations }}
- name: build rootless container image
uses: docker/build-push-action@v7
with: with:
context: . context: .
platforms: linux/amd64,linux/arm64,linux/riscv64 platforms: linux/amd64,linux/arm64,linux/riscv64
push: true push: true
file: Dockerfile.rootless file: Dockerfile.rootless
tags: ${{ steps.meta_rootless.outputs.tags }} tags: ${{ steps.meta.outputs.tags }}
annotations: ${{ steps.meta_rootless.outputs.annotations }} labels: ${{ steps.meta.outputs.labels }}

View File

@@ -15,23 +15,20 @@ jobs:
binary: binary:
runs-on: namespace-profile-gitea-release-binary runs-on: namespace-profile-gitea-release-binary
permissions: permissions:
contents: read
packages: write # to publish to ghcr.io packages: write # to publish to ghcr.io
steps: steps:
- uses: actions/checkout@v6 - 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
# fetch all tags to ensure that "git describe" reports expected Gitea version, eg. v1.21.0-dev-1-g1234567 # fetch all tags to ensure that "git describe" reports expected Gitea version, eg. v1.21.0-dev-1-g1234567
- run: git fetch --unshallow --quiet --tags --force - run: git fetch --unshallow --quiet --tags --force
- uses: actions/setup-go@v6 - uses: actions/setup-go@v5
with: with:
go-version-file: go.mod go-version-file: go.mod
check-latest: true check-latest: true
- uses: pnpm/action-setup@v5 - uses: pnpm/action-setup@v4
- uses: actions/setup-node@v6 - uses: actions/setup-node@v5
with: with:
node-version: 24 node-version: 24
cache: pnpm
cache-dependency-path: pnpm-lock.yaml
- run: make deps-frontend deps-backend - run: make deps-frontend deps-backend
# xgo build # xgo build
- run: make release - run: make release
@@ -39,7 +36,7 @@ jobs:
TAGS: bindata sqlite sqlite_unlock_notify TAGS: bindata sqlite sqlite_unlock_notify
- name: import gpg key - name: import gpg key
id: import_gpg id: import_gpg
uses: crazy-max/ghaction-import-gpg@v7 uses: crazy-max/ghaction-import-gpg@v6
with: with:
gpg_private_key: ${{ secrets.GPGSIGN_KEY }} gpg_private_key: ${{ secrets.GPGSIGN_KEY }}
passphrase: ${{ secrets.GPGSIGN_PASSPHRASE }} passphrase: ${{ secrets.GPGSIGN_PASSPHRASE }}
@@ -56,7 +53,7 @@ jobs:
echo "Cleaned name is ${REF_NAME}" echo "Cleaned name is ${REF_NAME}"
echo "branch=${REF_NAME}" >> "$GITHUB_OUTPUT" echo "branch=${REF_NAME}" >> "$GITHUB_OUTPUT"
- name: configure aws - name: configure aws
uses: aws-actions/configure-aws-credentials@v6 uses: aws-actions/configure-aws-credentials@v4
with: with:
aws-region: ${{ secrets.AWS_REGION }} aws-region: ${{ secrets.AWS_REGION }}
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
@@ -65,7 +62,7 @@ jobs:
run: | run: |
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
- name: Install GH CLI - name: Install GH CLI
uses: dev-hanz-ops/install-gh-cli-action@v0.2.1 uses: dev-hanz-ops/install-gh-cli-action@v0.1.0
with: with:
gh-cli-version: 2.39.1 gh-cli-version: 2.39.1
- name: create github release - name: create github release
@@ -73,20 +70,18 @@ jobs:
gh release create ${{ github.ref_name }} --title ${{ github.ref_name }} --notes-from-tag dist/release/* gh release create ${{ github.ref_name }} --title ${{ github.ref_name }} --notes-from-tag dist/release/*
env: env:
GITHUB_TOKEN: ${{ secrets.RELEASE_TOKEN }} GITHUB_TOKEN: ${{ secrets.RELEASE_TOKEN }}
docker-rootful:
container:
runs-on: namespace-profile-gitea-release-docker runs-on: namespace-profile-gitea-release-docker
permissions: permissions:
contents: read
packages: write # to publish to ghcr.io packages: write # to publish to ghcr.io
steps: steps:
- uses: actions/checkout@v6 - 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
# fetch all tags to ensure that "git describe" reports expected Gitea version, eg. v1.21.0-dev-1-g1234567 # fetch all tags to ensure that "git describe" reports expected Gitea version, eg. v1.21.0-dev-1-g1234567
- run: git fetch --unshallow --quiet --tags --force - run: git fetch --unshallow --quiet --tags --force
- uses: docker/setup-qemu-action@v4 - uses: docker/setup-qemu-action@v3
- uses: docker/setup-buildx-action@v4 - uses: docker/setup-buildx-action@v3
- uses: docker/metadata-action@v6 - uses: docker/metadata-action@v5
id: meta id: meta
with: with:
images: |- images: |-
@@ -101,10 +96,36 @@ jobs:
type=semver,pattern={{version}} type=semver,pattern={{version}}
type=semver,pattern={{major}} type=semver,pattern={{major}}
type=semver,pattern={{major}}.{{minor}} type=semver,pattern={{major}}.{{minor}}
annotations: | - name: Login to Docker Hub
org.opencontainers.image.authors="maintainers@gitea.io" uses: docker/login-action@v3
- uses: docker/metadata-action@v6 with:
id: meta_rootless username: ${{ secrets.DOCKERHUB_USERNAME }}
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
uses: docker/build-push-action@v5
with:
context: .
platforms: linux/amd64,linux/arm64,linux/riscv64
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
docker-rootless:
runs-on: namespace-profile-gitea-release-docker
steps:
- 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 tags to ensure that "git describe" reports expected Gitea version, eg. v1.21.0-dev-1-g1234567
- run: git fetch --unshallow --quiet --tags --force
- uses: docker/setup-qemu-action@v3
- uses: docker/setup-buildx-action@v3
- uses: docker/metadata-action@v5
id: meta
with: with:
images: |- images: |-
gitea/gitea gitea/gitea
@@ -121,33 +142,23 @@ jobs:
type=semver,pattern={{version}} type=semver,pattern={{version}}
type=semver,pattern={{major}} type=semver,pattern={{major}}
type=semver,pattern={{major}}.{{minor}} type=semver,pattern={{major}}.{{minor}}
annotations: |
org.opencontainers.image.authors="maintainers@gitea.io"
- name: Login to Docker Hub - name: Login to Docker Hub
uses: docker/login-action@v4 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 - name: Login to GHCR using PAT
uses: docker/login-action@v4 uses: docker/login-action@v3
with: with:
registry: ghcr.io registry: ghcr.io
username: ${{ github.repository_owner }} username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }} password: ${{ secrets.GITHUB_TOKEN }}
- name: build regular container image - name: build rootless docker image
uses: docker/build-push-action@v7 uses: docker/build-push-action@v5
with:
context: .
platforms: linux/amd64,linux/arm64,linux/riscv64
push: true
tags: ${{ steps.meta.outputs.tags }}
annotations: ${{ steps.meta.outputs.annotations }}
- name: build rootless container image
uses: docker/build-push-action@v7
with: with:
context: . context: .
platforms: linux/amd64,linux/arm64,linux/riscv64 platforms: linux/amd64,linux/arm64,linux/riscv64
push: true push: true
file: Dockerfile.rootless file: Dockerfile.rootless
tags: ${{ steps.meta_rootless.outputs.tags }} tags: ${{ steps.meta.outputs.tags }}
annotations: ${{ steps.meta_rootless.outputs.annotations }} labels: ${{ steps.meta.outputs.labels }}

21
.gitignore vendored
View File

@@ -25,9 +25,6 @@ __debug_bin*
# Visual Studio # Visual Studio
/.vs/ /.vs/
# mise version managment tool
mise.toml
*.cgo1.go *.cgo1.go
*.cgo2.c *.cgo2.c
_cgo_defun.c _cgo_defun.c
@@ -55,7 +52,6 @@ cpu.out
*.log.*.gz *.log.*.gz
/gitea /gitea
/gitea-e2e
/gitea-vet /gitea-vet
/debug /debug
/integrations.test /integrations.test
@@ -68,9 +64,13 @@ cpu.out
/indexers /indexers
/log /log
/public/assets/img/avatar /public/assets/img/avatar
/tests/e2e-output
/tests/integration/gitea-integration-* /tests/integration/gitea-integration-*
/tests/integration/indexers-* /tests/integration/indexers-*
/tests/e2e/gitea-e2e-*
/tests/e2e/indexers-*
/tests/e2e/reports
/tests/e2e/test-artifacts
/tests/e2e/test-snapshots
/tests/*.ini /tests/*.ini
/tests/**/*.git/**/*.sample /tests/**/*.git/**/*.sample
/node_modules /node_modules
@@ -79,7 +79,6 @@ cpu.out
/yarn-error.log /yarn-error.log
/npm-debug.log* /npm-debug.log*
/.pnpm-store /.pnpm-store
/public/assets/.vite
/public/assets/js /public/assets/js
/public/assets/css /public/assets/css
/public/assets/fonts /public/assets/fonts
@@ -87,7 +86,10 @@ cpu.out
/vendor /vendor
/VERSION /VERSION
/.air /.air
/.go-licenses
# Files and folders that were previously generated
/public/assets/img/webpack
# Snapcraft # Snapcraft
/gitea_a*.txt /gitea_a*.txt
@@ -116,10 +118,7 @@ prime/
/.goosehints /.goosehints
/.windsurfrules /.windsurfrules
/.github/copilot-instructions.md /.github/copilot-instructions.md
/AGENT.md
/CLAUDE.md
/llms.txt /llms.txt
# Ignore worktrees when working on multiple branches
.worktrees/
# A Makefile for custom make targets
Makefile.local

51
.gitpod.yml Normal file
View File

@@ -0,0 +1,51 @@
tasks:
- name: Setup
init: |
cp -r contrib/ide/vscode .vscode
make deps
make build
command: |
gp sync-done setup
exit 0
- name: Run backend
command: |
gp sync-await setup
# Get the URL and extract the domain
url=$(gp url 3000)
domain=$(echo $url | awk -F[/:] '{print $4}')
if [ -f custom/conf/app.ini ]; then
sed -i "s|^ROOT_URL =.*|ROOT_URL = ${url}/|" custom/conf/app.ini
sed -i "s|^DOMAIN =.*|DOMAIN = ${domain}|" custom/conf/app.ini
sed -i "s|^SSH_DOMAIN =.*|SSH_DOMAIN = ${domain}|" custom/conf/app.ini
sed -i "s|^NO_REPLY_ADDRESS =.*|SSH_DOMAIN = noreply.${domain}|" custom/conf/app.ini
else
mkdir -p custom/conf/
echo -e "[server]\nROOT_URL = ${url}/" > custom/conf/app.ini
echo -e "\n[database]\nDB_TYPE = sqlite3\nPATH = $GITPOD_REPO_ROOT/data/gitea.db" >> custom/conf/app.ini
fi
export TAGS="sqlite sqlite_unlock_notify"
make watch-backend
- name: Run frontend
command: |
gp sync-await setup
make watch-frontend
openMode: split-right
vscode:
extensions:
- editorconfig.editorconfig
- dbaeumer.vscode-eslint
- golang.go
- stylelint.vscode-stylelint
- DavidAnson.vscode-markdownlint
- Vue.volar
- ms-azuretools.vscode-docker
- vitest.explorer
- cweijan.vscode-database-client2
- GitHub.vscode-pull-request-github
ports:
- name: Gitea
port: 3000

View File

@@ -6,20 +6,15 @@ linters:
default: none default: none
enable: enable:
- bidichk - bidichk
- bodyclose
- depguard - depguard
- dupl - dupl
- errcheck - errcheck
- forbidigo - forbidigo
- gocheckcompilerdirectives
- gocritic - gocritic
- goheader
- govet - govet
- ineffassign - ineffassign
- mirror - mirror
- modernize
- nakedret - nakedret
- nilnil
- nolintlint - nolintlint
- perfsprint - perfsprint
- revive - revive
@@ -50,16 +45,6 @@ linters:
desc: do not use the ini package, use gitea's config system instead desc: do not use the ini package, use gitea's config system instead
- pkg: gitea.com/go-chi/cache - pkg: gitea.com/go-chi/cache
desc: do not use the go-chi cache package, use gitea's cache system desc: do not use the go-chi cache package, use gitea's cache system
- pkg: github.com/pkg/errors
desc: use builtin errors package instead
migrations:
files:
- '**/models/migrations/**/*.go'
deny:
- pkg: code.gitea.io/gitea/models$
desc: migrations must not depend on the models package
- pkg: code.gitea.io/gitea/modules/structs
desc: migrations must not depend on modules/structs (API structures change over time)
nolintlint: nolintlint:
allow-unused: false allow-unused: false
require-explanation: true require-explanation: true
@@ -70,28 +55,38 @@ linters:
disabled-checks: disabled-checks:
- ifElseChain - ifElseChain
- singleCaseSwitch # Every time this occurred in the code, there was no other way. - singleCaseSwitch # Every time this occurred in the code, there was no other way.
- deprecatedComment # conflicts with go-swagger comments
revive: revive:
severity: error severity: error
rules: rules:
- name: atomic
- name: bare-return
- name: blank-imports - name: blank-imports
- name: constant-logical-expr - name: constant-logical-expr
- name: context-as-argument - name: context-as-argument
- name: context-keys-type - name: context-keys-type
- name: dot-imports - name: dot-imports
- name: duplicated-imports
- name: empty-lines - name: empty-lines
- name: error-naming
- name: error-return - name: error-return
- name: error-strings - name: error-strings
- name: errorf
- name: exported - name: exported
- name: identical-branches - name: identical-branches
- name: if-return - name: if-return
- name: increment-decrement - name: increment-decrement
- name: indent-error-flow
- name: modifies-value-receiver - name: modifies-value-receiver
- name: package-comments - name: package-comments
- name: range
- name: receiver-naming
- name: redefines-builtin-id - name: redefines-builtin-id
- name: string-of-int
- name: superfluous-else - name: superfluous-else
- name: time-naming - name: time-naming
- name: unconditional-recursion
- name: unexported-return - name: unexported-return
- name: unreachable-code
- name: var-declaration - name: var-declaration
- name: var-naming - name: var-naming
arguments: arguments:
@@ -112,17 +107,6 @@ linters:
- require-error - require-error
usetesting: usetesting:
os-temp-dir: true os-temp-dir: true
perfsprint:
concat-loop: false
govet:
enable:
- nilness
- unusedwrite
goheader:
values:
regexp:
HEADER: '((Copyright [^\n]+|All rights reserved\.)\n)*Copyright \d{4} (The (Gogs|Gitea) Authors|Gitea Authors|Gitea)\.( All rights reserved\.)?(\n(Copyright [^\n]+|All rights reserved\.))*\nSPDX-License-Identifier: [\w.-]+'
template: '{{ HEADER }}'
exclusions: exclusions:
generated: lax generated: lax
presets: presets:
@@ -134,12 +118,16 @@ linters:
- linters: - linters:
- dupl - dupl
- errcheck - errcheck
- gocyclo
- gosec
- staticcheck - staticcheck
- unparam - unparam
path: _test\.go path: _test\.go
- linters: - linters:
- dupl - dupl
- errcheck - errcheck
- gocyclo
- gosec
path: models/migrations/v path: models/migrations/v
- linters: - linters:
- forbidigo - forbidigo
@@ -151,8 +139,12 @@ linters:
- gocritic - gocritic
text: (?i)`ID' should not be capitalized text: (?i)`ID' should not be capitalized
- linters: - linters:
- deadcode
- unused - unused
text: (?i)swagger text: (?i)swagger
- linters:
- staticcheck
text: (?i)argument x is overwritten before first use
- linters: - linters:
- gocritic - gocritic
text: '(?i)commentFormatting: put a space between `//` and comment text' text: '(?i)commentFormatting: put a space between `//` and comment text'
@@ -161,7 +153,6 @@ linters:
text: '(?i)exitAfterDefer:' text: '(?i)exitAfterDefer:'
paths: paths:
- node_modules - node_modules
- .venv
- public - public
- web_src - web_src
- third_party$ - third_party$
@@ -172,25 +163,20 @@ issues:
max-same-issues: 0 max-same-issues: 0
formatters: formatters:
enable: enable:
- gci - gofmt
- gofumpt - gofumpt
settings: settings:
gci:
custom-order: true
sections:
- standard
- prefix(code.gitea.io/gitea)
- blank
- default
gofumpt: gofumpt:
extra-rules: true extra-rules: true
exclusions: exclusions:
generated: lax generated: lax
paths: paths:
- node_modules - node_modules
- .venv
- public - public
- web_src - web_src
- third_party$
- builtin$
- examples$
run: run:
timeout: 10m timeout: 10m

View File

@@ -21,7 +21,9 @@ rules:
comments-indentation: comments-indentation:
level: error level: error
document-start: disable document-start:
level: error
present: false
document-end: document-end:
present: false present: false

View File

@@ -1,11 +0,0 @@
- Use `make help` to find available development targets
- Run `make fmt` to format `.go` files, and run `make lint-go` to lint them
- Run `make lint-js` to lint `.ts` files
- Run `make tidy` after any `go.mod` changes
- Add the current year into the copyright header of new `.go` files
- Ensure no trailing whitespace in edited files
- Never force-push, amend, or squash unless asked. Use new commits and normal push for pull request updates
- Preserve existing code comments, do not remove or rewrite comments that are still relevant
- In TypeScript, use `!` (non-null assertion) instead of `?.`/`??` when a value is known to always exist
- Include authorship attribution in issue and pull request comments
- Add `Co-Authored-By` lines to all commits, indicating name and model used

View File

@@ -4,513 +4,7 @@ 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.26.0](https://github.com/go-gitea/gitea/releases/tag/v1.26.0) - 2026-04-17 ## [1.25.2](https://github.com/go-gitea/gitea/releases/tag/1.25.2) - 2025-11-23
* BREAKING
* Correct swagger annotations for enums, status codes, and notification state (#37030)
* Remove GET API registration-token (#36801)
* Support Actions `concurrency` syntax (#32751)
* Make PUBLIC_URL_DETECTION default to "auto" (#36955)
* SECURITY
* Bound PageSize in `ListUnadoptedRepositories` (#36884)
* FEATURES
* Support Actions `concurrency` syntax (#32751)
* Add terraform state registry (#36710)
* Instance-wide (global) info banner and maintenance mode (#36571)
* Support rendering OpenAPI spec (#36449)
* Add keyboard shortcuts for repository file and code search (#36416)
* Add support for archive-upload rpc (#36391)
* Add ability to download subpath archive (#36371)
* Add workflow dependencies visualization (#26062) (#36248) & Restyle Workflow Graph (#36912)
* Automatic generation of release notes (#35977)
* Add "Go to file", "Delete Directory" to repo file list page (#35911)
* Introduce "config edit-ini" sub command to help maintaining INI config file (#35735)
* Add button to re-run failed jobs in Actions (#36924)
* Support actions and reusable workflows from private repos (#32562)
* Add summary to action runs view (#36883)
* Add user badges (#36752)
* Add configurable permissions for Actions automatic tokens (#36173)
* Add per-runner "Disable/Pause" (#36776)
* Feature non-zipped actions artifacts (action v7 / nodejs / npm v6.2.0) (#36786)
* PERFORMANCE
* WorkflowDispatch API optionally return runid (#36706)
* Add render cache for SVG icons (#36863)
* Load `mentionValues` asynchronously (#36739)
* Lazy-load some Vue components, fix heatmap chunk loading on every page (#36719)
* Load heatmap data asynchronously (#36622)
* Use prev/next pagination for user profile activities page to speed up (#36642)
* Refactor cat-file batch operations and support `--batch-command` approach (#35775)
* Use merge tree to detect conflicts when possible (#36400)
* ENHANCEMENTS
* Implement logout redirection for reverse proxy auth setups (#36085) (#37171)
* Adds option to force update new branch in contents routes (#35592)
* Add viewer controller for mermaid (zoom, drag) (#36557)
* Add code editor setting dropdowns (#36534)
* Add `elk` layout support to mermaid (#36486)
* Add resolve/unresolve review comment API endpoints (#36441)
* Allow configuring default PR base branch (fixes #36412) (#36425)
* Add support for RPM Errata (updateinfo.xml) (#37125)
* Require additional user confirmation for making repo private (#36959)
* Add `actions.WORKFLOW_DIRS` setting (#36619)
* Avoid opening new tab when downloading actions logs (#36740)
* Implements OIDC RP-Initiated Logout (#36724)
* Show workflow link (#37070)
* Desaturate dark theme background colors (#37056)
* Refactor "org teams" page and help new users to "add member" to an org (#37051)
* Add webhook name field to improve webhook identification (#37025) (#37040)
* Make task list checkboxes clickable in the preview tab (#37010)
* Improve severity labels in Actions logs and tweak colors (#36993)
* Linkify URLs in Actions workflow logs (#36986)
* Allow text selection on checkbox labels (#36970)
* Support dark/light theme images in markdown (#36922)
* Enable native dark mode for swagger-ui (#36899)
* Rework checkbox styling, remove `input` border hover effect (#36870)
* Refactor storage content-type handling of ServeDirectURL (#36804)
* Use "Enable Gravatar" but not "Disable" (#36771)
* Use case-insensitive matching for Git error "Not a valid object name" (#36728)
* Add "Copy Source" to markup comment menu (#36726)
* Change image transparency grid to CSS (#36711)
* Add "Run" prefix for unnamed action steps (#36624)
* Persist actions log time display settings in `localStorage` (#36623)
* Use first commit title for multi-commit PRs and fix auto-focus title field (#36606)
* Improve BuildCaseInsensitiveLike with lowercase (#36598)
* Improve diff highlighting (#36583)
* Exclude cancelled runs from failure-only email notifications (#36569)
* Use full-file highlighting for diff sections (#36561)
* Color command/error logs in Actions log (#36538)
* Add paging headers (#36521)
* Improve timeline entries for WIP prefix changes in pull requests (#36518)
* Add FOLDER_ICON_THEME configuration option (#36496)
* Normalize guessed languages for code highlighting (#36450)
* Add chunked transfer encoding support for LFS uploads (#36380)
* Indicate when only optional checks failed (#36367)
* Add 'allow_maintainer_edit' API option for creating a pull request (#36283)
* Support closing keywords with URL references (#36221)
* Improve diff file headers (#36215)
* Fix and enhance comment editor monospace toggle (#36181)
* Add git.DIFF_RENAME_SIMILARITY_THRESHOLD option (#36164)
* Add matching pair insertion to markdown textarea (#36121)
* Add sorting/filtering to admin user search API endpoint (#36112)
* Allow action user have read permission in public repo like other user (#36095)
* Disable matchBrackets in monaco (#36089)
* Use GitHub-style commit message for squash merge (#35987)
* Make composer registry support tar.gz and tar.bz2 and fix bugs (#35958)
* Add GITEA_PR_INDEX env variable to githooks (#35938)
* Add proper error message if session provider can not be created (#35520)
* Add button to copy file name in PR files (#35509)
* Move `X_FRAME_OPTIONS` setting from `cors` to `security` section (#30256)
* Add placeholder content for empty content page (#37114)
* Add `DEFAULT_DELETE_BRANCH_AFTER_MERGE` setting (#36917)
* Redirect to the only OAuth2 provider when no other login methods and fix various problems (#36901)
* Add admin badge to navbar avatar (#36790)
* Add `never` option to `PUBLIC_URL_DETECTION` configuration (#36785)
* Add background and run count to actions list page (#36707)
* Add icon to buttons "Close with Comment", "Close Pull Request", "Close Issue" (#36654)
* Add support for in_progress event in workflow_run webhook (#36979)
* Report commit status for pull_request_review events (#36589)
* Render merged pull request title as such in dashboard feed (#36479)
* Feature to be able to filter project boards by milestones (#36321)
* Use user id in noreply emails (#36550)
* Enable pagination on GiteaDownloader.getIssueReactions() (#36549)
* Remove striped tables in UI (#36509)
* Improve control char rendering and escape button styling (#37094)
* Support legacy run/job index-based URLs and refactor migration 326 (#37008)
* Add date to "No Contributions" tooltip (#36190)
* Show edit page confirmation dialog on tree view file change (#36130)
* Mention proc-receive in text for dashboard.resync_all_hooks func (#35991)
* Reuse selectable style for wiki (#35990)
* Support blue yellow colorblind theme (#35910)
* Support selecting theme on the footer (#35741)
* Improve online runner check (#35722)
* Add quick approve button on PR page (#35678)
* Enable commenting on expanded lines in PR diffs (#35662)
* Print PR-Title into tooltip for actions (#35579)
* Use explicit, stronger defaults for newly generated repo signing keys for Debian (#36236)
* Improve the compare page (#36261)
* Unify repo names in system notices (#36491)
* Move package settings to package instead of being tied to version (#37026)
* Add Actions API rerun endpoints for runs and jobs (#36768)
* Add branch_count to repository API (#35351) (#36743)
* Add created_by filter to SearchIssues (#36670)
* Allow admins to rename non-local users (#35970)
* Support updating branch via API (#35951)
* Add an option to automatically verify SSH keys from LDAP (#35927)
* Make "update file" API can create a new file when SHA is not set (#35738)
* Update issue.go with labels documentation (labels content, not ids) (#35522)
* Expose content_version for optimistic locking on issue and PR edits (#37035)
* Pass ServeHeaderOptions by value instead of pointer, fine tune httplib tests (#36982)
* BUGFIXES
* Frontend iframe renderer framework: 3D models, OpenAPI (#37233) (#37273)
* Fix CODEOWNERS absolute path matching. (#37244) (#37264)
* Swift registry metadata: preserve more JSON fields and accept empty metadata (#37254) (#37261)
* Fix user ssh key exporting and tests (#37256) (#37258)
* Fix team member avatar size and add tooltip (#37253)
* Fix commit title rendering in action run and blame (#37243) (#37251)
* Fix corrupted JSON caused by goccy library (#37214) (#37220)
* Add test for "fetch redirect", add CSS value validation for external render (#37207) (#37216)
* Fix incorrect concurrency check (#37205) (#37215)
* Fix handle missing base branch in PR commits API (#37193) (#37203)
* Fix encoding for Matrix Webhooks (#37190) (#37201)
* Fix handle fork-only commits in compare API (#37185) (#37199)
* Indicate form field readonly via background, fix RunUser config (#37175, #37180) (#37178)
* Report structurally invalid workflows to users (#37116) (#37164)
* Fix API not persisting pull request unit config when has_pull_requests is not set (#36718)
* Rename CSS variables and improve colorblind themes (#36353)
* Hide `add-matcher` and `remove-matcher` from actions job logs (#36520)
* Prevent navigation keys from triggering actions during IME composition (#36540)
* Fix vertical alignment of `.commit-sign-badge` children (#36570)
* Fix duplicate startup warnings in admin panel (#36641)
* Fix CODEOWNERS review request attribution using comment metadata (#36348)
* Fix HTML tags appearing in wiki table of contents (#36284)
* Fix various bugs (#37096)
* Fix various legacy problems (#37092)
* Fix RPM Registry 404 when package name contains 'package' (#37087)
* Merge some standalone Vite entries into index.js (#37085)
* Fix various problems (#37077)
* Fix issue label deletion with Actions tokens (#37013)
* Hide delete branch or tag buttons in mirror or archived repositories. (#37006)
* Fix org contact email not clearable once set (#36975)
* Fix a bug when forking a repository in an organization (#36950)
* Preserve sort order of exclusive labels from template repo (#36931)
* Make container registry support Apple Container (basic auth) (#36920)
* Fix the wrong push commits in the pull request when force push (#36914)
* Add class "list-header-filters" to the div for projects (#36889)
* Fix dbfs error handling (#36844)
* Fix incorrect viewed files counter if reverted change was viewed (#36819)
* Refactor avatar package, support default avatar fallback (#36788)
* Fix README symlink resolution in subdirectories like .github (#36775)
* Fix CSS stacking context issue in actions log (#36749)
* Add gpg signing for merge rebase and update by rebase (#36701)
* Delete non-exist branch should return 404 (#36694)
* Fix `TestActionsCollaborativeOwner` (#36657)
* Fix multi-arch Docker build SIGILL by splitting frontend stage (#36646)
* Fix linguist-detectable attribute being ignored for configuration files (#36640)
* Fix state desync in ComboMarkdownEditor (#36625)
* Unify DEFAULT_SHOW_FULL_NAME output in templates and dropdown (#36597)
* Pull Request Pusher should be the author of the merge (#36581)
* Fix various version parsing problems (#36553)
* Fix highlight diff result (#36539)
* Fix mirror sync parser and fix mirror messages (#36504)
* Fix bug when list pull request commits (#36485)
* Fix various bugs (#36446)
* Fix issue filter menu layout (#36426)
* Restrict branch naming when new change matches with protection rules (#36405)
* Fix link/origin referrer and login redirect (#36279)
* Generate IDs for HTML headings without id attribute (#36233)
* Use a migration test instead of a wrong test which populated the meta test repositories and fix a migration bug (#36160)
* Fix issue close timeline icon (#36138)
* Fix diff blob excerpt expansion (#35922)
* Fix external render (#35727)
* Fix review request webhook bug (#35339) (#35723)
* Fix shutdown waitgroup panic (#35676)
* Cleanup ActionRun creation (#35624)
* Fix possible bug when migrating issues/pull requests (#33487)
* Various fixes (#36697)
* Apply notify/register mail flags during install load (#37120)
* Repair duration display for bad stopped timestamps (#37121)
* Fix(upgrade.sh): use HTTPS for GPG key import and restore SELinux context after upgrade (#36930)
* Fix various trivial problems (#36921)
* Fix various trivial problems (#36953)
* Fix NuGet package upload error handling (#37074)
* Fix CodeQL code scanning alerts (#36858)
* Refactor issue sidebar and fix various problems (#37045)
* Fix various problems (#37029)
* Fix relative-time RangeError (#37021)
* Fix chroma lexer mapping (#36629)
* Fix typos and grammar in English locale (#36751)
* Fix milestone/project text overflow in issue sidebar (#36741)
* Fix `no-content` message not rendering after comment edit (#36733)
* Fix theme loading in development (#36605)
* Fix workflow run jobs API returning null steps (#36603)
* Fix timeline event layout overflow with long content (#36595)
* Fix minor UI issues in runner edit page (#36590)
* Fix incorrect vendored detections (#36508)
* Fix editorconfig not respected in PR Conversation view (#36492)
* Don't create self-references in merged PRs (#36490)
* Fix potential incorrect runID in run status update (#36437)
* Fix file-tree ui error when adding files to repo without commits (#36312)
* Improve image captcha contrast for dark mode (#36265)
* Fix panic in blame view when a file has only a single commit (#36230)
* Fix spelling error in migrate-storage cmd utility (#36226)
* Fix code highlighting on blame page (#36157)
* Fix nilnil in onedev downloader (#36154)
* Fix actions lint (#36029)
* Fix oauth2 session gob register (#36017)
* Fix Arch repo pacman.conf snippet (#35825)
* Fix a number of `strictNullChecks`-related issues (#35795)
* Fix URLJoin, markup render link reoslving, sign-in/up/linkaccount page common data (#36861)
* Hide delete directory button for mirror or archive repository and disable the menu item if user have no permission (#36384)
* Update message severity colors, fix navbar double border (#37019)
* Inline and lazy-load EasyMDE CSS, fix border colors (#36714)
* Closed milestones with no issues now show as 100% completed (#36220)
* Add test for ExtendCommentTreePathLength migration and fix bugs (#35791)
* Only turn links to current instance into hash links (#36237)
* Fix typos in code comments: doesnt, dont, wont (#36890)
* REFACTOR
* Clean up and improve non-gitea js error filter (#37148) (#37155)
* Always show owner/repo name in compare page dropdowns (#37172) (#37200)
* Remove dead CSS rules (#37173) (#37177)
* Replace Monaco with CodeMirror (#36764)
* Replace CSRF cookie with `CrossOriginProtection` (#36183)
* Replace index with id in actions routes (#36842)
* Remove unnecessary function parameter (#35765)
* Move jobparser from act repository to Gitea (#36699)
* Refactor compare router param parse (#36105)
* Optimize 'refreshAccesses' to perform update without removing then adding (#35702)
* Clean up checkbox cursor styles (#37016)
* Remove undocumented support of signing key in the repository git configuration file (#36143)
* Switch `cmd/` to use constructor functions. (#36962)
* Use `relative-time` to render absolute dates (#36238)
* Some refactors about GetMergeBase (#36186)
* Some small refactors (#36163)
* Use gitRepo as parameter instead of repopath when invoking sign functions (#36162)
* Move blame to gitrepo (#36161)
* Move some functions to gitrepo package to reduce RepoPath reference directly (#36126)
* Use gitrepo's clone and push when possible (#36093)
* Remove mermaid margin workaround (#35732)
* Move some functions to gitrepo package (#35543)
* Move GetDiverging functions to gitrepo (#35524)
* Use global lock instead of status pool for cron lock (#35507)
* Use explicit mux instead of DefaultServeMux (#36276)
* Use gitrepo's push function (#36245)
* Pass request context to generateAdditionalHeadersForIssue (#36274)
* Move assign project when creating pull request to the same database transaction (#36244)
* Move catfile batch to a sub package of git module (#36232)
* Use gitrepo.Repository instead of wikipath (#35398)
* Use experimental go json v2 library (#35392)
* Refactor template render (#36438)
* Refactor GetRepoRawDiffForFile to avoid unnecessary pipe or goroutine (#36434)
* Refactor text utility classes to Tailwind CSS (#36703)
* Refactor git command stdio pipe (#36422)
* Refactor git command context & pipeline (#36406)
* Refactor git command stdio pipe (#36393)
* Remove unused functions (#36672)
* Refactor Actions Token Access (#35688)
* Move commit related functions to gitrepo package (#35600)
* Move archive function to repo_model and gitrepo (#35514)
* Move some functions to gitrepo package (#35503)
* Use git model to detect whether branch exist instead of gitrepo method (#35459)
* Some refactor for repo path (#36251)
* Extract helper functions from SearchIssues (#36158)
* Refactor merge conan and container auth preserve actions taskID (#36560)
* Refactor Nuget Auth to reuse Basic Auth Token Validation (#36558)
* Refactor ActionsTaskID (#36503)
* Refactor auth middleware (#36848)
* Refactor code render and render control chars (#37078)
* Clean up AppURL, remove legacy origin-url webcomponent (#37090)
* Remove `util.URLJoin` and replace all callers with direct path concatenation (#36867)
* Replace legacy tw-flex utility classes with flex-text-block/inline (#36778)
* Mark unused&immature activitypub as "not implemented" (#36789)
* TESTING
* Add e2e tests for server push events (#36879)
* Rework e2e tests (#36634)
* Add e2e reaction test, improve accessibility, enable parallel testing (#37081)
* Increase e2e test timeouts on CI to fix flaky tests (#37053)
* BUILD
* Upgrade go-git to v5.18.0 (#37269)
* Replace rollup-plugin-license with rolldown-license-plugin (#37130) (#37158)
* Bump min go version to 1.26.2 (#37139) (#37143)
* Convert locale files from ini to json format (#35489)
* Bump golangci-lint to 2.7.2, enable modernize stringsbuilder (#36180)
* Port away from `flake-utils` (#35675)
* Remove nolint (#36252)
* Update the Unlicense copy to latest version (#36636)
* Update to go 1.26.0 and golangci-lint 2.9.0 (#36588)
* Replace `google/go-licenses` with custom generation (#36575)
* Update go dependencies (#36548)
* Bump appleboy/git-push-action from 1.0.0 to 1.2.0 (#36306)
* Remove fomantic form module (#36222)
* Bump setup-node to v6, re-enable cache (#36207)
* Bump crowdin/github-action from 1 to 2 (#36204)
* Revert "Bump alpine to 3.23 (#36185)" (#36202)
* Update chroma to v2.21.1 (#36201)
* Bump astral-sh/setup-uv from 6 to 7 (#36198)
* Bump docker/build-push-action from 5 to 6 (#36197)
* Bump aws-actions/configure-aws-credentials from 4 to 5 (#36196)
* Bump dev-hanz-ops/install-gh-cli-action from 0.1.0 to 0.2.1 (#36195)
* Add JSON linting (#36192)
* Enable dependabot for actions (#36191)
* Bump alpine to 3.23 (#36185)
* Update chroma to v2.21.0 (#36171)
* Update JS deps and eslint enhancements (#36147)
* Update JS deps (#36091)
* update golangci-lint to v2.7.0 (#36079)
* Update JS deps, fix deprecations (#36040)
* Update JS deps (#35978)
* Add toolchain directive to go.mod (#35901)
* Move `gitea-vet` to use `go tool` (#35878)
* Update to go 1.25.4 (#35877)
* Enable TypeScript `strictNullChecks` (#35843)
* Enable `vue/require-typed-ref` eslint rule (#35764)
* Update JS dependencies (#35759)
* Move `codeformat` folder to tools (#35758)
* Update dependencies (#35733)
* Bump happy-dom from 20.0.0 to 20.0.2 (#35677)
* Bump setup-go to v6 (#35660)
* Update JS deps, misc tweaks (#35643)
* Bump happy-dom from 19.0.2 to 20.0.0 (#35625)
* Use bundled version of spectral (#35573)
* Update JS and PY deps (#35565)
* Bump github.com/wneessen/go-mail from 0.6.2 to 0.7.1 (#35557)
* Migrate from webpack to vite (#37002)
* Update JS dependencies and misc tweaks (#37064)
* Update to eslint 10 (#36925)
* Optimize Docker build with dependency layer caching (#36864)
* Update JS deps (#36850)
* Update tool dependencies and fix new lint issues (#36702)
* Remove redundant linter rules (#36658)
* Move Fomantic dropdown CSS to custom module (#36530)
* Remove and forbid `@ts-expect-error` (#36513)
* Refactor git command stderr handling (#36402)
* Enable gocheckcompilerdirectives linter (#36156)
* Replace `lint-go-gopls` with additional `govet` linters (#36028)
* Update golangci-lint to v2.6.0 (#35801)
* Misc tool tweaks (#35734)
* Add cache to container build (#35697)
* Upgrade vite (#37126)
* Update `setup-uv` to v8.0.0 (#37101)
* Upgrade `go-git` to v5.17.2 and related dependencies (#37060)
* Raise minimum Node.js version to 22.18.0 (#37058)
* Upgrade `golang.org/x/image` to v0.38.0 (#37054)
* Update minimum go version to 1.26.1, golangci-lint to 2.11.2, fix test style (#36876)
* Enable eslint concurrency (#36878)
* Vendor relative-time-element as local web component (#36853)
* Update material-icon-theme v5.32.0 (#36832)
* Update Go dependencies (#36781)
* Upgrade minimatch (#36760)
* Remove i18n backport tool at the moment because of translation format changed (#36643)
* Update emoji data for Unicode 16 (#36596)
* Update JS dependencies, adjust webpack config, misc fixes (#36431)
* Update material-icon-theme to v5.31.0 (#36427)
* Update JS and PY deps (#36383)
* Bump alpine to 3.23, add platforms to `docker-dryrun` (#36379)
* Update JS deps (#36354)
* Update goldmark to v1.7.16 (#36343)
* Update chroma to v2.22.0 (#36342)
* DOCS
* Update AI Contribution Policy (#37022)
* Update AGENTS.md with additional guidelines (#37018)
* Add missing cron tasks to example ini (#37012)
* Add AI Contribution Policy to CONTRIBUTING.md (#36651)
* Minor punctuation improvement in CONTRIBUTING.md (#36291)
* Add documentation for markdown anchor post-processing (#36443)
* MISC
* Correct spelling (#36783)
* Update Nix flake (#37110)
* Update Nix flake (#37024)
* Add valid github scopes (#36977)
* Update Nix flake (#36943)
* Update Nix flake (#36902)
* Update Nix flake (#36857)
* Update Nix flake (#36787)
## [1.25.5](https://github.com/go-gitea/gitea/releases/tag/v1.25.5) - 2026-03-10
* SECURITY
* Toolchain Update to Go 1.25.6 (#36480) (#36487)
* Adjust the toolchain version (#36537) (#36542)
* Update toolchain to 1.25.8 for v1.25 (#36888)
* Prevent redirect bypasses via backslash-encoded paths (#36660) (#36716)
* Fix get release draft permission check (#36659) (#36715)
* Fix a bug user could change another user's primary email (#36586) (#36607)
* Fix OAuth2 authorization code expiry and reuse handling (#36797) (#36851)
* Add validation constraints for repository creation fields (#36671) (#36757)
* Fix bug to check whether user can update pull request branch or rebase branch (#36465) (#36838)
* Add migration http transport for push/sync mirror lfs (#36665) (#36691)
* Fix track time list permission check (#36662) (#36744)
* Fix track time issue id (#36664) (#36689)
* Fix path resolving (#36734) (#36746)
* Fix dump release asset bug (#36799) (#36839)
* Fix org permission API visibility checks for hidden members and private orgs (#36798) (#36841)
* Fix forwarded proto handling for public URL detection (#36810) (#36836)
* Add a git grep search timeout (#36809) (#36835)
* Fix oauth2 s256 (#36462) (#36477)
* ENHANCEMENTS
* Make `security-check` informational only (#36681) (#36852)
* Upgrade to github.com/cloudflare/circl 1.6.3, svgo 4.0.1, markdownlint-cli 0.48.0 (#36840)
* Add some validation on values provided to USER_DISABLED_FEATURES and EXTERNAL_USER_DISABLED_FEATURES (#36688) (#36692)
* Upgrade gogit to 5.16.5 (#36687)
* Add wrap to runner label list (#36565) (#36574)
* Add dnf5 command for Fedora in RPM package instructions (#36527) (#36572)
* Allow scroll propagation outside code editor (#36502) (#36510)
* BUGFIXES
* Fix non-admins unable to automerge PRs from forks (#36833) (#36843)
* Fix bug when pushing mirror with wiki (#36795) (#36807)
* Fix artifacts v4 backend upload problems (#36805) (#36834)
* Fix CRAN package version validation to allow more than 4 version components (#36813) (#36821)
* Fix force push time-line commit comments of pull request (#36653) (#36717)
* Fix SVG height calculation in diff viewer (#36748) (#36750)
* Fix push time bug (#36693) (#36713)
* Fix bug the protected branch rule name is conflicted with renamed branch name (#36650) (#36661)
* Fix bug when do LFS GC (#36500) (#36608)
* Fix focus lost bugs in the Monaco editor (#36609)
* Reprocess htmx content after loading more files (#36568) (#36577)
* Fix assignee sidebar links and empty placeholder (#36559) (#36563)
* Fix issues filter dropdown showing empty label scope section (#36535) (#36544)
* Fix various mermaid bugs (#36547) (#36552)
* Fix data race when uploading container blobs concurrently (#36524) (#36526)
* Correct spacing between username and bot label (#36473) (#36484)
## [1.25.4](https://github.com/go-gitea/gitea/releases/tag/v1.25.4) - 2026-01-15
* SECURITY
* Release attachments must belong to the intended repo (#36347) (#36375)
* Fix permission check on org project operations (#36318) (#36373)
* Clean watches when make a repository private and check permission when send release emails (#36319) (#36370)
* Add more check for stopwatch read or list (#36340) (#36368)
* Fix openid setting check (#36346) (#36361)
* Fix cancel auto merge bug (#36341) (#36356)
* Fix delete attachment check (#36320) (#36355)
* LFS locks must belong to the intended repo (#36344) (#36349)
* Fix bug on notification read (#36339) #36387
* ENHANCEMENTS
* Add more routes to the "expensive" list (#36290)
* Make "commit statuses" API accept slashes in "ref" (#36264) (#36275)
* BUGFIXES
* Fix git http service handling (#36396)
* Fix markdown newline handling during IME composition (#36421) (#36424)
* Fix missing repository id when migrating release attachments (#36389)
* Fix bug when compare in the pull request (#36363) (#36372)
* Fix incorrect text content detection (#36364) (#36369)
* Fill missing `has_code` in repository api (#36338) (#36359)
* Fix notifications pagination query parameters (#36351) (#36358)
* Fix some trivial problems (#36336) (#36337)
* Prevent panic when GitLab release has more links than sources (#36295) (#36305)
* Fix stats bug when syncing release (#36285) (#36294)
* Always honor user's choice for "delete branch after merge" (#36281) (#36286)
* Use the requested host for LFS links (#36242) (#36258)
* Fix panic when get editor config file (#36241) (#36247)
* Fix regression in writing authorized principals (#36213) (#36218)
* Fix WebAuthn error checking (#36219) (#36235)
## [1.25.3](https://github.com/go-gitea/gitea/releases/tag/v1.25.3) - 2025-12-17
* SECURITY
* Bump toolchain to go1.25.5, misc fixes (#36082)
* ENHANCEMENTS
* Add strikethrough button to markdown editor (#36087) (#36104)
* Add "site admin" back to profile menu (#36010) (#36013)
* Improve math rendering (#36124) (#36125)
* BUGFIXES
* Check user visibility when redirecting to a renamed user (#36148) (#36159)
* Fix various bugs (#36139) (#36151)
* Fix bug when viewing the commit diff page with non-ANSI files (#36149) (#36150)
* Hide RSS icon when viewing a file not under a branch (#36135) (#36141)
* Fix SVG size calulation, only use `style` attribute (#36133) (#36134)
* Make Golang correctly delete temp files during uploading (#36128) (#36129)
* Fix the bug when ssh clone with redirect user or repository (#36039) (#36090)
* Use Golang net/smtp instead of gomail's smtp to send email (#36055) (#36083)
* Fix edit user email bug in API (#36068) (#36081)
* Fix bug when updating user email (#36058) (#36066)
* Fix incorrect viewed files counter if file has changed (#36009) (#36047)
* Fix container registry error handling (#36021) (#36037)
* Fix webAuthn insecure error view (#36165) (#36179)
* Fix some file icon ui (#36078) (#36088)
* Fix Actions `pull_request.paths` being triggered incorrectly by rebase (#36045) (#36054)
* Fix error handling in mailer and wiki services (#36041) (#36053)
* Fix bugs when comparing and creating pull request (#36166) (#36144)
## [1.25.2](https://github.com/go-gitea/gitea/releases/tag/v1.25.2) - 2025-11-23
* SECURITY * SECURITY
* Upgrade golang.org/x/crypto to 0.45.0 (#35985) (#35988) * Upgrade golang.org/x/crypto to 0.45.0 (#35985) (#35988)

View File

@@ -1 +0,0 @@
@AGENTS.md

View File

@@ -1,25 +1,19 @@
# Contribution Guidelines # Contribution Guidelines
This document explains how to contribute changes to the Gitea project. Topic-specific guides live in separate files so the essentials are easier to find.
| Topic | Document |
| :---- | :------- |
| Backend (Go modules, API v1) | [docs/guideline-backend.md](docs/guideline-backend.md) |
| Frontend (npm, UI guidelines) | [docs/guideline-frontend.md](docs/guideline-frontend.md) |
| Maintainers, TOC, labels, merge queue, commit format for mergers | [docs/community-governance.md](docs/community-governance.md) |
| Release cycle, backports, tagging releases | [docs/release-management.md](docs/release-management.md) |
<details><summary>Table of Contents</summary> <details><summary>Table of Contents</summary>
- [Contribution Guidelines](#contribution-guidelines) - [Contribution Guidelines](#contribution-guidelines)
- [Introduction](#introduction) - [Introduction](#introduction)
- [AI Contribution Policy](#ai-contribution-policy)
- [Issues](#issues) - [Issues](#issues)
- [How to report issues](#how-to-report-issues) - [How to report issues](#how-to-report-issues)
- [Types of issues](#types-of-issues) - [Types of issues](#types-of-issues)
- [Discuss your design before the implementation](#discuss-your-design-before-the-implementation) - [Discuss your design before the implementation](#discuss-your-design-before-the-implementation)
- [Issue locking](#issue-locking) - [Issue locking](#issue-locking)
- [Building Gitea](#building-gitea) - [Building Gitea](#building-gitea)
- [Dependencies](#dependencies)
- [Backend](#backend)
- [Frontend](#frontend)
- [Design guideline](#design-guideline)
- [Styleguide](#styleguide) - [Styleguide](#styleguide)
- [Copyright](#copyright) - [Copyright](#copyright)
- [Testing](#testing) - [Testing](#testing)
@@ -27,39 +21,52 @@ This document explains how to contribute changes to the Gitea project. Topic-spe
- [Code review](#code-review) - [Code review](#code-review)
- [Pull request format](#pull-request-format) - [Pull request format](#pull-request-format)
- [PR title and summary](#pr-title-and-summary) - [PR title and summary](#pr-title-and-summary)
- [Milestone](#milestone)
- [Labels](#labels)
- [Breaking PRs](#breaking-prs) - [Breaking PRs](#breaking-prs)
- [What is a breaking PR?](#what-is-a-breaking-pr) - [What is a breaking PR?](#what-is-a-breaking-pr)
- [How to handle breaking PRs?](#how-to-handle-breaking-prs) - [How to handle breaking PRs?](#how-to-handle-breaking-prs)
- [Maintaining open PRs](#maintaining-open-prs) - [Maintaining open PRs](#maintaining-open-prs)
- [Reviewing PRs](#reviewing-prs) - [Getting PRs merged](#getting-prs-merged)
- [For PR authors](#for-pr-authors) - [Final call](#final-call)
- [Commit messages](#commit-messages)
- [PR Co-authors](#pr-co-authors)
- [PRs targeting `main`](#prs-targeting-main)
- [Backport PRs](#backport-prs)
- [Documentation](#documentation) - [Documentation](#documentation)
- [API v1](#api-v1)
- [GitHub API compatibility](#github-api-compatibility)
- [Adding/Maintaining API routes](#addingmaintaining-api-routes)
- [When to use what HTTP method](#when-to-use-what-http-method)
- [Requirements for API routes](#requirements-for-api-routes)
- [Backports and Frontports](#backports-and-frontports)
- [What is backported?](#what-is-backported)
- [How to backport?](#how-to-backport)
- [Format of backport PRs](#format-of-backport-prs)
- [Frontports](#frontports)
- [Developer Certificate of Origin (DCO)](#developer-certificate-of-origin-dco) - [Developer Certificate of Origin (DCO)](#developer-certificate-of-origin-dco)
- [Release Cycle](#release-cycle)
- [Maintainers](#maintainers)
- [Technical Oversight Committee (TOC)](#technical-oversight-committee-toc)
- [TOC election process](#toc-election-process)
- [Current TOC members](#current-toc-members)
- [Previous TOC/owners members](#previous-tocowners-members)
- [Governance Compensation](#governance-compensation)
- [TOC \& Working groups](#toc--working-groups)
- [Roadmap](#roadmap)
- [Versions](#versions)
- [Releasing Gitea](#releasing-gitea)
</details> </details>
## Introduction ## Introduction
This document explains how to contribute changes to the Gitea project. \
It assumes you have followed the [installation instructions](https://docs.gitea.com/category/installation). \ It assumes you have followed the [installation instructions](https://docs.gitea.com/category/installation). \
Sensitive security-related issues should be reported to [security@gitea.io](mailto:security@gitea.io). Sensitive security-related issues should be reported to [security@gitea.io](mailto:security@gitea.io).
For configuring IDEs for Gitea development, see the [contributed IDE configurations](contrib/ide/). For configuring IDEs for Gitea development, see the [contributed IDE configurations](contrib/ide/).
## AI Contribution Policy
Contributions made with the assistance of AI tools are welcome, but contributors must use them responsibly and disclose that use clearly.
1. Review AI-generated code closely before marking a pull request ready for review.
2. Manually test the changes and add appropriate automated tests where feasible.
3. Only use AI to assist in contributions that you understand well enough to explain, defend, and revise yourself during review.
4. Disclose AI-assisted content clearly.
5. Do not use AI to reply to questions about your issue or pull request. The questions are for you, not an AI model.
6. AI may be used to help draft issues and pull requests, but contributors remain responsible for the accuracy, completeness, and intent of what they submit.
Maintainers reserve the right to close pull requests and issues that do not disclose AI assistance, that appear to be low-quality AI-generated content, or where the contributor cannot explain or defend the proposed changes themselves.
We welcome new contributors, but cannot sustain the effort of supporting contributors who primarily defer to AI rather than engaging substantively with the review process.
## Issues ## Issues
### How to report issues ### How to report issues
@@ -73,7 +80,7 @@ The more detailed and specific you are, the faster we can fix the issue. \
It is really helpful if you can reproduce your problem on a site running on the latest commits, i.e. <https://demo.gitea.com>, as perhaps your problem has already been fixed on a current version. \ It is really helpful if you can reproduce your problem on a site running on the latest commits, i.e. <https://demo.gitea.com>, as perhaps your problem has already been fixed on a current version. \
Please follow the guidelines described in [How to Report Bugs Effectively](http://www.chiark.greenend.org.uk/~sgtatham/bugs.html) for your report. Please follow the guidelines described in [How to Report Bugs Effectively](http://www.chiark.greenend.org.uk/~sgtatham/bugs.html) for your report.
Please be kindremember that Gitea comes at no cost to you, and you're getting free help. Please be kind, remember that Gitea comes at no cost to you, and you're getting free help.
### Types of issues ### Types of issues
@@ -108,6 +115,34 @@ If further discussion is needed, we encourage you to open a new issue instead an
See the [development setup instructions](https://docs.gitea.com/development/hacking-on-gitea). See the [development setup instructions](https://docs.gitea.com/development/hacking-on-gitea).
## Dependencies
### Backend
Go dependencies are managed using [Go Modules](https://go.dev/cmd/go/#hdr-Module_maintenance). \
You can find more details in the [go mod documentation](https://go.dev/ref/mod) and the [Go Modules Wiki](https://github.com/golang/go/wiki/Modules).
Pull requests should only modify `go.mod` and `go.sum` where it is related to your change, be it a bugfix or a new feature. \
Apart from that, these files should only be modified by Pull Requests whose only purpose is to update dependencies.
The `go.mod`, `go.sum` update needs to be justified as part of the PR description,
and must be verified by the reviewers and/or merger to always reference
an existing upstream commit.
### Frontend
For the frontend, we use [npm](https://www.npmjs.com/).
The same restrictions apply for frontend dependencies as for backend dependencies, with the exceptions that the files for it are `package.json` and `package-lock.json`, and that new versions must always reference an existing version.
## Design guideline
Depending on your change, please read the
- [backend development guideline](https://docs.gitea.com/contributing/guidelines-backend)
- [frontend development guideline](https://docs.gitea.com/contributing/guidelines-frontend)
- [refactoring guideline](https://docs.gitea.com/contributing/guidelines-refactoring)
## Styleguide ## Styleguide
You should always run `make fmt` before committing to conform to Gitea's styleguide. You should always run `make fmt` before committing to conform to Gitea's styleguide.
@@ -131,32 +166,24 @@ Here's how to run the test suite:
- code lint - code lint
| | | | | |
| :-------------------- | :--------------------------------------------------------------------------- | | :-------------------- | :---------------------------------------------------------------- |
|``make lint`` | lint everything (not needed if you only change the front- **or** backend) | |``make lint`` | lint everything (not needed if you only change the front- **or** backend) |
|``make lint-frontend`` | lint frontend files | |``make lint-frontend`` | lint frontend files |
|``make lint-backend`` | lint backend files | |``make lint-backend`` | lint backend files |
- run tests (we suggest running them on Linux) - run tests (we suggest running them on Linux)
| Command | Action | | | Command | Action | |
| :------------------------------------------ | :------------------------------------------------------- | ------------------------------------------- | | :------------------------------------- | :----------------------------------------------- | ------------ |
|``make test[\#SpecificTestName]`` | run unit test(s) | | |``make test[\#SpecificTestName]`` | run unit test(s) | |
|``make test-sqlite[\#SpecificTestName]`` | run [integration](tests/integration) test(s) for SQLite | [More details](tests/integration/README.md) | |``make test-sqlite[\#SpecificTestName]``| run [integration](tests/integration) test(s) for SQLite |[More details](tests/integration/README.md) |
|``make test-e2e`` | run [end-to-end](tests/e2e) test(s) using Playwright | | |``make test-e2e-sqlite[\#SpecificTestName]``| run [end-to-end](tests/e2e) test(s) for SQLite |[More details](tests/e2e/README.md) |
- E2E test environment variables
| Variable | Description |
| :-------------------------------- | :---------------------------------------------------------- |
| ``GITEA_TEST_E2E_DEBUG`` | When set, show Gitea server output |
| ``GITEA_TEST_E2E_FLAGS`` | Additional flags passed to Playwright, for example ``--ui`` |
| ``GITEA_TEST_E2E_TIMEOUT_FACTOR`` | Timeout multiplier (default: 3 on CI, 1 locally) |
## Translation ## Translation
All translation work happens on [Crowdin](https://translate.gitea.com). 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.json). 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. \
Once a language has reached a **satisfactory percentage** of translated keys (~25%), it will be synced back into this repo and included in the next released version. Once a language has reached a **satisfactory percentage** of translated keys (~25%), it will be synced back into this repo and included in the next released version.
@@ -165,8 +192,6 @@ The tool `go run build/backport-locale.go` can be used to backport locales from
## Code review ## Code review
How labels, milestones, and the merge queue work is documented in [docs/community-governance.md](docs/community-governance.md).
### Pull request format ### Pull request format
Please try to make your pull request easy to review for us. \ Please try to make your pull request easy to review for us. \
@@ -211,6 +236,29 @@ Fixes/Closes/Resolves #<ISSUE_NR_Y>.
to your summary. \ to your summary. \
Each issue that will be closed must stand on a separate line. Each issue that will be closed must stand on a separate line.
### Milestone
A PR should only be assigned to a milestone if it will likely be merged into the given version. \
As a rule of thumb, assume that a PR will stay open for an additional month for every 100 added lines. \
PRs without a milestone may not be merged.
### Labels
Almost all labels used inside Gitea can be classified as one of the following:
- `modifies/…`: Determines which parts of the codebase are affected. These labels will be set through the CI.
- `topic/…`: Determines the conceptual component of Gitea that is affected, i.e. issues, projects, or authentication. At best, PRs should only target one component but there might be overlap. Must be set manually.
- `type/…`: Determines the type of an issue or PR (feature, refactoring, docs, bug, …). If GitHub supported scoped labels, these labels would be exclusive, so you should set **exactly** one, not more or less (every PR should fall into one of the provided categories, and only one).
- `issue/…` / `pr/…`: Labels that are specific to issues or PRs respectively and that are only necessary in a given context, i.e. `issue/not-a-bug` or `pr/need-2-approvals`
Every PR should be labeled correctly with every label that applies.
There are also some labels that will be managed automatically.\
In particular, these are
- the amount of pending required approvals
- has all `backport`s or needs a manual backport
### Breaking PRs ### Breaking PRs
#### What is a breaking PR? #### What is a breaking PR?
@@ -239,29 +287,165 @@ Breaking PRs will not be merged as long as not both of these requirements are me
### Maintaining open PRs ### Maintaining open PRs
Code review starts when you open a non-draft PR or move a draft out of draft state. After that, do not rebase or squash your branch; it makes new changes harder to review. The moment you create a non-draft PR or the moment you convert a draft PR to a non-draft PR is the moment code review starts for it. \
Once that happens, do not rebase or squash your branch anymore as it makes it difficult to review the new changes. \
Merge the base branch into your branch only when you really need to, i.e. because of conflicting changes in the mean time. \
This reduces unnecessary CI runs. \
Don't worry about merge commits messing up your commit history as every PR will be squash merged. \
This means that all changes are joined into a single new commit whose message is as described below.
Merge the base branch into yours only when you need to, for example because of conflicting changes elsewhere. That limits unnecessary CI runs. ### Getting PRs merged
Every PR is squash-merged, so merge commits on your branch do not matter for final history. The squash produces a single commit; mergers follow the [commit message format](docs/community-governance.md#commit-messages) in the governance guide. Changes to Gitea must be reviewed before they are accepted — no matter who
makes the change, even if they are an owner or a maintainer. \
The only exception are critical bugs that prevent Gitea from being compiled or started. \
Specifically, we require two approvals from maintainers for every PR. \
Once this criteria has been met, your PR receives the `lgtm/done` label. \
From this point on, your only responsibility is to fix merge conflicts or respond to/implement requests by maintainers. \
It is the responsibility of the maintainers from this point to get your PR merged.
### Reviewing PRs If a PR has the `lgtm/done` label and there are no open discussions or merge conflicts anymore, any maintainer can add the `reviewed/wait-merge` label. \
This label means that the PR is part of the merge queue and will be merged as soon as possible. \
The merge queue will be cleared in the order of the list below:
Maintainers are encouraged to review pull requests in areas where they have expertise or particular interest. <https://github.com/go-gitea/gitea/pulls?q=is%3Apr+label%3Areviewed%2Fwait-merge+sort%3Acreated-asc+is%3Aopen>
#### For PR authors Gitea uses it's own tool, the <https://github.com/GiteaBot/gitea-backporter> to automate parts of the review process. \
This tool does the things listed below automatically:
- **Response**: When answering reviewer questions, use real-world cases or examples and avoid speculation. - create a backport PR if needed once the initial PR was merged
- **Discussion**: A discussion is always welcome and should be used to clarify the changes and the intent of the PR. - remove the PR from the merge queue after the PR merged
- **Help**: If you need help with the PR or comments are unclear, ask for clarification. - keep the oldest branch in the merge queue up to date with merges
Guidance for reviewers, the merge queue, and the squash commit message format is in [docs/community-governance.md](docs/community-governance.md). ### Final call
If a PR has been ignored for more than 7 days with no comments or reviews, and the author or any maintainer believes it will not survive a long wait (such as a refactoring PR), they can send "final call" to the TOC by mentioning them in a comment.
After another 7 days, if there is still zero approval, this is considered a polite refusal, and the PR will be closed to avoid wasting further time. Therefore, the "final call" has a cost, and should be used cautiously.
However, if there are no objections from maintainers, the PR can be merged with only one approval from the TOC (not the author).
### Commit messages
Mergers are able and required to rewrite the PR title and summary (the first comment of a PR) so that it can produce an easily understandable commit message if necessary. \
The final commit message should no longer contain any uncertainty such as `hopefully, <x> won't happen anymore`. Replace uncertainty with certainty.
#### PR Co-authors
A person counts as a PR co-author the moment they (co-)authored a commit that is not simply a `Merge base branch into branch` commit. \
Mergers are required to remove such "false-positive" co-authors when writing the commit message. \
The true co-authors must remain in the commit message.
#### PRs targeting `main`
The commit message of PRs targeting `main` is always
```bash
$PR_TITLE ($PR_INDEX)
$REWRITTEN_PR_SUMMARY
```
#### Backport PRs
The commit message of backport PRs is always
```bash
$PR_TITLE ($INITIAL_PR_INDEX) ($BACKPORT_PR_INDEX)
$REWRITTEN_PR_SUMMARY
```
## Documentation ## Documentation
If you add a new feature or change an existing aspect of Gitea, the documentation for that feature must be created or updated in another PR at [https://gitea.com/gitea/docs](https://gitea.com/gitea/docs). If you add a new feature or change an existing aspect of Gitea, the documentation for that feature must be created or updated in another PR at [https://gitea.com/gitea/docs](https://gitea.com/gitea/docs).
**The docs directory on main repository will be removed at some time. We will have a yaml file to store configuration file's meta data. After that completed, configuration documentation should be in the main repository.** **The docs directory on main repository will be removed at some time. We will have a yaml file to store configuration file's meta data. After that completed, configuration documentation should be in the main repository.**
## API v1
The API is documented by [swagger](https://gitea.com/api/swagger) and is based on [the GitHub API](https://docs.github.com/en/rest).
### GitHub API compatibility
Gitea's API should use the same endpoints and fields as the GitHub API as far as possible, unless there are good reasons to deviate. \
If Gitea provides functionality that GitHub does not, a new endpoint can be created. \
If information is provided by Gitea that is not provided by the GitHub API, a new field can be used that doesn't collide with any GitHub fields. \
Updating an existing API should not remove existing fields unless there is a really good reason to do so. \
The same applies to status responses. If you notice a problem, feel free to leave a comment in the code for future refactoring to API v2 (which is currently not planned).
### Adding/Maintaining API routes
All expected results (errors, success, fail messages) must be documented ([example](https://github.com/go-gitea/gitea/blob/c620eb5b2d0d874da68ebd734d3864c5224f71f7/routers/api/v1/repo/issue.go#L319-L327)). \
All JSON input types must be defined as a struct in [modules/structs/](modules/structs/) ([example](https://github.com/go-gitea/gitea/blob/c620eb5b2d0d874da68ebd734d3864c5224f71f7/modules/structs/issue.go#L76-L91)) \
and referenced in [routers/api/v1/swagger/options.go](https://github.com/go-gitea/gitea/blob/c620eb5b2d0d874da68ebd734d3864c5224f71f7/routers/api/v1/swagger/options.go). \
They can then be used like [this example](https://github.com/go-gitea/gitea/blob/c620eb5b2d0d874da68ebd734d3864c5224f71f7/routers/api/v1/repo/issue.go#L318). \
All JSON responses must be defined as a struct in [modules/structs/](modules/structs/) ([example](https://github.com/go-gitea/gitea/blob/c620eb5b2d0d874da68ebd734d3864c5224f71f7/modules/structs/issue.go#L36-L68)) \
and referenced in its category in [routers/api/v1/swagger/](routers/api/v1/swagger/) ([example](https://github.com/go-gitea/gitea/blob/c620eb5b2d0d874da68ebd734d3864c5224f71f7/routers/api/v1/swagger/issue.go#L11-L16)) \
They can be used like [this example](https://github.com/go-gitea/gitea/blob/c620eb5b2d0d874da68ebd734d3864c5224f71f7/routers/api/v1/repo/issue.go#L277-L279).
### When to use what HTTP method
In general, HTTP methods are chosen as follows:
- **GET** endpoints return the requested object(s) and status **OK (200)**
- **DELETE** endpoints return the status **No Content (204)** and no content either
- **POST** endpoints are used to **create** new objects (e.g. a User) and return the status **Created (201)** and the created object
- **PUT** endpoints are used to **add/assign** existing Objects (e.g. a user to a team) and return the status **No Content (204)** and no content either
- **PATCH** endpoints are used to **edit/change** an existing object and return the changed object and the status **OK (200)**
### Requirements for API routes
All parameters of endpoints changing/editing an object must be optional (except the ones to identify the object, which are required).
Endpoints returning lists must
- support pagination (`page` & `limit` options in query)
- set `X-Total-Count` header via **SetTotalCountHeader** ([example](https://github.com/go-gitea/gitea/blob/7aae98cc5d4113f1e9918b7ee7dd09f67c189e3e/routers/api/v1/repo/issue.go#L444))
## Backports and Frontports
### What is backported?
We backport PRs given the following circumstances:
1. Feature freeze is active, but `<version>-rc0` has not been released yet. Here, we backport as much as possible. <!-- TODO: Is that our definition with the new backport bot? -->
2. `rc0` has been released. Here, we only backport bug- and security-fixes, and small enhancements. Large PRs such as refactors are not backported anymore. <!-- TODO: Is that our definition with the new backport bot? -->
3. We never backport new features.
4. We never backport breaking changes except when
1. The breaking change has no effect on the vast majority of users
2. The component triggering the breaking change is marked as experimental
### How to backport?
In the past, it was necessary to manually backport your PRs. \
Now, that's not a requirement anymore as our [backport bot](https://github.com/GiteaBot) tries to create backports automatically once the PR is merged when the PR
- does not have the label `backport/manual`
- has the label `backport/<version>`
The `backport/manual` label signifies either that you want to backport the change yourself, or that there were conflicts when backporting, thus you **must** do it yourself.
### Format of backport PRs
The title of backport PRs should be
```
<original PR title> (#<original pr number>)
```
The first two lines of the summary of the backporting PR should be
```
Backport #<original pr number>
```
with the rest of the summary and labels matching the original PR.
### Frontports
Frontports behave exactly as described above for backports.
## Developer Certificate of Origin (DCO) ## Developer Certificate of Origin (DCO)
We consider the act of contributing to the code by submitting a Pull Request as the "Sign off" or agreement to the certifications and terms of the [DCO](DCO) and [MIT license](LICENSE). \ We consider the act of contributing to the code by submitting a Pull Request as the "Sign off" or agreement to the certifications and terms of the [DCO](DCO) and [MIT license](LICENSE). \
@@ -275,3 +459,148 @@ Signed-off-by: Joe Smith <joe.smith@email.com>
If you set the `user.name` and `user.email` Git config options, you can add the line to the end of your commits automatically with `git commit -s`. If you set the `user.name` and `user.email` Git config options, you can add the line to the end of your commits automatically with `git commit -s`.
We assume in good faith that the information you provide is legally binding. We assume in good faith that the information you provide is legally binding.
## Release Cycle
We adopted a release schedule to streamline the process of working on, finishing, and issuing releases. \
The overall goal is to make a major release every three or four months, which breaks down into two or three months of general development followed by one month of testing and polishing known as the release freeze. \
All the feature pull requests should be
merged before feature freeze. All feature pull requests haven't been merged before this feature freeze will be moved to next milestone, please notice our feature freeze announcement on discord. And, during the frozen period, a corresponding
release branch is open for fixes backported from main branch. Release candidates
are made during this period for user testing to
obtain a final version that is maintained in this branch.
During a development cycle, we may also publish any necessary minor releases
for the previous version. For example, if the latest, published release is
v1.2, then minor changes for the previous release—e.g., v1.1.0 -> v1.1.1—are
still possible.
## Maintainers
To make sure every PR is checked, we have [maintainers](MAINTAINERS). \
Every PR **must** be reviewed by at least two maintainers (or owners) before it can get merged. \
For refactoring PRs after a week and documentation only PRs, the approval of only one maintainer is enough. \
A maintainer should be a contributor of Gitea and contributed at least
4 accepted PRs. A contributor should apply as a maintainer in the
[Discord](https://discord.gg/Gitea) `#develop` channel. The team maintainers may invite the contributor. A maintainer
should spend some time on code reviews. If a maintainer has no
time to do that, they should apply to leave the maintainers team
and we will give them the honor of being a member of the [advisors
team](https://github.com/orgs/go-gitea/teams/advisors). Of course, if
an advisor has time to code review, we will gladly welcome them back
to the maintainers team. If a maintainer is inactive for more than 3
months and forgets to leave the maintainers team, the owners may move
him or her from the maintainers team to the advisors team.
For security reasons, Maintainers should use 2FA for their accounts and
if possible provide GPG signed commits.
https://help.github.com/articles/securing-your-account-with-two-factor-authentication-2fa/
https://help.github.com/articles/signing-commits-with-gpg/
Furthermore, any account with write access (like bots and TOC members) **must** use 2FA.
https://help.github.com/articles/securing-your-account-with-two-factor-authentication-2fa/
## Technical Oversight Committee (TOC)
At the start of 2023, the `Owners` team was dissolved. Instead, the governance charter proposed a technical oversight committee (TOC) which expands the ownership team of the Gitea project from three elected positions to six positions. Three positions are elected as it has been over the past years, and the other three consist of appointed members from the Gitea company.
https://blog.gitea.com/quarterly-23q1/
### TOC election process
Any maintainer is eligible to be part of the community TOC if they are not associated with the Gitea company.
A maintainer can either nominate themselves, or can be nominated by other maintainers to be a candidate for the TOC election.
If you are nominated by someone else, you must first accept your nomination before the vote starts to be a candidate.
The TOC is elected for one year, the TOC election happens yearly.
After the announcement of the results of the TOC election, elected members have two weeks time to confirm or refuse the seat.
If an elected member does not answer within this timeframe, they are automatically assumed to refuse the seat.
Refusals result in the person with the next highest vote getting the same choice.
As long as seats are empty in the TOC, members of the previous TOC can fill them until an elected member accepts the seat.
If an elected member that accepts the seat does not have 2FA configured yet, they will be temporarily counted as `answer pending` until they manage to configure 2FA, thus leaving their seat empty for this duration.
### Current TOC members
- 2024-01-01 ~ 2024-12-31
- Company
- [Jason Song](https://gitea.com/wolfogre) <i@wolfogre.com>
- [Lunny Xiao](https://gitea.com/lunny) <xiaolunwen@gmail.com>
- [Matti Ranta](https://gitea.com/techknowlogick) <techknowlogick@gitea.com>
- Community
- [6543](https://gitea.com/6543) <6543@obermui.de>
- [delvh](https://gitea.com/delvh) <dev.lh@web.de>
- [John Olheiser](https://gitea.com/jolheiser) <john.olheiser@gmail.com>
### Previous TOC/owners members
Here's the history of the owners and the time they served:
- [Lunny Xiao](https://gitea.com/lunny) - 2016, 2017, [2018](https://github.com/go-gitea/gitea/issues/3255), [2019](https://github.com/go-gitea/gitea/issues/5572), [2020](https://github.com/go-gitea/gitea/issues/9230), [2021](https://github.com/go-gitea/gitea/issues/13801), [2022](https://github.com/go-gitea/gitea/issues/17872), 2023
- [Kim Carlbäcker](https://github.com/bkcsoft) - 2016, 2017
- [Thomas Boerger](https://gitea.com/tboerger) - 2016, 2017
- [Lauris Bukšis-Haberkorns](https://gitea.com/lafriks) - [2018](https://github.com/go-gitea/gitea/issues/3255), [2019](https://github.com/go-gitea/gitea/issues/5572), [2020](https://github.com/go-gitea/gitea/issues/9230), [2021](https://github.com/go-gitea/gitea/issues/13801)
- [Matti Ranta](https://gitea.com/techknowlogick) - [2019](https://github.com/go-gitea/gitea/issues/5572), [2020](https://github.com/go-gitea/gitea/issues/9230), [2021](https://github.com/go-gitea/gitea/issues/13801), [2022](https://github.com/go-gitea/gitea/issues/17872), 2023
- [Andrew Thornton](https://gitea.com/zeripath) - [2020](https://github.com/go-gitea/gitea/issues/9230), [2021](https://github.com/go-gitea/gitea/issues/13801), [2022](https://github.com/go-gitea/gitea/issues/17872), 2023
- [6543](https://gitea.com/6543) - 2023
- [John Olheiser](https://gitea.com/jolheiser) - 2023
- [Jason Song](https://gitea.com/wolfogre) - 2023
## Governance Compensation
Each member of the community elected TOC will be granted $500 each month as compensation for their work.
Furthermore, any community release manager for a specific release or LTS will be compensated $500 for the delivery of said release.
These funds will come from community sources like the OpenCollective rather than directly from the company.
Only non-company members are eligible for this compensation, and if a member of the community TOC takes the responsibility of release manager, they would only be compensated for their TOC duties.
Gitea Ltd employees are not eligible to receive any funds from the OpenCollective unless it is reimbursement for a purchase made for the Gitea project itself.
## TOC & Working groups
With Gitea covering many projects outside of the main repository, several groups will be created to help focus on specific areas instead of requiring maintainers to be a jack-of-all-trades. Maintainers are of course more than welcome to be part of multiple groups should they wish to contribute in multiple places.
The currently proposed groups are:
- **Core Group**: maintain the primary Gitea repository
- **Integration Group**: maintain the Gitea ecosystem's related tools, including go-sdk/tea/changelog/bots etc.
- **Documentation Group**: maintain related documents and repositories
- **Translation Group**: coordinate with translators and maintain translations
- **Security Group**: managed by TOC directly, members are decided by TOC, maintains security patches/responsible for security items
## Roadmap
Each year a roadmap will be discussed with the entire Gitea maintainers team, and feedback will be solicited from various stakeholders.
TOC members need to review the roadmap every year and work together on the direction of the project.
When a vote is required for a proposal or other change, the vote of community elected TOC members count slightly more than the vote of company elected TOC members. With this approach, we both avoid ties and ensure that changes align with the mission statement and community opinion.
You can visit our roadmap on the wiki.
## Versions
Gitea has the `main` branch as a tip branch and has version branches
such as `release/v1.19`. `release/v1.19` is a release branch and we will
tag `v1.19.0` for binary download. If `v1.19.0` has bugs, we will accept
pull requests on the `release/v1.19` branch and publish a `v1.19.1` tag,
after bringing the bug fix also to the main branch.
Since the `main` branch is a tip version, if you wish to use Gitea
in production, please download the latest release tag version. All the
branches will be protected via GitHub, all the PRs to every branch must
be reviewed by two maintainers and must pass the automatic tests.
## Releasing Gitea
- Let $vmaj, $vmin and $vpat be Major, Minor and Patch version numbers, $vpat should be rc1, rc2, 0, 1, ...... $vmaj.$vmin will be kept the same as milestones on github or gitea in future.
- Before releasing, confirm all the version's milestone issues or PRs has been resolved. Then discuss the release on Discord channel #maintainers and get agreed with almost all the owners and mergers. Or you can declare the version and if nobody is against it in about several hours.
- If this is a big version first you have to create PR for changelog on branch `main` with PRs with label `changelog` and after it has been merged do following steps:
- Create `-dev` tag as `git tag -s -F release.notes v$vmaj.$vmin.0-dev` and push the tag as `git push origin v$vmaj.$vmin.0-dev`.
- When CI has finished building tag then you have to create a new branch named `release/v$vmaj.$vmin`
- If it is bugfix version create PR for changelog on branch `release/v$vmaj.$vmin` and wait till it is reviewed and merged.
- Add a tag as `git tag -s -F release.notes v$vmaj.$vmin.$`, release.notes file could be a temporary file to only include the changelog this version which you added to `CHANGELOG.md`.
- And then push the tag as `git push origin v$vmaj.$vmin.$`. Drone CI will automatically create a release and upload all the compiled binary. (But currently it doesn't add the release notes automatically. Maybe we should fix that.)
- If needed send a frontport PR for the changelog to branch `main` and update the version in `docs/config.yaml` to refer to the new version.
- Send PR to [blog repository](https://gitea.com/gitea/blog) announcing the release.
- Verify all release assets were correctly published through CI on dl.gitea.com and GitHub releases. Once ACKed:
- bump the version of https://dl.gitea.com/gitea/version.json
- merge the blog post PR
- announce the release in discord `#announcements`

View File

@@ -1,15 +1,8 @@
# syntax=docker/dockerfile:1 # Build stage
# Build frontend on the native platform to avoid QEMU-related issues with nodejs ecosystem FROM docker.io/library/golang:1.25-alpine3.22 AS build-env
FROM --platform=$BUILDPLATFORM docker.io/library/golang:1.26-alpine3.23 AS frontend-build
RUN apk --no-cache add build-base git nodejs pnpm
WORKDIR /src
COPY package.json pnpm-lock.yaml .npmrc ./
RUN --mount=type=cache,target=/root/.local/share/pnpm/store pnpm install --frozen-lockfile
COPY --exclude=.git/ . .
RUN make frontend
# Build backend for each target platform ARG GOPROXY
FROM docker.io/library/golang:1.26-alpine3.23 AS build-env ENV GOPROXY=${GOPROXY:-direct}
ARG GITEA_VERSION ARG GITEA_VERSION
ARG TAGS="sqlite sqlite_unlock_notify" ARG TAGS="sqlite sqlite_unlock_notify"
@@ -19,32 +12,37 @@ ARG CGO_EXTRA_CFLAGS
# Build deps # Build deps
RUN apk --no-cache add \ RUN apk --no-cache add \
build-base \ build-base \
git git \
nodejs \
npm \
&& npm install -g pnpm@10 \
&& rm -rf /var/cache/apk/*
# Setup repo
COPY . ${GOPATH}/src/code.gitea.io/gitea
WORKDIR ${GOPATH}/src/code.gitea.io/gitea WORKDIR ${GOPATH}/src/code.gitea.io/gitea
COPY go.mod go.sum ./
RUN go mod download
# Use COPY instead of bind mount as read-only one breaks makefile state tracking and read-write one needs binary to be moved as it's discarded.
# ".git" directory is mounted separately later only for version data extraction.
COPY --exclude=.git/ . .
COPY --from=frontend-build /src/public/assets public/assets
# Build gitea, .git mount is required for version data # Checkout version if set
RUN --mount=type=cache,target="/root/.cache/go-build" \ RUN if [ -n "${GITEA_VERSION}" ]; then git checkout "${GITEA_VERSION}"; fi \
--mount=type=bind,source=".git/",target=".git/" \ && make clean-all build
make backend
# Begin env-to-ini build
RUN go build contrib/environment-to-ini/environment-to-ini.go
# Copy local files
COPY docker/root /tmp/local COPY docker/root /tmp/local
# Set permissions for builds that made under windows which strips the executable bit from file # Set permissions
RUN chmod 755 /tmp/local/usr/bin/entrypoint \ RUN chmod 755 /tmp/local/usr/bin/entrypoint \
/tmp/local/usr/local/bin/* \ /tmp/local/usr/local/bin/gitea \
/tmp/local/etc/s6/gitea/* \ /tmp/local/etc/s6/gitea/* \
/tmp/local/etc/s6/openssh/* \ /tmp/local/etc/s6/openssh/* \
/tmp/local/etc/s6/.s6-svscan/* \ /tmp/local/etc/s6/.s6-svscan/* \
/go/src/code.gitea.io/gitea/gitea /go/src/code.gitea.io/gitea/gitea \
/go/src/code.gitea.io/gitea/environment-to-ini
FROM docker.io/library/alpine:3.23 AS gitea FROM docker.io/library/alpine:3.22
LABEL maintainer="maintainers@gitea.io"
EXPOSE 22 3000 EXPOSE 22 3000
@@ -59,7 +57,8 @@ RUN apk --no-cache add \
s6 \ s6 \
sqlite \ sqlite \
su-exec \ su-exec \
gnupg gnupg \
&& rm -rf /var/cache/apk/*
RUN addgroup \ RUN addgroup \
-S -g 1000 \ -S -g 1000 \
@@ -73,14 +72,14 @@ RUN addgroup \
git && \ git && \
echo "git:*" | chpasswd -e echo "git:*" | chpasswd -e
COPY --from=build-env /tmp/local /
COPY --from=build-env /go/src/code.gitea.io/gitea/gitea /app/gitea/gitea
ENV USER=git ENV USER=git
ENV GITEA_CUSTOM=/data/gitea ENV GITEA_CUSTOM=/data/gitea
VOLUME ["/data"] VOLUME ["/data"]
# HINT: HEALTH-CHECK-ENDPOINT: don't use HEALTHCHECK, search this hint keyword for more information
ENTRYPOINT ["/usr/bin/entrypoint"] ENTRYPOINT ["/usr/bin/entrypoint"]
CMD ["/usr/bin/s6-svscan", "/etc/s6"] CMD ["/usr/bin/s6-svscan", "/etc/s6"]
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/environment-to-ini /usr/local/bin/environment-to-ini

View File

@@ -1,45 +1,46 @@
# syntax=docker/dockerfile:1 # Build stage
# Build frontend on the native platform to avoid QEMU-related issues with nodejs ecosystem FROM docker.io/library/golang:1.25-alpine3.22 AS build-env
FROM --platform=$BUILDPLATFORM docker.io/library/golang:1.26-alpine3.23 AS frontend-build
RUN apk --no-cache add build-base git nodejs pnpm
WORKDIR /src
COPY package.json pnpm-lock.yaml .npmrc ./
RUN --mount=type=cache,target=/root/.local/share/pnpm/store pnpm install --frozen-lockfile
COPY --exclude=.git/ . .
RUN make frontend
# Build backend for each target platform ARG GOPROXY
FROM docker.io/library/golang:1.26-alpine3.23 AS build-env ENV GOPROXY=${GOPROXY:-direct}
ARG GITEA_VERSION ARG GITEA_VERSION
ARG TAGS="sqlite sqlite_unlock_notify" ARG TAGS="sqlite sqlite_unlock_notify"
ENV TAGS="bindata timetzdata $TAGS" ENV TAGS="bindata timetzdata $TAGS"
ARG CGO_EXTRA_CFLAGS ARG CGO_EXTRA_CFLAGS
# Build deps #Build deps
RUN apk --no-cache add \ RUN apk --no-cache add \
build-base \ build-base \
git git \
nodejs \
npm \
&& npm install -g pnpm@10 \
&& rm -rf /var/cache/apk/*
# Setup repo
COPY . ${GOPATH}/src/code.gitea.io/gitea
WORKDIR ${GOPATH}/src/code.gitea.io/gitea WORKDIR ${GOPATH}/src/code.gitea.io/gitea
COPY go.mod go.sum ./
RUN go mod download
# See the comments in Dockerfile
COPY --exclude=.git/ . .
COPY --from=frontend-build /src/public/assets public/assets
# Build gitea, .git mount is required for version data # Checkout version if set
RUN --mount=type=cache,target="/root/.cache/go-build" \ RUN if [ -n "${GITEA_VERSION}" ]; then git checkout "${GITEA_VERSION}"; fi \
--mount=type=bind,source=".git/",target=".git/" \ && make clean-all build
make backend
# Begin env-to-ini build
RUN go build contrib/environment-to-ini/environment-to-ini.go
# Copy local files
COPY docker/rootless /tmp/local COPY docker/rootless /tmp/local
# Set permissions for builds that made under windows which strips the executable bit from file # Set permissions
RUN chmod 755 /tmp/local/usr/local/bin/* \ RUN chmod 755 /tmp/local/usr/local/bin/docker-entrypoint.sh \
/go/src/code.gitea.io/gitea/gitea /tmp/local/usr/local/bin/docker-setup.sh \
/tmp/local/usr/local/bin/gitea \
/go/src/code.gitea.io/gitea/gitea \
/go/src/code.gitea.io/gitea/environment-to-ini
FROM docker.io/library/alpine:3.23 AS gitea-rootless FROM docker.io/library/alpine:3.22
LABEL maintainer="maintainers@gitea.io"
EXPOSE 2222 3000 EXPOSE 2222 3000
@@ -51,7 +52,8 @@ RUN apk --no-cache add \
git \ git \
curl \ curl \
gnupg \ gnupg \
openssh-keygen openssh-keygen \
&& rm -rf /var/cache/apk/*
RUN addgroup \ RUN addgroup \
-S -g 1000 \ -S -g 1000 \
@@ -69,6 +71,7 @@ RUN chown git:git /var/lib/gitea /etc/gitea
COPY --from=build-env /tmp/local / COPY --from=build-env /tmp/local /
COPY --from=build-env --chown=root:root /go/src/code.gitea.io/gitea/gitea /app/gitea/gitea COPY --from=build-env --chown=root:root /go/src/code.gitea.io/gitea/gitea /app/gitea/gitea
COPY --from=build-env --chown=root:root /go/src/code.gitea.io/gitea/environment-to-ini /usr/local/bin/environment-to-ini
# git:git # git:git
USER 1000:1000 USER 1000:1000
@@ -83,6 +86,5 @@ ENV HOME="/var/lib/gitea/git"
VOLUME ["/var/lib/gitea", "/etc/gitea"] VOLUME ["/var/lib/gitea", "/etc/gitea"]
WORKDIR /var/lib/gitea WORKDIR /var/lib/gitea
# HINT: HEALTH-CHECK-ENDPOINT: don't use HEALTHCHECK, search this hint keyword for more information
ENTRYPOINT ["/usr/bin/dumb-init", "--", "/usr/local/bin/docker-entrypoint.sh"] ENTRYPOINT ["/usr/bin/dumb-init", "--", "/usr/local/bin/docker-entrypoint.sh"]
CMD [] CMD []

View File

@@ -64,4 +64,3 @@ metiftikci <metiftikci@hotmail.com> (@metiftikci)
Christopher Homberger <christopher.homberger@web.de> (@ChristopherHX) Christopher Homberger <christopher.homberger@web.de> (@ChristopherHX)
Tobias Balle-Petersen <tobiasbp@gmail.com> (@tobiasbp) Tobias Balle-Petersen <tobiasbp@gmail.com> (@tobiasbp)
TheFox <thefox0x7@gmail.com> (@TheFox0x7) TheFox <thefox0x7@gmail.com> (@TheFox0x7)
Nicolas <bircni@icloud.com> (@bircni)

388
Makefile
View File

@@ -1,9 +1,22 @@
ifeq ($(USE_REPO_TEST_DIR),1)
# This rule replaces the whole Makefile when we're trying to use /tmp repository temporary files
location = $(CURDIR)/$(word $(words $(MAKEFILE_LIST)),$(MAKEFILE_LIST))
self := $(location)
%:
@tmpdir=`mktemp --tmpdir -d` ; \
echo Using temporary directory $$tmpdir for test repositories ; \
USE_REPO_TEST_DIR= $(MAKE) -f $(self) --no-print-directory REPO_TEST_DIR=$$tmpdir/ $@ ; \
STATUS=$$? ; rm -r "$$tmpdir" ; exit $$STATUS
else
# This is the "normal" part of the Makefile
DIST := dist DIST := dist
DIST_DIRS := $(DIST)/binaries $(DIST)/release DIST_DIRS := $(DIST)/binaries $(DIST)/release
IMPORT := code.gitea.io/gitea
# By default use go's 1.25 experimental json v2 library when building
# TODO: remove when no longer experimental
export GOEXPERIMENT ?= jsonv2
GO ?= go GO ?= go
SHASUM ?= shasum -a 256 SHASUM ?= shasum -a 256
@@ -14,13 +27,17 @@ XGO_VERSION := go-1.25.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/v3/cmd/editorconfig-checker@v3 EDITORCONFIG_CHECKER_PACKAGE ?= github.com/editorconfig-checker/editorconfig-checker/v3/cmd/editorconfig-checker@v3
GOLANGCI_LINT_PACKAGE ?= github.com/golangci/golangci-lint/v2/cmd/golangci-lint@v2.11.4 GOFUMPT_PACKAGE ?= mvdan.cc/gofumpt@v0.9.1
GOLANGCI_LINT_PACKAGE ?= github.com/golangci/golangci-lint/v2/cmd/golangci-lint@v2.4.0
GXZ_PACKAGE ?= github.com/ulikunitz/xz/cmd/gxz@v0.5.15 GXZ_PACKAGE ?= github.com/ulikunitz/xz/cmd/gxz@v0.5.15
MISSPELL_PACKAGE ?= github.com/golangci/misspell/cmd/misspell@v0.8.0 MISSPELL_PACKAGE ?= github.com/golangci/misspell/cmd/misspell@v0.7.0
SWAGGER_PACKAGE ?= github.com/go-swagger/go-swagger/cmd/swagger@v0.33.1 SWAGGER_PACKAGE ?= github.com/go-swagger/go-swagger/cmd/swagger@717e3cb29becaaf00e56953556c6d80f8a01b286
XGO_PACKAGE ?= src.techknowlogick.com/xgo@latest XGO_PACKAGE ?= src.techknowlogick.com/xgo@latest
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.7.11 ACTIONLINT_PACKAGE ?= github.com/rhysd/actionlint/cmd/actionlint@v1
GOPLS_PACKAGE ?= golang.org/x/tools/gopls@v0.20.0
GOPLS_MODERNIZE_PACKAGE ?= golang.org/x/tools/gopls/internal/analysis/modernize/cmd/modernize@v0.20.0
DOCKER_IMAGE ?= gitea/gitea DOCKER_IMAGE ?= gitea/gitea
DOCKER_TAG ?= latest DOCKER_TAG ?= latest
@@ -52,11 +69,9 @@ endif
ifeq ($(IS_WINDOWS),yes) ifeq ($(IS_WINDOWS),yes)
GOFLAGS := -v -buildmode=exe GOFLAGS := -v -buildmode=exe
EXECUTABLE ?= gitea.exe EXECUTABLE ?= gitea.exe
EXECUTABLE_E2E ?= gitea-e2e.exe
else else
GOFLAGS := -v GOFLAGS := -v
EXECUTABLE ?= gitea EXECUTABLE ?= gitea
EXECUTABLE_E2E ?= gitea-e2e
endif endif
ifeq ($(shell sed --version 2>/dev/null | grep -q GNU && echo gnu),gnu) ifeq ($(shell sed --version 2>/dev/null | grep -q GNU && echo gnu),gnu)
@@ -67,6 +82,7 @@ endif
EXTRA_GOFLAGS ?= EXTRA_GOFLAGS ?=
MAKE_VERSION := $(shell "$(MAKE)" -v | cat | head -n 1)
MAKE_EVIDENCE_DIR := .make_evidence MAKE_EVIDENCE_DIR := .make_evidence
GOTESTFLAGS ?= GOTESTFLAGS ?=
@@ -80,6 +96,15 @@ STORED_VERSION_FILE := VERSION
GITHUB_REF_TYPE ?= branch GITHUB_REF_TYPE ?= branch
GITHUB_REF_NAME ?= $(shell git rev-parse --abbrev-ref HEAD) GITHUB_REF_NAME ?= $(shell git rev-parse --abbrev-ref HEAD)
# Enable typescript support in Node.js before 22.18
# TODO: Remove this once we can raise the minimum Node.js version to 22.18 (alpine >= 3.23)
NODE_VERSION := $(shell printf "%03d%03d%03d" $(shell node -v 2>/dev/null | cut -c2- | tr '.' ' '))
ifeq ($(shell test "$(NODE_VERSION)" -lt "022018000"; echo $$?),0)
NODE_VARS := NODE_OPTIONS="--experimental-strip-types"
else
NODE_VARS :=
endif
ifneq ($(GITHUB_REF_TYPE),branch) ifneq ($(GITHUB_REF_TYPE),branch)
VERSION ?= $(subst v,,$(GITHUB_REF_NAME)) VERSION ?= $(subst v,,$(GITHUB_REF_NAME))
GITEA_VERSION ?= $(VERSION) GITEA_VERSION ?= $(VERSION)
@@ -103,18 +128,17 @@ ifeq ($(VERSION),main)
VERSION := main-nightly VERSION := main-nightly
endif endif
LDFLAGS := $(LDFLAGS) -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/riscv64 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,$(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/...)
FRONTEND_SOURCES := $(shell find web_src/js web_src/css -type f) WEBPACK_SOURCES := $(shell find web_src/js web_src/css -type f)
FRONTEND_CONFIGS := vite.config.ts tailwind.config.ts WEBPACK_CONFIGS := webpack.config.ts tailwind.config.ts
FRONTEND_DEST := public/assets/.vite/manifest.json WEBPACK_DEST := public/assets/js/index.js public/assets/css/index.css
FRONTEND_DEST_ENTRIES := public/assets/js public/assets/css public/assets/fonts public/assets/.vite WEBPACK_DEST_ENTRIES := public/assets/js public/assets/css public/assets/fonts
FRONTEND_DEV_LOG_LEVEL ?= warn
BINDATA_DEST_WILDCARD := modules/migration/bindata.* modules/public/bindata.* modules/options/bindata.* modules/templates/bindata.* BINDATA_DEST_WILDCARD := modules/migration/bindata.* modules/public/bindata.* modules/options/bindata.* modules/templates/bindata.*
@@ -124,6 +148,7 @@ SVG_DEST_DIR := public/assets/img/svg
AIR_TMP_DIR := .air AIR_TMP_DIR := .air
GO_LICENSE_TMP_DIR := .go-licenses
GO_LICENSE_FILE := assets/go-licenses.json GO_LICENSE_FILE := assets/go-licenses.json
TAGS ?= TAGS ?=
@@ -132,21 +157,24 @@ 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) $(DIST) $(MAKE_EVIDENCE_DIR) $(AIR_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 tools 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 *.ts tests/e2e ESLINT_FILES := web_src/js tools *.ts 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.json .github $(filter-out CHANGELOG.md, $(wildcard *.go *.md *.yml *.yaml *.toml)) SPELLCHECK_FILES := $(GO_DIRS) $(WEB_DIRS) templates options/locale/locale_en-US.ini .github $(filter-out CHANGELOG.md, $(wildcard *.go *.md *.yml *.yaml *.toml)) $(filter-out tools/misspellings.csv, $(wildcard tools/*))
EDITORCONFIG_FILES := templates .github/workflows options/locale/locale_en-US.json EDITORCONFIG_FILES := templates .github/workflows options/locale/locale_en-US.ini
GO_SOURCES := $(wildcard *.go) GO_SOURCES := $(wildcard *.go)
GO_SOURCES += $(shell find $(GO_DIRS) -type f -name "*.go") GO_SOURCES += $(shell find $(GO_DIRS) -type f -name "*.go")
GO_SOURCES += $(GENERATED_GO_DEST) GO_SOURCES += $(GENERATED_GO_DEST)
ESLINT_CONCURRENCY ?= 2 # Force installation of playwright dependencies by setting this flag
ifdef DEPS_PLAYWRIGHT
PLAYWRIGHT_FLAGS += --with-deps
endif
SWAGGER_SPEC := templates/swagger/v1_json.tmpl SWAGGER_SPEC := templates/swagger/v1_json.tmpl
SWAGGER_SPEC_INPUT := templates/swagger/v1_input.json SWAGGER_SPEC_INPUT := templates/swagger/v1_input.json
@@ -167,20 +195,26 @@ TEST_MSSQL_DBNAME ?= gitea
TEST_MSSQL_USERNAME ?= sa TEST_MSSQL_USERNAME ?= sa
TEST_MSSQL_PASSWORD ?= MwantsaSecurePassword1 TEST_MSSQL_PASSWORD ?= MwantsaSecurePassword1
# Include local Makefile
# Makefile.local is listed in .gitignore
sinclude Makefile.local
.PHONY: all .PHONY: all
all: build all: build
.PHONY: help .PHONY: help
help: Makefile ## print Makefile help information. help: Makefile ## print Makefile help information.
@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) @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)
@printf " \033[36m%-46s\033[0m %s\n" "test-e2e" "test end to end using playwright" @printf " \033[36m%-46s\033[0m %s\n" "test-e2e[#TestSpecificName]" "test end to end using playwright"
@printf " \033[36m%-46s\033[0m %s\n" "test[#TestSpecificName]" "run unit test" @printf " \033[36m%-46s\033[0m %s\n" "test[#TestSpecificName]" "run unit test"
@printf " \033[36m%-46s\033[0m %s\n" "test-sqlite[#TestSpecificName]" "run integration test for sqlite" @printf " \033[36m%-46s\033[0m %s\n" "test-sqlite[#TestSpecificName]" "run integration test for sqlite"
.PHONY: go-check
go-check:
$(eval MIN_GO_VERSION_STR := $(shell grep -Eo '^go\s+[0-9]+\.[0-9]+' go.mod | cut -d' ' -f2))
$(eval MIN_GO_VERSION := $(shell printf "%03d%03d" $(shell echo '$(MIN_GO_VERSION_STR)' | tr '.' ' ')))
$(eval GO_VERSION := $(shell printf "%03d%03d" $(shell $(GO) version | grep -Eo '[0-9]+\.[0-9]+' | tr '.' ' ');))
@if [ "$(GO_VERSION)" -lt "$(MIN_GO_VERSION)" ]; then \
echo "Gitea requires Go $(MIN_GO_VERSION_STR) or greater to build. You can get it at https://go.dev/dl/"; \
exit 1; \
fi
.PHONY: git-check .PHONY: git-check
git-check: git-check:
@if git lfs >/dev/null 2>&1 ; then : ; else \ @if git lfs >/dev/null 2>&1 ; then : ; else \
@@ -188,24 +222,39 @@ git-check:
exit 1; \ exit 1; \
fi fi
.PHONY: node-check
node-check:
$(eval MIN_NODE_VERSION_STR := $(shell grep -Eo '"node":.*[0-9.]+"' package.json | sed -n 's/.*[^0-9.]\([0-9.]*\)"/\1/p'))
$(eval MIN_NODE_VERSION := $(shell printf "%03d%03d%03d" $(shell echo '$(MIN_NODE_VERSION_STR)' | tr '.' ' ')))
$(eval PNPM_MISSING := $(shell hash pnpm > /dev/null 2>&1 || echo 1))
@if [ "$(NODE_VERSION)" -lt "$(MIN_NODE_VERSION)" ]; then \
echo "Gitea requires Node.js $(MIN_NODE_VERSION_STR) or greater to build. You can get it at https://nodejs.org/en/download/"; \
exit 1; \
fi
@if [ "$(PNPM_MISSING)" = "1" ]; then \
echo "Gitea requires pnpm to build. You can install it at https://pnpm.io/installation"; \
exit 1; \
fi
.PHONY: clean-all .PHONY: clean-all
clean-all: clean ## delete backend, frontend and integration files clean-all: clean ## delete backend, frontend and integration files
rm -rf $(FRONTEND_DEST_ENTRIES) node_modules rm -rf $(WEBPACK_DEST_ENTRIES) node_modules
.PHONY: clean .PHONY: clean
clean: ## delete backend and integration files clean: ## delete backend and integration files
rm -rf $(EXECUTABLE) $(EXECUTABLE_E2E) $(DIST) $(BINDATA_DEST_WILDCARD) \ rm -rf $(EXECUTABLE) $(DIST) $(BINDATA_DEST_WILDCARD) \
integrations*.test \ integrations*.test \
e2e*.test \
tests/integration/gitea-integration-* \ tests/integration/gitea-integration-* \
tests/integration/indexers-* \ tests/integration/indexers-* \
tests/sqlite.ini tests/mysql.ini tests/pgsql.ini tests/mssql.ini man/ \ tests/mysql.ini tests/pgsql.ini tests/mssql.ini man/ \
tests/e2e/gitea-e2e-*/ \ tests/e2e/gitea-e2e-*/ \
tests/e2e/indexers-*/ \ tests/e2e/indexers-*/ \
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: ## format the Go and template code fmt: ## format the Go and template code
$(GO) run $(GOLANGCI_LINT_PACKAGE) fmt @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
@# whitespace before it @# whitespace before it
@@ -223,6 +272,19 @@ fmt-check: fmt
exit 1; \ exit 1; \
fi fi
.PHONY: fix
fix: ## apply automated fixes to Go code
$(GO) run $(GOPLS_MODERNIZE_PACKAGE) -fix ./...
.PHONY: fix-check
fix-check: fix
@diff=$$(git diff --color=always $(GO_SOURCES)); \
if [ -n "$$diff" ]; then \
echo "Please run 'make fix' and commit the result:"; \
printf "%s" "$${diff}"; \
exit 1; \
fi
.PHONY: $(TAGS_EVIDENCE) .PHONY: $(TAGS_EVIDENCE)
$(TAGS_EVIDENCE): $(TAGS_EVIDENCE):
@mkdir -p $(MAKE_EVIDENCE_DIR) @mkdir -p $(MAKE_EVIDENCE_DIR)
@@ -262,7 +324,7 @@ checks: checks-frontend checks-backend ## run various consistency checks
checks-frontend: lockfile-check svg-check ## check frontend files 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 ## check backend files checks-backend: tidy-check swagger-check fmt-check fix-check swagger-validate security-check ## check backend files
.PHONY: lint .PHONY: lint
lint: lint-frontend lint-backend lint-spell ## lint everything lint: lint-frontend lint-backend lint-spell ## lint everything
@@ -277,48 +339,44 @@ lint-frontend: lint-js lint-css ## lint frontend files
lint-frontend-fix: lint-js-fix lint-css-fix ## lint frontend files and fix issues 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-editorconfig ## lint backend files 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-editorconfig ## lint backend files and fix issues 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 and ts files lint-js: node_modules ## lint js files
pnpm exec eslint --color --max-warnings=0 --concurrency $(ESLINT_CONCURRENCY) $(ESLINT_FILES) $(NODE_VARS) pnpm exec eslint --color --max-warnings=0 --flag unstable_native_nodejs_ts_config $(ESLINT_FILES)
pnpm exec vue-tsc $(NODE_VARS) pnpm exec vue-tsc
.PHONY: lint-js-fix .PHONY: lint-js-fix
lint-js-fix: node_modules ## lint js and ts files and fix issues lint-js-fix: node_modules ## lint js files and fix issues
pnpm exec eslint --color --max-warnings=0 --concurrency $(ESLINT_CONCURRENCY) $(ESLINT_FILES) --fix $(NODE_VARS) pnpm exec eslint --color --max-warnings=0 --flag unstable_native_nodejs_ts_config $(ESLINT_FILES) --fix
pnpm exec vue-tsc $(NODE_VARS) pnpm exec vue-tsc
.PHONY: lint-css .PHONY: lint-css
lint-css: node_modules ## lint css files lint-css: node_modules ## lint css files
pnpm exec stylelint --color --max-warnings=0 $(STYLELINT_FILES) $(NODE_VARS) pnpm exec stylelint --color --max-warnings=0 $(STYLELINT_FILES)
.PHONY: lint-css-fix .PHONY: lint-css-fix
lint-css-fix: node_modules ## lint css files and fix issues lint-css-fix: node_modules ## lint css files and fix issues
pnpm exec stylelint --color --max-warnings=0 $(STYLELINT_FILES) --fix $(NODE_VARS) pnpm exec stylelint --color --max-warnings=0 $(STYLELINT_FILES) --fix
.PHONY: lint-swagger .PHONY: lint-swagger
lint-swagger: node_modules ## lint swagger files lint-swagger: node_modules ## lint swagger files
pnpm exec spectral lint -q -F hint $(SWAGGER_SPEC) $(NODE_VARS) pnpm exec spectral lint -q -F hint $(SWAGGER_SPEC)
.PHONY: lint-md .PHONY: lint-md
lint-md: node_modules ## lint markdown files lint-md: node_modules ## lint markdown files
pnpm exec markdownlint *.md $(NODE_VARS) pnpm exec markdownlint *.md
.PHONY: lint-md-fix
lint-md-fix: node_modules ## lint markdown files and fix issues
pnpm exec markdownlint --fix *.md
.PHONY: lint-spell .PHONY: lint-spell
lint-spell: ## lint spelling lint-spell: ## lint spelling
@git ls-files $(SPELLCHECK_FILES) | xargs go run $(MISSPELL_PACKAGE) -dict assets/misspellings.csv -error @go run $(MISSPELL_PACKAGE) -dict tools/misspellings.csv -error $(SPELLCHECK_FILES)
.PHONY: lint-spell-fix .PHONY: lint-spell-fix
lint-spell-fix: ## lint spelling and fix issues lint-spell-fix: ## lint spelling and fix issues
@git ls-files $(SPELLCHECK_FILES) | xargs go run $(MISSPELL_PACKAGE) -dict assets/misspellings.csv -w @go run $(MISSPELL_PACKAGE) -dict tools/misspellings.csv -w $(SPELLCHECK_FILES)
.PHONY: lint-go .PHONY: lint-go
lint-go: ## lint go files lint-go: ## lint go files
@@ -335,6 +393,17 @@ 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-gitea-vet
lint-go-gitea-vet: ## lint go files with gitea-vet
@echo "Running gitea-vet..."
@GOOS= GOARCH= $(GO) build code.gitea.io/gitea-vet
@$(GO) vet -vettool=gitea-vet ./...
.PHONY: lint-go-gopls
lint-go-gopls: ## lint go files with gopls
@echo "Running gopls check..."
@GO=$(GO) GOPLS_PACKAGE=$(GOPLS_PACKAGE) tools/lint-go-gopls.sh $(GO_SOURCES)
.PHONY: lint-editorconfig .PHONY: lint-editorconfig
lint-editorconfig: lint-editorconfig:
@echo "Running editorconfig check..." @echo "Running editorconfig check..."
@@ -353,24 +422,17 @@ lint-templates: .venv node_modules ## lint template files
lint-yaml: .venv ## lint yaml files lint-yaml: .venv ## lint yaml files
@uv run --frozen yamllint -s . @uv run --frozen yamllint -s .
.PHONY: lint-json
lint-json: node_modules ## lint json files
pnpm exec eslint -c eslint.json.config.ts --color --max-warnings=0 --concurrency $(ESLINT_CONCURRENCY)
.PHONY: lint-json-fix
lint-json-fix: node_modules ## lint and fix json files
pnpm exec eslint -c eslint.json.config.ts --color --max-warnings=0 --concurrency $(ESLINT_CONCURRENCY) --fix
.PHONY: watch .PHONY: watch
watch: ## watch everything and continuously rebuild watch: ## watch everything and continuously rebuild
@bash tools/watch.sh @bash tools/watch.sh
.PHONY: watch-frontend .PHONY: watch-frontend
watch-frontend: node_modules ## start vite dev server for frontend watch-frontend: node-check node_modules ## watch frontend files and continuously rebuild
NODE_ENV=development pnpm exec vite --logLevel $(FRONTEND_DEV_LOG_LEVEL) @rm -rf $(WEBPACK_DEST_ENTRIES)
NODE_ENV=development $(NODE_VARS) pnpm exec webpack --watch --progress --disable-interpret
.PHONY: watch-backend .PHONY: watch-backend
watch-backend: ## watch backend files and continuously rebuild 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
@@ -383,7 +445,7 @@ test-backend: ## test backend files
.PHONY: test-frontend .PHONY: test-frontend
test-frontend: node_modules ## test frontend files test-frontend: node_modules ## test frontend files
pnpm exec vitest $(NODE_VARS) pnpm exec vitest
.PHONY: test-check .PHONY: test-check
test-check: test-check:
@@ -406,7 +468,7 @@ test\#%:
coverage: coverage:
grep '^\(mode: .*\)\|\(.*:[0-9]\+\.[0-9]\+,[0-9]\+\.[0-9]\+ [0-9]\+ [0-9]\+\)$$' coverage.out > coverage-bodged.out grep '^\(mode: .*\)\|\(.*:[0-9]\+\.[0-9]\+,[0-9]\+\.[0-9]\+ [0-9]\+ [0-9]\+\)$$' coverage.out > coverage-bodged.out
grep '^\(mode: .*\)\|\(.*:[0-9]\+\.[0-9]\+,[0-9]\+\.[0-9]\+ [0-9]\+ [0-9]\+\)$$' integration.coverage.out > integration.coverage-bodged.out grep '^\(mode: .*\)\|\(.*:[0-9]\+\.[0-9]\+,[0-9]\+\.[0-9]\+ [0-9]\+ [0-9]\+\)$$' integration.coverage.out > integration.coverage-bodged.out
$(GO) run tools/gocovmerge.go integration.coverage-bodged.out coverage-bodged.out > coverage.all $(GO) run build/gocovmerge.go integration.coverage-bodged.out coverage-bodged.out > coverage.all
.PHONY: unit-test-coverage .PHONY: unit-test-coverage
unit-test-coverage: unit-test-coverage:
@@ -436,20 +498,25 @@ tidy-check: tidy
go-licenses: $(GO_LICENSE_FILE) ## regenerate go licenses go-licenses: $(GO_LICENSE_FILE) ## regenerate go licenses
$(GO_LICENSE_FILE): go.mod go.sum $(GO_LICENSE_FILE): go.mod go.sum
GO=$(GO) $(GO) run build/generate-go-licenses.go $(GO_LICENSE_FILE) @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)
@rm -rf $(GO_LICENSE_TMP_DIR)
generate-ini-sqlite: generate-ini-sqlite:
sed -e 's|{{WORK_PATH}}|$(CURDIR)/tests/$(or $(TEST_TYPE),integration)/gitea-$(or $(TEST_TYPE),integration)-sqlite|g' \ sed -e 's|{{REPO_TEST_DIR}}|${REPO_TEST_DIR}|g' \
-e 's|{{TEST_LOGGER}}|$(or $(TEST_LOGGER),test$(COMMA)file)|g' \ -e 's|{{TEST_LOGGER}}|$(or $(TEST_LOGGER),test$(COMMA)file)|g' \
-e 's|{{TEST_TYPE}}|$(or $(TEST_TYPE),integration)|g' \
tests/sqlite.ini.tmpl > tests/sqlite.ini tests/sqlite.ini.tmpl > tests/sqlite.ini
.PHONY: test-sqlite .PHONY: test-sqlite
test-sqlite: integrations.sqlite.test generate-ini-sqlite test-sqlite: integrations.sqlite.test generate-ini-sqlite
GITEA_TEST_CONF=tests/sqlite.ini ./integrations.sqlite.test GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/sqlite.ini ./integrations.sqlite.test
.PHONY: test-sqlite\#% .PHONY: test-sqlite\#%
test-sqlite\#%: integrations.sqlite.test generate-ini-sqlite test-sqlite\#%: integrations.sqlite.test generate-ini-sqlite
GITEA_TEST_CONF=tests/sqlite.ini ./integrations.sqlite.test -test.run $(subst .,/,$*) GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/sqlite.ini ./integrations.sqlite.test -test.run $(subst .,/,$*)
.PHONY: test-sqlite-migration .PHONY: test-sqlite-migration
test-sqlite-migration: migrations.sqlite.test migrations.individual.sqlite.test test-sqlite-migration: migrations.sqlite.test migrations.individual.sqlite.test
@@ -459,17 +526,18 @@ generate-ini-mysql:
-e 's|{{TEST_MYSQL_DBNAME}}|${TEST_MYSQL_DBNAME}|g' \ -e 's|{{TEST_MYSQL_DBNAME}}|${TEST_MYSQL_DBNAME}|g' \
-e 's|{{TEST_MYSQL_USERNAME}}|${TEST_MYSQL_USERNAME}|g' \ -e 's|{{TEST_MYSQL_USERNAME}}|${TEST_MYSQL_USERNAME}|g' \
-e 's|{{TEST_MYSQL_PASSWORD}}|${TEST_MYSQL_PASSWORD}|g' \ -e 's|{{TEST_MYSQL_PASSWORD}}|${TEST_MYSQL_PASSWORD}|g' \
-e 's|{{WORK_PATH}}|$(CURDIR)/tests/$(or $(TEST_TYPE),integration)/gitea-$(or $(TEST_TYPE),integration)-mysql|g' \ -e 's|{{REPO_TEST_DIR}}|${REPO_TEST_DIR}|g' \
-e 's|{{TEST_LOGGER}}|$(or $(TEST_LOGGER),test$(COMMA)file)|g' \ -e 's|{{TEST_LOGGER}}|$(or $(TEST_LOGGER),test$(COMMA)file)|g' \
-e 's|{{TEST_TYPE}}|$(or $(TEST_TYPE),integration)|g' \
tests/mysql.ini.tmpl > tests/mysql.ini tests/mysql.ini.tmpl > tests/mysql.ini
.PHONY: test-mysql .PHONY: test-mysql
test-mysql: integrations.mysql.test generate-ini-mysql test-mysql: integrations.mysql.test generate-ini-mysql
GITEA_TEST_CONF=tests/mysql.ini ./integrations.mysql.test GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/mysql.ini ./integrations.mysql.test
.PHONY: test-mysql\#% .PHONY: test-mysql\#%
test-mysql\#%: integrations.mysql.test generate-ini-mysql test-mysql\#%: integrations.mysql.test generate-ini-mysql
GITEA_TEST_CONF=tests/mysql.ini ./integrations.mysql.test -test.run $(subst .,/,$*) GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/mysql.ini ./integrations.mysql.test -test.run $(subst .,/,$*)
.PHONY: test-mysql-migration .PHONY: test-mysql-migration
test-mysql-migration: migrations.mysql.test migrations.individual.mysql.test test-mysql-migration: migrations.mysql.test migrations.individual.mysql.test
@@ -481,17 +549,18 @@ generate-ini-pgsql:
-e 's|{{TEST_PGSQL_PASSWORD}}|${TEST_PGSQL_PASSWORD}|g' \ -e 's|{{TEST_PGSQL_PASSWORD}}|${TEST_PGSQL_PASSWORD}|g' \
-e 's|{{TEST_PGSQL_SCHEMA}}|${TEST_PGSQL_SCHEMA}|g' \ -e 's|{{TEST_PGSQL_SCHEMA}}|${TEST_PGSQL_SCHEMA}|g' \
-e 's|{{TEST_MINIO_ENDPOINT}}|${TEST_MINIO_ENDPOINT}|g' \ -e 's|{{TEST_MINIO_ENDPOINT}}|${TEST_MINIO_ENDPOINT}|g' \
-e 's|{{WORK_PATH}}|$(CURDIR)/tests/$(or $(TEST_TYPE),integration)/gitea-$(or $(TEST_TYPE),integration)-pgsql|g' \ -e 's|{{REPO_TEST_DIR}}|${REPO_TEST_DIR}|g' \
-e 's|{{TEST_LOGGER}}|$(or $(TEST_LOGGER),test$(COMMA)file)|g' \ -e 's|{{TEST_LOGGER}}|$(or $(TEST_LOGGER),test$(COMMA)file)|g' \
-e 's|{{TEST_TYPE}}|$(or $(TEST_TYPE),integration)|g' \
tests/pgsql.ini.tmpl > tests/pgsql.ini tests/pgsql.ini.tmpl > tests/pgsql.ini
.PHONY: test-pgsql .PHONY: test-pgsql
test-pgsql: integrations.pgsql.test generate-ini-pgsql test-pgsql: integrations.pgsql.test generate-ini-pgsql
GITEA_TEST_CONF=tests/pgsql.ini ./integrations.pgsql.test GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/pgsql.ini ./integrations.pgsql.test
.PHONY: test-pgsql\#% .PHONY: test-pgsql\#%
test-pgsql\#%: integrations.pgsql.test generate-ini-pgsql test-pgsql\#%: integrations.pgsql.test generate-ini-pgsql
GITEA_TEST_CONF=tests/pgsql.ini ./integrations.pgsql.test -test.run $(subst .,/,$*) GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/pgsql.ini ./integrations.pgsql.test -test.run $(subst .,/,$*)
.PHONY: test-pgsql-migration .PHONY: test-pgsql-migration
test-pgsql-migration: migrations.pgsql.test migrations.individual.pgsql.test test-pgsql-migration: migrations.pgsql.test migrations.individual.pgsql.test
@@ -501,53 +570,89 @@ generate-ini-mssql:
-e 's|{{TEST_MSSQL_DBNAME}}|${TEST_MSSQL_DBNAME}|g' \ -e 's|{{TEST_MSSQL_DBNAME}}|${TEST_MSSQL_DBNAME}|g' \
-e 's|{{TEST_MSSQL_USERNAME}}|${TEST_MSSQL_USERNAME}|g' \ -e 's|{{TEST_MSSQL_USERNAME}}|${TEST_MSSQL_USERNAME}|g' \
-e 's|{{TEST_MSSQL_PASSWORD}}|${TEST_MSSQL_PASSWORD}|g' \ -e 's|{{TEST_MSSQL_PASSWORD}}|${TEST_MSSQL_PASSWORD}|g' \
-e 's|{{WORK_PATH}}|$(CURDIR)/tests/$(or $(TEST_TYPE),integration)/gitea-$(or $(TEST_TYPE),integration)-mssql|g' \ -e 's|{{REPO_TEST_DIR}}|${REPO_TEST_DIR}|g' \
-e 's|{{TEST_LOGGER}}|$(or $(TEST_LOGGER),test$(COMMA)file)|g' \ -e 's|{{TEST_LOGGER}}|$(or $(TEST_LOGGER),test$(COMMA)file)|g' \
-e 's|{{TEST_TYPE}}|$(or $(TEST_TYPE),integration)|g' \
tests/mssql.ini.tmpl > tests/mssql.ini tests/mssql.ini.tmpl > tests/mssql.ini
.PHONY: test-mssql .PHONY: test-mssql
test-mssql: integrations.mssql.test generate-ini-mssql test-mssql: integrations.mssql.test generate-ini-mssql
GITEA_TEST_CONF=tests/mssql.ini ./integrations.mssql.test GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/mssql.ini ./integrations.mssql.test
.PHONY: test-mssql\#% .PHONY: test-mssql\#%
test-mssql\#%: integrations.mssql.test generate-ini-mssql test-mssql\#%: integrations.mssql.test generate-ini-mssql
GITEA_TEST_CONF=tests/mssql.ini ./integrations.mssql.test -test.run $(subst .,/,$*) GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/mssql.ini ./integrations.mssql.test -test.run $(subst .,/,$*)
.PHONY: test-mssql-migration .PHONY: test-mssql-migration
test-mssql-migration: migrations.mssql.test migrations.individual.mssql.test test-mssql-migration: migrations.mssql.test migrations.individual.mssql.test
.PHONY: playwright .PHONY: playwright
playwright: deps-frontend playwright: deps-frontend
@# on GitHub Actions VMs, playwright's system deps are pre-installed $(NODE_VARS) pnpm exec playwright install $(PLAYWRIGHT_FLAGS)
@pnpm exec playwright install $(if $(GITHUB_ACTIONS),,--with-deps) chromium firefox $(PLAYWRIGHT_FLAGS)
.PHONY: test-e2e%
test-e2e%: TEST_TYPE ?= e2e
# Clear display env variable. Otherwise, chromium tests can fail.
DISPLAY=
.PHONY: test-e2e .PHONY: test-e2e
test-e2e: playwright $(EXECUTABLE_E2E) test-e2e: test-e2e-sqlite
@EXECUTABLE=$(EXECUTABLE_E2E) ./tools/test-e2e.sh $(GITEA_TEST_E2E_FLAGS)
.PHONY: test-e2e-sqlite
test-e2e-sqlite: playwright e2e.sqlite.test generate-ini-sqlite
GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/sqlite.ini ./e2e.sqlite.test
.PHONY: test-e2e-sqlite\#%
test-e2e-sqlite\#%: playwright e2e.sqlite.test generate-ini-sqlite
GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/sqlite.ini ./e2e.sqlite.test -test.run TestE2e/$*
.PHONY: test-e2e-mysql
test-e2e-mysql: playwright e2e.mysql.test generate-ini-mysql
GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/mysql.ini ./e2e.mysql.test
.PHONY: test-e2e-mysql\#%
test-e2e-mysql\#%: playwright e2e.mysql.test generate-ini-mysql
GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/mysql.ini ./e2e.mysql.test -test.run TestE2e/$*
.PHONY: test-e2e-pgsql
test-e2e-pgsql: playwright e2e.pgsql.test generate-ini-pgsql
GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/pgsql.ini ./e2e.pgsql.test
.PHONY: test-e2e-pgsql\#%
test-e2e-pgsql\#%: playwright e2e.pgsql.test generate-ini-pgsql
GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/pgsql.ini ./e2e.pgsql.test -test.run TestE2e/$*
.PHONY: test-e2e-mssql
test-e2e-mssql: playwright e2e.mssql.test generate-ini-mssql
GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/mssql.ini ./e2e.mssql.test
.PHONY: test-e2e-mssql\#%
test-e2e-mssql\#%: playwright e2e.mssql.test generate-ini-mssql
GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/mssql.ini ./e2e.mssql.test -test.run TestE2e/$*
.PHONY: bench-sqlite .PHONY: bench-sqlite
bench-sqlite: integrations.sqlite.test generate-ini-sqlite bench-sqlite: integrations.sqlite.test generate-ini-sqlite
GITEA_TEST_CONF=tests/sqlite.ini ./integrations.sqlite.test -test.cpuprofile=cpu.out -test.run DontRunTests -test.bench . GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/sqlite.ini ./integrations.sqlite.test -test.cpuprofile=cpu.out -test.run DontRunTests -test.bench .
.PHONY: bench-mysql .PHONY: bench-mysql
bench-mysql: integrations.mysql.test generate-ini-mysql bench-mysql: integrations.mysql.test generate-ini-mysql
GITEA_TEST_CONF=tests/mysql.ini ./integrations.mysql.test -test.cpuprofile=cpu.out -test.run DontRunTests -test.bench . GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/mysql.ini ./integrations.mysql.test -test.cpuprofile=cpu.out -test.run DontRunTests -test.bench .
.PHONY: bench-mssql .PHONY: bench-mssql
bench-mssql: integrations.mssql.test generate-ini-mssql bench-mssql: integrations.mssql.test generate-ini-mssql
GITEA_TEST_CONF=tests/mssql.ini ./integrations.mssql.test -test.cpuprofile=cpu.out -test.run DontRunTests -test.bench . GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/mssql.ini ./integrations.mssql.test -test.cpuprofile=cpu.out -test.run DontRunTests -test.bench .
.PHONY: bench-pgsql .PHONY: bench-pgsql
bench-pgsql: integrations.pgsql.test generate-ini-pgsql bench-pgsql: integrations.pgsql.test generate-ini-pgsql
GITEA_TEST_CONF=tests/pgsql.ini ./integrations.pgsql.test -test.cpuprofile=cpu.out -test.run DontRunTests -test.bench . GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/pgsql.ini ./integrations.pgsql.test -test.cpuprofile=cpu.out -test.run DontRunTests -test.bench .
.PHONY: integration-test-coverage .PHONY: integration-test-coverage
integration-test-coverage: integrations.cover.test generate-ini-mysql integration-test-coverage: integrations.cover.test generate-ini-mysql
GITEA_TEST_CONF=tests/mysql.ini ./integrations.cover.test -test.coverprofile=integration.coverage.out GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/mysql.ini ./integrations.cover.test -test.coverprofile=integration.coverage.out
.PHONY: integration-test-coverage-sqlite .PHONY: integration-test-coverage-sqlite
integration-test-coverage-sqlite: integrations.cover.sqlite.test generate-ini-sqlite integration-test-coverage-sqlite: integrations.cover.sqlite.test generate-ini-sqlite
GITEA_TEST_CONF=tests/sqlite.ini ./integrations.cover.sqlite.test -test.coverprofile=integration.coverage.out GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/sqlite.ini ./integrations.cover.sqlite.test -test.coverprofile=integration.coverage.out
integrations.mysql.test: git-check $(GO_SOURCES) integrations.mysql.test: git-check $(GO_SOURCES)
$(GO) test $(GOTESTFLAGS) -c code.gitea.io/gitea/tests/integration -o integrations.mysql.test $(GO) test $(GOTESTFLAGS) -c code.gitea.io/gitea/tests/integration -o integrations.mysql.test
@@ -570,54 +675,66 @@ integrations.cover.sqlite.test: git-check $(GO_SOURCES)
.PHONY: migrations.mysql.test .PHONY: migrations.mysql.test
migrations.mysql.test: $(GO_SOURCES) generate-ini-mysql migrations.mysql.test: $(GO_SOURCES) generate-ini-mysql
$(GO) test $(GOTESTFLAGS) -c code.gitea.io/gitea/tests/integration/migration-test -o migrations.mysql.test $(GO) test $(GOTESTFLAGS) -c code.gitea.io/gitea/tests/integration/migration-test -o migrations.mysql.test
GITEA_TEST_CONF=tests/mysql.ini ./migrations.mysql.test GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/mysql.ini ./migrations.mysql.test
.PHONY: migrations.pgsql.test .PHONY: migrations.pgsql.test
migrations.pgsql.test: $(GO_SOURCES) generate-ini-pgsql migrations.pgsql.test: $(GO_SOURCES) generate-ini-pgsql
$(GO) test $(GOTESTFLAGS) -c code.gitea.io/gitea/tests/integration/migration-test -o migrations.pgsql.test $(GO) test $(GOTESTFLAGS) -c code.gitea.io/gitea/tests/integration/migration-test -o migrations.pgsql.test
GITEA_TEST_CONF=tests/pgsql.ini ./migrations.pgsql.test GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/pgsql.ini ./migrations.pgsql.test
.PHONY: migrations.mssql.test .PHONY: migrations.mssql.test
migrations.mssql.test: $(GO_SOURCES) generate-ini-mssql migrations.mssql.test: $(GO_SOURCES) generate-ini-mssql
$(GO) test $(GOTESTFLAGS) -c code.gitea.io/gitea/tests/integration/migration-test -o migrations.mssql.test $(GO) test $(GOTESTFLAGS) -c code.gitea.io/gitea/tests/integration/migration-test -o migrations.mssql.test
GITEA_TEST_CONF=tests/mssql.ini ./migrations.mssql.test GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/mssql.ini ./migrations.mssql.test
.PHONY: migrations.sqlite.test .PHONY: migrations.sqlite.test
migrations.sqlite.test: $(GO_SOURCES) generate-ini-sqlite migrations.sqlite.test: $(GO_SOURCES) generate-ini-sqlite
$(GO) test $(GOTESTFLAGS) -c code.gitea.io/gitea/tests/integration/migration-test -o migrations.sqlite.test -tags '$(TEST_TAGS)' $(GO) test $(GOTESTFLAGS) -c code.gitea.io/gitea/tests/integration/migration-test -o migrations.sqlite.test -tags '$(TEST_TAGS)'
GITEA_TEST_CONF=tests/sqlite.ini ./migrations.sqlite.test GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/sqlite.ini ./migrations.sqlite.test
.PHONY: migrations.individual.mysql.test .PHONY: migrations.individual.mysql.test
migrations.individual.mysql.test: $(GO_SOURCES) generate-ini-mysql migrations.individual.mysql.test: $(GO_SOURCES)
GITEA_TEST_CONF=tests/mysql.ini $(GO) test $(GOTESTFLAGS) -tags='$(TEST_TAGS)' -p 1 $(MIGRATE_TEST_PACKAGES) GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/mysql.ini $(GO) test $(GOTESTFLAGS) -tags='$(TEST_TAGS)' -p 1 $(MIGRATE_TEST_PACKAGES)
.PHONY: migrations.individual.sqlite.test\#% .PHONY: migrations.individual.sqlite.test\#%
migrations.individual.sqlite.test\#%: $(GO_SOURCES) generate-ini-sqlite migrations.individual.sqlite.test\#%: $(GO_SOURCES) generate-ini-sqlite
GITEA_TEST_CONF=tests/sqlite.ini $(GO) test $(GOTESTFLAGS) -tags '$(TEST_TAGS)' code.gitea.io/gitea/models/migrations/$* GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/sqlite.ini $(GO) test $(GOTESTFLAGS) -tags '$(TEST_TAGS)' code.gitea.io/gitea/models/migrations/$*
.PHONY: migrations.individual.pgsql.test .PHONY: migrations.individual.pgsql.test
migrations.individual.pgsql.test: $(GO_SOURCES) generate-ini-pgsql migrations.individual.pgsql.test: $(GO_SOURCES)
GITEA_TEST_CONF=tests/pgsql.ini $(GO) test $(GOTESTFLAGS) -tags='$(TEST_TAGS)' -p 1 $(MIGRATE_TEST_PACKAGES) GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/pgsql.ini $(GO) test $(GOTESTFLAGS) -tags='$(TEST_TAGS)' -p 1 $(MIGRATE_TEST_PACKAGES)
.PHONY: migrations.individual.pgsql.test\#% .PHONY: migrations.individual.pgsql.test\#%
migrations.individual.pgsql.test\#%: $(GO_SOURCES) generate-ini-pgsql migrations.individual.pgsql.test\#%: $(GO_SOURCES) generate-ini-pgsql
GITEA_TEST_CONF=tests/pgsql.ini $(GO) test $(GOTESTFLAGS) -tags '$(TEST_TAGS)' code.gitea.io/gitea/models/migrations/$* GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/pgsql.ini $(GO) test $(GOTESTFLAGS) -tags '$(TEST_TAGS)' code.gitea.io/gitea/models/migrations/$*
.PHONY: migrations.individual.mssql.test .PHONY: migrations.individual.mssql.test
migrations.individual.mssql.test: $(GO_SOURCES) generate-ini-mssql migrations.individual.mssql.test: $(GO_SOURCES) generate-ini-mssql
GITEA_TEST_CONF=tests/mssql.ini $(GO) test $(GOTESTFLAGS) -tags='$(TEST_TAGS)' -p 1 $(MIGRATE_TEST_PACKAGES) GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/mssql.ini $(GO) test $(GOTESTFLAGS) -tags='$(TEST_TAGS)' -p 1 $(MIGRATE_TEST_PACKAGES)
.PHONY: migrations.individual.mssql.test\#% .PHONY: migrations.individual.mssql.test\#%
migrations.individual.mssql.test\#%: $(GO_SOURCES) generate-ini-mssql migrations.individual.mssql.test\#%: $(GO_SOURCES) generate-ini-mssql
GITEA_TEST_CONF=tests/mssql.ini $(GO) test $(GOTESTFLAGS) -tags '$(TEST_TAGS)' code.gitea.io/gitea/models/migrations/$* GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/mssql.ini $(GO) test $(GOTESTFLAGS) -tags '$(TEST_TAGS)' code.gitea.io/gitea/models/migrations/$*
.PHONY: migrations.individual.sqlite.test .PHONY: migrations.individual.sqlite.test
migrations.individual.sqlite.test: $(GO_SOURCES) generate-ini-sqlite migrations.individual.sqlite.test: $(GO_SOURCES) generate-ini-sqlite
GITEA_TEST_CONF=tests/sqlite.ini $(GO) test $(GOTESTFLAGS) -tags='$(TEST_TAGS)' -p 1 $(MIGRATE_TEST_PACKAGES) GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/sqlite.ini $(GO) test $(GOTESTFLAGS) -tags='$(TEST_TAGS)' -p 1 $(MIGRATE_TEST_PACKAGES)
.PHONY: migrations.individual.sqlite.test\#% .PHONY: migrations.individual.sqlite.test\#%
migrations.individual.sqlite.test\#%: $(GO_SOURCES) generate-ini-sqlite migrations.individual.sqlite.test\#%: $(GO_SOURCES) generate-ini-sqlite
GITEA_TEST_CONF=tests/sqlite.ini $(GO) test $(GOTESTFLAGS) -tags '$(TEST_TAGS)' code.gitea.io/gitea/models/migrations/$* GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/sqlite.ini $(GO) test $(GOTESTFLAGS) -tags '$(TEST_TAGS)' code.gitea.io/gitea/models/migrations/$*
e2e.mysql.test: $(GO_SOURCES)
$(GO) test $(GOTESTFLAGS) -c code.gitea.io/gitea/tests/e2e -o e2e.mysql.test
e2e.pgsql.test: $(GO_SOURCES)
$(GO) test $(GOTESTFLAGS) -c code.gitea.io/gitea/tests/e2e -o e2e.pgsql.test
e2e.mssql.test: $(GO_SOURCES)
$(GO) test $(GOTESTFLAGS) -c code.gitea.io/gitea/tests/e2e -o e2e.mssql.test
e2e.sqlite.test: $(GO_SOURCES)
$(GO) test $(GOTESTFLAGS) -c code.gitea.io/gitea/tests/e2e -o e2e.sqlite.test -tags '$(TEST_TAGS)'
.PHONY: check .PHONY: check
check: test check: test
@@ -630,10 +747,10 @@ install: $(wildcard *.go)
build: frontend backend ## build everything build: frontend backend ## build everything
.PHONY: frontend .PHONY: frontend
frontend: $(FRONTEND_DEST) ## build frontend files frontend: $(WEBPACK_DEST) ## build frontend files
.PHONY: backend .PHONY: backend
backend: generate-backend $(EXECUTABLE) ## build backend files 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
@@ -649,17 +766,14 @@ generate-go: $(TAGS_PREREQ)
.PHONY: security-check .PHONY: security-check
security-check: security-check:
GOEXPERIMENT= go run $(GOVULNCHECK_PACKAGE) -show color ./... || true go run $(GOVULNCHECK_PACKAGE) -show color ./...
$(EXECUTABLE): $(GO_SOURCES) $(TAGS_PREREQ) $(EXECUTABLE): $(GO_SOURCES) $(TAGS_PREREQ)
ifneq ($(and $(STATIC),$(findstring pam,$(TAGS))),) ifneq ($(and $(STATIC),$(findstring pam,$(TAGS))),)
$(error pam support set via TAGS does not support static builds) $(error pam support set via TAGS doesn't support static builds)
endif endif
CGO_ENABLED="$(CGO_ENABLED)" CGO_CFLAGS="$(CGO_CFLAGS)" $(GO) build $(GOFLAGS) $(EXTRA_GOFLAGS) -tags '$(TAGS)' -ldflags '-s -w $(EXTLDFLAGS) $(LDFLAGS)' -o $@ CGO_ENABLED="$(CGO_ENABLED)" CGO_CFLAGS="$(CGO_CFLAGS)" $(GO) build $(GOFLAGS) $(EXTRA_GOFLAGS) -tags '$(TAGS)' -ldflags '-s -w $(EXTLDFLAGS) $(LDFLAGS)' -o $@
$(EXECUTABLE_E2E): $(GO_SOURCES) $(FRONTEND_DEST)
CGO_ENABLED=1 $(GO) build $(GOFLAGS) $(EXTRA_GOFLAGS) -tags '$(TEST_TAGS)' -ldflags '-s -w $(EXTLDFLAGS) $(LDFLAGS)' -o $@
.PHONY: release .PHONY: release
release: frontend generate release-windows release-linux release-darwin release-freebsd release-copy release-compress vendor release-sources release-check release: frontend generate release-windows release-linux release-darwin release-freebsd release-copy release-compress vendor release-sources release-check
@@ -724,17 +838,21 @@ deps-backend: ## install backend dependencies
deps-tools: ## install tool dependencies 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 $(GOLANGCI_LINT_PACKAGE) & \ $(GO) install $(GOLANGCI_LINT_PACKAGE) & \
$(GO) install $(GXZ_PACKAGE) & \ $(GO) install $(GXZ_PACKAGE) & \
$(GO) install $(MISSPELL_PACKAGE) & \ $(GO) install $(MISSPELL_PACKAGE) & \
$(GO) install $(SWAGGER_PACKAGE) & \ $(GO) install $(SWAGGER_PACKAGE) & \
$(GO) install $(XGO_PACKAGE) & \ $(GO) install $(XGO_PACKAGE) & \
$(GO) install $(GO_LICENSES_PACKAGE) & \
$(GO) install $(GOVULNCHECK_PACKAGE) & \ $(GO) install $(GOVULNCHECK_PACKAGE) & \
$(GO) install $(ACTIONLINT_PACKAGE) & \ $(GO) install $(ACTIONLINT_PACKAGE) & \
$(GO) install $(GOPLS_PACKAGE) & \
$(GO) install $(GOPLS_MODERNIZE_PACKAGE) & \
wait wait
node_modules: pnpm-lock.yaml node_modules: pnpm-lock.yaml
pnpm install --frozen-lockfile $(NODE_VARS) pnpm install --frozen-lockfile
@touch node_modules @touch node_modules
.venv: uv.lock .venv: uv.lock
@@ -742,41 +860,36 @@ node_modules: pnpm-lock.yaml
@touch .venv @touch .venv
.PHONY: update .PHONY: update
update: update-go update-js update-py ## update dependencies update: update-js update-py ## update js and py dependencies
.PHONY: update-go
update-go: ## update go dependencies
$(GO) get -u ./...
$(MAKE) tidy
.PHONY: update-js .PHONY: update-js
update-js: node_modules ## update js dependencies update-js: node-check | node_modules ## update js dependencies
pnpm exec updates -u -f package.json $(NODE_VARS) pnpm exec updates -u -f package.json
rm -rf node_modules pnpm-lock.yaml rm -rf node_modules pnpm-lock.yaml
pnpm install $(NODE_VARS) pnpm install
pnpm exec nolyfill install $(NODE_VARS) pnpm exec nolyfill install
pnpm install $(NODE_VARS) pnpm install
@touch node_modules @touch node_modules
.PHONY: update-py .PHONY: update-py
update-py: node_modules ## update py dependencies update-py: node-check | node_modules ## update py dependencies
pnpm exec updates -u -f pyproject.toml $(NODE_VARS) pnpm exec updates -u -f pyproject.toml
rm -rf .venv uv.lock rm -rf .venv uv.lock
uv sync uv sync
@touch .venv @touch .venv
.PHONY: vite .PHONY: webpack
vite: $(FRONTEND_DEST) ## build vite files webpack: $(WEBPACK_DEST) ## build webpack files
$(FRONTEND_DEST): $(FRONTEND_SOURCES) $(FRONTEND_CONFIGS) pnpm-lock.yaml $(WEBPACK_DEST): $(WEBPACK_SOURCES) $(WEBPACK_CONFIGS) pnpm-lock.yaml
@$(MAKE) -s node_modules @$(MAKE) -s node-check node_modules
@rm -rf $(FRONTEND_DEST_ENTRIES) @rm -rf $(WEBPACK_DEST_ENTRIES)
@echo "Running vite build..." @echo "Running webpack..."
@pnpm exec vite build @BROWSERSLIST_IGNORE_OLD_DATA=true $(NODE_VARS) pnpm exec webpack --disable-interpret
@touch $(FRONTEND_DEST) @touch $(WEBPACK_DEST)
.PHONY: svg .PHONY: svg
svg: node_modules ## build svg files svg: node-check | node_modules ## build svg files
rm -rf $(SVG_DEST_DIR) rm -rf $(SVG_DEST_DIR)
node tools/generate-svg.ts node tools/generate-svg.ts
@@ -792,7 +905,7 @@ svg-check: svg
.PHONY: lockfile-check .PHONY: lockfile-check
lockfile-check: lockfile-check:
pnpm install --frozen-lockfile $(NODE_VARS) pnpm install --frozen-lockfile
@diff=$$(git diff --color=always pnpm-lock.yaml); \ @diff=$$(git diff --color=always pnpm-lock.yaml); \
if [ -n "$$diff" ]; then \ if [ -n "$$diff" ]; then \
echo "pnpm-lock.yaml is inconsistent with package.json"; \ echo "pnpm-lock.yaml is inconsistent with package.json"; \
@@ -801,6 +914,16 @@ lockfile-check:
exit 1; \ exit 1; \
fi fi
.PHONY: update-translations
update-translations:
mkdir -p ./translations
cd ./translations && curl -L https://crowdin.com/download/project/gitea.zip > gitea.zip && unzip gitea.zip
rm ./translations/gitea.zip
$(SED_INPLACE) -e 's/="/=/g' -e 's/"$$//g' ./translations/*.ini
$(SED_INPLACE) -e 's/\\"/"/g' ./translations/*.ini
mv ./translations/*.ini ./options/locale/
rmdir ./translations
.PHONY: generate-gitignore .PHONY: generate-gitignore
generate-gitignore: ## update gitignore files generate-gitignore: ## update gitignore files
$(GO) run build/generate-gitignores.go $(GO) run build/generate-gitignores.go
@@ -822,6 +945,9 @@ docker:
docker build --disable-content-trust=false -t $(DOCKER_REF) . docker build --disable-content-trust=false -t $(DOCKER_REF) .
# support also build args docker build --build-arg GITEA_VERSION=v1.2.3 --build-arg TAGS="bindata sqlite sqlite_unlock_notify" . # support also build args docker build --build-arg GITEA_VERSION=v1.2.3 --build-arg TAGS="bindata sqlite sqlite_unlock_notify" .
# This endif closes the if at the top of the file
endif
# Disable parallel execution because it would break some targets that don't # Disable parallel execution because it would break some targets that don't
# specify exact dependencies like 'backend' which does currently not depend # specify exact dependencies like 'backend' which does currently not depend
# on 'frontend' to enable Node.js-less builds from source tarballs. # on 'frontend' to enable Node.js-less builds from source tarballs.

View File

@@ -8,6 +8,7 @@
[![](https://www.codetriage.com/go-gitea/gitea/badges/users.svg)](https://www.codetriage.com/go-gitea/gitea "Help Contribute to Open Source") [![](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://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)
[![](https://badges.crowdin.net/gitea/localized.svg)](https://translate.gitea.com "Crowdin") [![](https://badges.crowdin.net/gitea/localized.svg)](https://translate.gitea.com "Crowdin")
[繁體中文](./README.zh-tw.md) | [简体中文](./README.zh-cn.md) [繁體中文](./README.zh-tw.md) | [简体中文](./README.zh-cn.md)

View File

@@ -8,6 +8,7 @@
[![](https://www.codetriage.com/go-gitea/gitea/badges/users.svg)](https://www.codetriage.com/go-gitea/gitea "Help Contribute to Open Source") [![](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://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)
[![](https://badges.crowdin.net/gitea/localized.svg)](https://translate.gitea.com "Crowdin") [![](https://badges.crowdin.net/gitea/localized.svg)](https://translate.gitea.com "Crowdin")
[English](./README.md) | [繁體中文](./README.zh-tw.md) [English](./README.md) | [繁體中文](./README.zh-tw.md)
@@ -45,7 +46,7 @@
`build` 目标分为两个子目标: `build` 目标分为两个子目标:
- `make backend` 需要 [Go Stable](https://go.dev/dl/),所需版本在 [go.mod](/go.mod) 中定义。 - `make backend` 需要 [Go Stable](https://go.dev/dl/),所需版本在 [go.mod](/go.mod) 中定义。
- `make frontend` 需要 [Node.js LTS](https://nodejs.org/en/download/) 或更高版本以及 [pnpm](https://pnpm.io/installation) - `make frontend` 需要 [Node.js LTS](https://nodejs.org/en/download/) 或更高版本。
需要互联网连接来下载 go 和 npm 模块。从包含预构建前端文件的官方源代码压缩包构建时,不会触发 `frontend` 目标,因此可以在没有 Node.js 的情况下构建。 需要互联网连接来下载 go 和 npm 模块。从包含预构建前端文件的官方源代码压缩包构建时,不会触发 `frontend` 目标,因此可以在没有 Node.js 的情况下构建。

View File

@@ -8,6 +8,7 @@
[![](https://www.codetriage.com/go-gitea/gitea/badges/users.svg)](https://www.codetriage.com/go-gitea/gitea "Help Contribute to Open Source") [![](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://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)
[![](https://badges.crowdin.net/gitea/localized.svg)](https://translate.gitea.com "Crowdin") [![](https://badges.crowdin.net/gitea/localized.svg)](https://translate.gitea.com "Crowdin")
[English](./README.md) | [简体中文](./README.zh-cn.md) [English](./README.md) | [简体中文](./README.zh-cn.md)
@@ -45,7 +46,7 @@
`build` 目標分為兩個子目標: `build` 目標分為兩個子目標:
- `make backend` 需要 [Go Stable](https://go.dev/dl/),所需版本在 [go.mod](/go.mod) 中定義。 - `make backend` 需要 [Go Stable](https://go.dev/dl/),所需版本在 [go.mod](/go.mod) 中定義。
- `make frontend` 需要 [Node.js LTS](https://nodejs.org/en/download/) 或更高版本以及 [pnpm](https://pnpm.io/installation) - `make frontend` 需要 [Node.js LTS](https://nodejs.org/en/download/) 或更高版本。
需要互聯網連接來下載 go 和 npm 模塊。從包含預構建前端文件的官方源代碼壓縮包構建時,不會觸發 `frontend` 目標,因此可以在沒有 Node.js 的情況下構建。 需要互聯網連接來下載 go 和 npm 模塊。從包含預構建前端文件的官方源代碼壓縮包構建時,不會觸發 `frontend` 目標,因此可以在沒有 Node.js 的情況下構建。

11484
assets/emoji.json generated

File diff suppressed because one or more lines are too long

303
assets/go-licenses.json generated

File diff suppressed because one or more lines are too long

14
build.go Normal file
View File

@@ -0,0 +1,14 @@
// Copyright 2020 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
//go:build vendor
package main
// Libraries that are included to vendor utilities used during Makefile build.
// These libraries will not be included in a normal compilation.
import (
// for vet
_ "code.gitea.io/gitea-vet"
)

115
build/backport-locales.go Normal file
View File

@@ -0,0 +1,115 @@
// Copyright 2023 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
//go:build ignore
package main
import (
"fmt"
"os"
"os/exec"
"path/filepath"
"strings"
"code.gitea.io/gitea/modules/container"
"code.gitea.io/gitea/modules/setting"
)
func main() {
if len(os.Args) != 2 {
println("usage: backport-locales <to-ref>")
println("eg: backport-locales release/v1.19")
os.Exit(1)
}
mustNoErr := func(err error) {
if err != nil {
panic(err)
}
}
collectInis := func(ref string) map[string]setting.ConfigProvider {
inis := map[string]setting.ConfigProvider{}
err := filepath.WalkDir("options/locale", func(path string, d os.DirEntry, err error) error {
if err != nil {
return err
}
if d.IsDir() || !strings.HasSuffix(d.Name(), ".ini") {
return nil
}
cfg, err := setting.NewConfigProviderForLocale(path)
mustNoErr(err)
inis[path] = cfg
fmt.Printf("collecting: %s @ %s\n", path, ref)
return nil
})
mustNoErr(err)
return inis
}
// collect new locales from current working directory
inisNew := collectInis("HEAD")
// switch to the target ref, and collect the old locales
cmd := exec.Command("git", "checkout", os.Args[1])
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
mustNoErr(cmd.Run())
inisOld := collectInis(os.Args[1])
// use old en-US as the base, and copy the new translations to the old locales
enUsOld := inisOld["options/locale/locale_en-US.ini"]
brokenWarned := make(container.Set[string])
for path, iniOld := range inisOld {
if iniOld == enUsOld {
continue
}
iniNew := inisNew[path]
if iniNew == nil {
continue
}
for _, secEnUS := range enUsOld.Sections() {
secOld := iniOld.Section(secEnUS.Name())
secNew := iniNew.Section(secEnUS.Name())
for _, keyEnUs := range secEnUS.Keys() {
if secNew.HasKey(keyEnUs.Name()) {
oldStr := secOld.Key(keyEnUs.Name()).String()
newStr := secNew.Key(keyEnUs.Name()).String()
broken := oldStr != "" && strings.Count(oldStr, "%") != strings.Count(newStr, "%")
broken = broken || strings.Contains(oldStr, "\n") || strings.Contains(oldStr, "\n")
if broken {
brokenWarned.Add(secOld.Name() + "." + keyEnUs.Name())
fmt.Println("----")
fmt.Printf("WARNING: skip broken locale: %s , [%s] %s\n", path, secEnUS.Name(), keyEnUs.Name())
fmt.Printf("\told: %s\n", strings.ReplaceAll(oldStr, "\n", "\\n"))
fmt.Printf("\tnew: %s\n", strings.ReplaceAll(newStr, "\n", "\\n"))
continue
}
secOld.Key(keyEnUs.Name()).SetValue(newStr)
}
}
}
mustNoErr(iniOld.SaveTo(path))
}
fmt.Println("========")
for path, iniNew := range inisNew {
for _, sec := range iniNew.Sections() {
for _, key := range sec.Keys() {
str := sec.Key(key.Name()).String()
broken := strings.Contains(str, "\n")
broken = broken || strings.HasPrefix(str, "`") != strings.HasSuffix(str, "`")
broken = broken || strings.HasPrefix(str, "\"`")
broken = broken || strings.HasPrefix(str, "`\"")
broken = broken || strings.Count(str, `"`)%2 == 1
broken = broken || strings.Count(str, "`")%2 == 1
if broken && !brokenWarned.Contains(sec.Name()+"."+key.Name()) {
fmt.Printf("WARNING: found broken locale: %s , [%s] %s\n", path, sec.Name(), key.Name())
fmt.Printf("\tstr: %s\n", strings.ReplaceAll(str, "\n", "\\n"))
fmt.Println("----")
}
}
}
}
}

281
build/code-batch-process.go Normal file
View File

@@ -0,0 +1,281 @@
// Copyright 2021 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
//go:build ignore
package main
import (
"fmt"
"log"
"os"
"os/exec"
"path/filepath"
"regexp"
"strconv"
"strings"
"code.gitea.io/gitea/build/codeformat"
)
// Windows has a limitation for command line arguments, the size can not exceed 32KB.
// So we have to feed the files to some tools (like gofmt) batch by batch
// We also introduce a `gitea-fmt` command, it does better import formatting than gofmt/goimports. `gitea-fmt` calls `gofmt` internally.
var optionLogVerbose bool
func logVerbose(msg string, args ...any) {
if optionLogVerbose {
log.Printf(msg, args...)
}
}
func passThroughCmd(cmd string, args []string) error {
foundCmd, err := exec.LookPath(cmd)
if err != nil {
log.Fatalf("can not find cmd: %s", cmd)
}
c := exec.Cmd{
Path: foundCmd,
Args: append([]string{cmd}, args...),
Stdin: os.Stdin,
Stdout: os.Stdout,
Stderr: os.Stderr,
}
return c.Run()
}
type fileCollector struct {
dirs []string
includePatterns []*regexp.Regexp
excludePatterns []*regexp.Regexp
batchSize int
}
func newFileCollector(fileFilter string, batchSize int) (*fileCollector, error) {
co := &fileCollector{batchSize: batchSize}
if fileFilter == "go-own" {
co.dirs = []string{
"build",
"cmd",
"contrib",
"tests",
"models",
"modules",
"routers",
"services",
}
co.includePatterns = append(co.includePatterns, regexp.MustCompile(`.*\.go$`))
co.excludePatterns = append(co.excludePatterns, regexp.MustCompile(`.*\bbindata\.go$`))
co.excludePatterns = append(co.excludePatterns, regexp.MustCompile(`\.pb\.go$`))
co.excludePatterns = append(co.excludePatterns, regexp.MustCompile(`tests/gitea-repositories-meta`))
co.excludePatterns = append(co.excludePatterns, regexp.MustCompile(`tests/integration/migration-test`))
co.excludePatterns = append(co.excludePatterns, regexp.MustCompile(`modules/git/tests`))
co.excludePatterns = append(co.excludePatterns, regexp.MustCompile(`models/fixtures`))
co.excludePatterns = append(co.excludePatterns, regexp.MustCompile(`models/migrations/fixtures`))
co.excludePatterns = append(co.excludePatterns, regexp.MustCompile(`services/gitdiff/testdata`))
}
if co.dirs == nil {
return nil, fmt.Errorf("unknown file-filter: %s", fileFilter)
}
return co, nil
}
func (fc *fileCollector) matchPatterns(path string, regexps []*regexp.Regexp) bool {
path = strings.ReplaceAll(path, "\\", "/")
for _, re := range regexps {
if re.MatchString(path) {
return true
}
}
return false
}
func (fc *fileCollector) collectFiles() (res [][]string, err error) {
var batch []string
for _, dir := range fc.dirs {
err = filepath.WalkDir(dir, func(path string, d os.DirEntry, err error) error {
include := len(fc.includePatterns) == 0 || fc.matchPatterns(path, fc.includePatterns)
exclude := fc.matchPatterns(path, fc.excludePatterns)
process := include && !exclude
if !process {
if d.IsDir() {
if exclude {
logVerbose("exclude dir %s", path)
return filepath.SkipDir
}
// for a directory, if it is not excluded explicitly, we should walk into
return nil
}
// for a file, we skip it if it shouldn't be processed
logVerbose("skip process %s", path)
return nil
}
if d.IsDir() {
// skip dir, we don't add dirs to the file list now
return nil
}
if len(batch) >= fc.batchSize {
res = append(res, batch)
batch = nil
}
batch = append(batch, path)
return nil
})
if err != nil {
return nil, err
}
}
res = append(res, batch)
return res, nil
}
// substArgFiles expands the {file-list} to a real file list for commands
func substArgFiles(args, files []string) []string {
for i, s := range args {
if s == "{file-list}" {
newArgs := append(args[:i], files...)
newArgs = append(newArgs, args[i+1:]...)
return newArgs
}
}
return args
}
func exitWithCmdErrors(subCmd string, subArgs []string, cmdErrors []error) {
for _, err := range cmdErrors {
if err != nil {
if exitError, ok := err.(*exec.ExitError); ok {
exitCode := exitError.ExitCode()
log.Printf("run command failed (code=%d): %s %v", exitCode, subCmd, subArgs)
os.Exit(exitCode)
} else {
log.Fatalf("run command failed (err=%s) %s %v", err, subCmd, subArgs)
}
}
}
}
func parseArgs() (mainOptions map[string]string, subCmd string, subArgs []string) {
mainOptions = map[string]string{}
for i := 1; i < len(os.Args); i++ {
arg := os.Args[i]
if arg == "" {
break
}
if arg[0] == '-' {
arg = strings.TrimPrefix(arg, "-")
arg = strings.TrimPrefix(arg, "-")
fields := strings.SplitN(arg, "=", 2)
if len(fields) == 1 {
mainOptions[fields[0]] = "1"
} else {
mainOptions[fields[0]] = fields[1]
}
} else {
subCmd = arg
subArgs = os.Args[i+1:]
break
}
}
return mainOptions, subCmd, subArgs
}
func showUsage() {
fmt.Printf(`Usage: %[1]s [options] {command} [arguments]
Options:
--verbose
--file-filter=go-own
--batch-size=100
Commands:
%[1]s gofmt ...
Arguments:
{file-list} the file list
Example:
%[1]s gofmt -s -d {file-list}
`, "file-batch-exec")
}
func newFileCollectorFromMainOptions(mainOptions map[string]string) (fc *fileCollector, err error) {
fileFilter := mainOptions["file-filter"]
if fileFilter == "" {
fileFilter = "go-own"
}
batchSize, _ := strconv.Atoi(mainOptions["batch-size"])
if batchSize == 0 {
batchSize = 100
}
return newFileCollector(fileFilter, batchSize)
}
func containsString(a []string, s string) bool {
for _, v := range a {
if v == s {
return true
}
}
return false
}
func giteaFormatGoImports(files []string, doWriteFile bool) error {
for _, file := range files {
if err := codeformat.FormatGoImports(file, doWriteFile); err != nil {
log.Printf("failed to format go imports: %s, err=%v", file, err)
return err
}
}
return nil
}
func main() {
mainOptions, subCmd, subArgs := parseArgs()
if subCmd == "" {
showUsage()
os.Exit(1)
}
optionLogVerbose = mainOptions["verbose"] != ""
fc, err := newFileCollectorFromMainOptions(mainOptions)
if err != nil {
log.Fatalf("can not create file collector: %s", err.Error())
}
fileBatches, err := fc.collectFiles()
if err != nil {
log.Fatalf("can not collect files: %s", err.Error())
}
processed := 0
var cmdErrors []error
for _, files := range fileBatches {
if len(files) == 0 {
break
}
substArgs := substArgFiles(subArgs, files)
logVerbose("batch cmd: %s %v", subCmd, substArgs)
switch subCmd {
case "gitea-fmt":
if containsString(subArgs, "-d") {
log.Print("the -d option is not supported by gitea-fmt")
}
cmdErrors = append(cmdErrors, giteaFormatGoImports(files, containsString(subArgs, "-w")))
cmdErrors = append(cmdErrors, passThroughCmd("gofmt", append([]string{"-w", "-r", "interface{} -> any"}, substArgs...)))
cmdErrors = append(cmdErrors, passThroughCmd("go", append([]string{"run", os.Getenv("GOFUMPT_PACKAGE"), "-extra"}, substArgs...)))
default:
log.Fatalf("unknown cmd: %s %v", subCmd, subArgs)
}
processed += len(files)
}
logVerbose("processed %d files", processed)
exitWithCmdErrors(subCmd, subArgs, cmdErrors)
}

View File

@@ -0,0 +1,195 @@
// Copyright 2021 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package codeformat
import (
"bytes"
"errors"
"io"
"os"
"sort"
"strings"
)
var importPackageGroupOrders = map[string]int{
"": 1, // internal
"code.gitea.io/gitea/": 2,
}
var errInvalidCommentBetweenImports = errors.New("comments between imported packages are invalid, please move comments to the end of the package line")
var (
importBlockBegin = []byte("\nimport (\n")
importBlockEnd = []byte("\n)")
)
type importLineParsed struct {
group string
pkg string
content string
}
func parseImportLine(line string) (*importLineParsed, error) {
il := &importLineParsed{content: line}
p1 := strings.IndexRune(line, '"')
if p1 == -1 {
return nil, errors.New("invalid import line: " + line)
}
p1++
p := strings.IndexRune(line[p1:], '"')
if p == -1 {
return nil, errors.New("invalid import line: " + line)
}
p2 := p1 + p
il.pkg = line[p1:p2]
pDot := strings.IndexRune(il.pkg, '.')
pSlash := strings.IndexRune(il.pkg, '/')
if pDot != -1 && pDot < pSlash {
il.group = "domain-package"
}
for groupName := range importPackageGroupOrders {
if groupName == "" {
continue // skip internal
}
if strings.HasPrefix(il.pkg, groupName) {
il.group = groupName
}
}
return il, nil
}
type (
importLineGroup []*importLineParsed
importLineGroupMap map[string]importLineGroup
)
func formatGoImports(contentBytes []byte) ([]byte, error) {
p1 := bytes.Index(contentBytes, importBlockBegin)
if p1 == -1 {
return nil, nil
}
p1 += len(importBlockBegin)
p := bytes.Index(contentBytes[p1:], importBlockEnd)
if p == -1 {
return nil, nil
}
p2 := p1 + p
importGroups := importLineGroupMap{}
r := bytes.NewBuffer(contentBytes[p1:p2])
eof := false
for !eof {
line, err := r.ReadString('\n')
eof = err == io.EOF
if err != nil && !eof {
return nil, err
}
line = strings.TrimSpace(line)
if line != "" {
if strings.HasPrefix(line, "//") || strings.HasPrefix(line, "/*") {
return nil, errInvalidCommentBetweenImports
}
importLine, err := parseImportLine(line)
if err != nil {
return nil, err
}
importGroups[importLine.group] = append(importGroups[importLine.group], importLine)
}
}
var groupNames []string
for groupName, importLines := range importGroups {
groupNames = append(groupNames, groupName)
sort.Slice(importLines, func(i, j int) bool {
return strings.Compare(importLines[i].pkg, importLines[j].pkg) < 0
})
}
sort.Slice(groupNames, func(i, j int) bool {
n1 := groupNames[i]
n2 := groupNames[j]
o1 := importPackageGroupOrders[n1]
o2 := importPackageGroupOrders[n2]
if o1 != 0 && o2 != 0 {
return o1 < o2
}
if o1 == 0 && o2 == 0 {
return strings.Compare(n1, n2) < 0
}
return o1 != 0
})
formattedBlock := bytes.Buffer{}
for _, groupName := range groupNames {
hasNormalImports := false
hasDummyImports := false
// non-dummy import comes first
for _, importLine := range importGroups[groupName] {
if strings.HasPrefix(importLine.content, "_") {
hasDummyImports = true
} else {
formattedBlock.WriteString("\t" + importLine.content + "\n")
hasNormalImports = true
}
}
// dummy (_ "pkg") comes later
if hasDummyImports {
if hasNormalImports {
formattedBlock.WriteString("\n")
}
for _, importLine := range importGroups[groupName] {
if strings.HasPrefix(importLine.content, "_") {
formattedBlock.WriteString("\t" + importLine.content + "\n")
}
}
}
formattedBlock.WriteString("\n")
}
formattedBlockBytes := bytes.TrimRight(formattedBlock.Bytes(), "\n")
var formattedBytes []byte
formattedBytes = append(formattedBytes, contentBytes[:p1]...)
formattedBytes = append(formattedBytes, formattedBlockBytes...)
formattedBytes = append(formattedBytes, contentBytes[p2:]...)
return formattedBytes, nil
}
// FormatGoImports format the imports by our rules (see unit tests)
func FormatGoImports(file string, doWriteFile bool) error {
f, err := os.Open(file)
if err != nil {
return err
}
var contentBytes []byte
{
defer f.Close()
contentBytes, err = io.ReadAll(f)
if err != nil {
return err
}
}
formattedBytes, err := formatGoImports(contentBytes)
if err != nil {
return err
}
if formattedBytes == nil {
return nil
}
if bytes.Equal(contentBytes, formattedBytes) {
return nil
}
if doWriteFile {
f, err = os.OpenFile(file, os.O_TRUNC|os.O_WRONLY, 0o644)
if err != nil {
return err
}
defer f.Close()
_, err = f.Write(formattedBytes)
return err
}
return err
}

View File

@@ -0,0 +1,124 @@
// Copyright 2021 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package codeformat
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestFormatImportsSimple(t *testing.T) {
formatted, err := formatGoImports([]byte(`
package codeformat
import (
"github.com/stretchr/testify/assert"
"testing"
)
`))
expected := `
package codeformat
import (
"testing"
"github.com/stretchr/testify/assert"
)
`
assert.NoError(t, err)
assert.Equal(t, expected, string(formatted))
}
func TestFormatImportsGroup(t *testing.T) {
// gofmt/goimports won't group the packages, for example, they produce such code:
// "bytes"
// "image"
// (a blank line)
// "fmt"
// "image/color/palette"
// our formatter does better, and these packages are grouped into one.
formatted, err := formatGoImports([]byte(`
package test
import (
"bytes"
"fmt"
"image"
"image/color"
_ "image/gif" // for processing gif images
_ "image/jpeg" // for processing jpeg images
_ "image/png" // for processing png images
"code.gitea.io/other/package"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/util"
"xorm.io/the/package"
"github.com/issue9/identicon"
"github.com/nfnt/resize"
"github.com/oliamb/cutter"
)
`))
expected := `
package test
import (
"bytes"
"fmt"
"image"
"image/color"
_ "image/gif" // for processing gif images
_ "image/jpeg" // for processing jpeg images
_ "image/png" // for processing png images
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/util"
"code.gitea.io/other/package"
"github.com/issue9/identicon"
"github.com/nfnt/resize"
"github.com/oliamb/cutter"
"xorm.io/the/package"
)
`
assert.NoError(t, err)
assert.Equal(t, expected, string(formatted))
}
func TestFormatImportsInvalidComment(t *testing.T) {
// why we shouldn't write comments between imports: it breaks the grouping of imports
// for example:
// "pkg1"
// "pkg2"
// // a comment
// "pkgA"
// "pkgB"
// the comment splits the packages into two groups, pkg1/2 are sorted separately, pkgA/B are sorted separately
// we don't want such code, so the code should be:
// "pkg1"
// "pkg2"
// "pkgA" // a comment
// "pkgB"
_, err := formatGoImports([]byte(`
package test
import (
"image/jpeg"
// for processing gif images
"image/gif"
)
`))
assert.ErrorIs(t, err, errInvalidCommentBetweenImports)
}

View File

@@ -24,8 +24,8 @@ import (
) )
const ( const (
gemojiURL = "https://raw.githubusercontent.com/rhysd/gemoji/537ff2d7e0496e9964824f7f73ec7ece88c9765a/db/emoji.json" gemojiURL = "https://raw.githubusercontent.com/github/gemoji/master/db/emoji.json"
maxUnicodeVersion = 16 maxUnicodeVersion = 15
) )
var flagOut = flag.String("o", "modules/emoji/emoji_data.go", "out") var flagOut = flag.String("o", "modules/emoji/emoji_data.go", "out")
@@ -149,8 +149,8 @@ func generate() ([]byte, error) {
} }
// write a JSON file to use with tribute (write before adding skin tones since we can't support them there yet) // write a JSON file to use with tribute (write before adding skin tones since we can't support them there yet)
file, _ := json.MarshalIndent(data, "", " ") file, _ := json.Marshal(data)
_ = os.WriteFile("assets/emoji.json", append(file, '\n'), 0o644) _ = os.WriteFile("assets/emoji.json", file, 0o644)
// Add skin tones to emoji that support it // Add skin tones to emoji that support it
var ( var (

View File

@@ -8,220 +8,99 @@ package main
import ( import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"io/fs"
"os" "os"
"os/exec" "path"
"path/filepath" "path/filepath"
"regexp" "regexp"
"slices"
"sort" "sort"
"strings" "strings"
"code.gitea.io/gitea/modules/container"
) )
// regexp is based on go-license, excluding README and NOTICE // regexp is based on go-license, excluding README and NOTICE
// https://github.com/google/go-licenses/blob/master/licenses/find.go // https://github.com/google/go-licenses/blob/master/licenses/find.go
// also defined in vite.config.ts
var licenseRe = regexp.MustCompile(`^(?i)((UN)?LICEN(S|C)E|COPYING).*$`) var licenseRe = regexp.MustCompile(`^(?i)((UN)?LICEN(S|C)E|COPYING).*$`)
// primaryLicenseRe matches exact primary license filenames without suffixes.
// When a directory has both primary and variant files (e.g. LICENSE and
// LICENSE.docs), only the primary files are kept.
var primaryLicenseRe = regexp.MustCompile(`^(?i)(LICEN[SC]E|COPYING)$`)
// ignoredNames are LicenseEntry.Name values to exclude from the output.
var ignoredNames = map[string]bool{
"code.gitea.io/gitea": true,
"code.gitea.io/gitea/options/license": true,
}
var excludedExt = map[string]bool{
".gitignore": true,
".go": true,
".mod": true,
".sum": true,
".toml": true,
".yaml": true,
".yml": true,
}
type ModuleInfo struct {
Path string
Dir string
PkgDirs []string // directories of packages imported from this module
}
type LicenseEntry struct { type LicenseEntry struct {
Name string `json:"name"` Name string `json:"name"`
Path string `json:"path"` Path string `json:"path"`
LicenseText string `json:"licenseText"` LicenseText string `json:"licenseText"`
} }
// getModules returns all dependency modules with their local directory paths func main() {
// and the package directories used from each module. if len(os.Args) != 3 {
func getModules(goCmd string) []ModuleInfo { fmt.Println("usage: go run generate-go-licenses.go <base-dir> <out-json-file>")
cmd := exec.Command(goCmd, "list", "-deps", "-f",
"{{if .Module}}{{.Module.Path}}\t{{.Module.Dir}}\t{{.Dir}}{{end}}", "./...")
cmd.Stderr = os.Stderr
// Use GOOS=linux with CGO to ensure we capture all platform-specific
// dependencies, matching the CI environment.
cmd.Env = append(os.Environ(), "GOOS=linux", "GOARCH=amd64", "CGO_ENABLED=1")
output, err := cmd.Output()
if err != nil {
fmt.Fprintf(os.Stderr, "failed to run 'go list -deps': %v\n", err)
os.Exit(1) os.Exit(1)
} }
var modules []ModuleInfo base, out := os.Args[1], os.Args[2]
seen := make(map[string]int) // module path -> index in modules
for _, line := range strings.Split(string(output), "\n") {
line = strings.TrimSpace(line)
if line == "" {
continue
}
parts := strings.Split(line, "\t")
if len(parts) != 3 {
continue
}
modPath, modDir, pkgDir := parts[0], parts[1], parts[2]
if idx, ok := seen[modPath]; ok {
modules[idx].PkgDirs = append(modules[idx].PkgDirs, pkgDir)
} else {
seen[modPath] = len(modules)
modules = append(modules, ModuleInfo{
Path: modPath,
Dir: modDir,
PkgDirs: []string{pkgDir},
})
}
}
return modules
}
// findLicenseFiles scans a module's root directory and its used package // Add ext for excluded files because license_test.go will be included for some reason.
// directories for license files. It also walks up from each package directory // And there are more files that should be excluded, check with:
// to the module root, scanning intermediate directories. Subdirectory licenses //
// are only included if their text differs from the root license(s). // go run github.com/google/go-licenses@v1.6.0 save . --force --save_path=.go-licenses 2>/dev/null
func findLicenseFiles(mod ModuleInfo) []LicenseEntry { // find .go-licenses -type f | while read FILE; do echo "${$(basename $FILE)##*.}"; done | sort -u
var entries []LicenseEntry // AUTHORS
seenTexts := make(map[string]bool) // COPYING
// LICENSE
// Makefile
// NOTICE
// gitignore
// go
// md
// mod
// sum
// toml
// txt
// yml
//
// It could be removed once we have a better regex.
excludedExt := container.SetOf(".gitignore", ".go", ".mod", ".sum", ".toml", ".yml")
// First, collect root-level license files. var paths []string
entries = append(entries, scanDirForLicenses(mod.Dir, mod.Path, "")...) err := filepath.WalkDir(base, func(path string, entry fs.DirEntry, err error) error {
for _, e := range entries {
seenTexts[e.LicenseText] = true
}
// Then check each package directory and all intermediate parent directories
// up to the module root for license files with unique text.
seenDirs := map[string]bool{mod.Dir: true}
for _, pkgDir := range mod.PkgDirs {
for dir := pkgDir; dir != mod.Dir && strings.HasPrefix(dir, mod.Dir); dir = filepath.Dir(dir) {
if seenDirs[dir] {
continue
}
seenDirs[dir] = true
for _, e := range scanDirForLicenses(dir, mod.Path, mod.Dir) {
if !seenTexts[e.LicenseText] {
seenTexts[e.LicenseText] = true
entries = append(entries, e)
}
}
}
}
return entries
}
// scanDirForLicenses reads a single directory for license files and returns entries.
// If moduleRoot is non-empty, paths are made relative to it.
func scanDirForLicenses(dir, modulePath, moduleRoot string) []LicenseEntry {
dirEntries, err := os.ReadDir(dir)
if err != nil {
return nil
}
var entries []LicenseEntry
for _, entry := range dirEntries {
if entry.IsDir() {
continue
}
name := entry.Name()
if !licenseRe.MatchString(name) {
continue
}
if excludedExt[strings.ToLower(filepath.Ext(name))] {
continue
}
content, err := os.ReadFile(filepath.Join(dir, name))
if err != nil { if err != nil {
continue return err
}
if entry.IsDir() || !licenseRe.MatchString(entry.Name()) || excludedExt.Contains(filepath.Ext(entry.Name())) {
return nil
}
paths = append(paths, path)
return nil
})
if err != nil {
panic(err)
}
sort.Strings(paths)
var entries []LicenseEntry
for _, filePath := range paths {
licenseText, err := os.ReadFile(filePath)
if err != nil {
panic(err)
} }
entryName := modulePath pkgPath := filepath.ToSlash(filePath)
entryPath := modulePath + "/" + name pkgPath = strings.TrimPrefix(pkgPath, base+"/")
if moduleRoot != "" { pkgName := path.Dir(pkgPath)
rel, _ := filepath.Rel(moduleRoot, dir)
if rel != "." { // There might be a bug somewhere in go-licenses that sometimes interprets the
relSlash := filepath.ToSlash(rel) // root package as "." and sometimes as "code.gitea.io/gitea". Workaround by
entryName = modulePath + "/" + relSlash // removing both of them for the sake of stable output.
entryPath = modulePath + "/" + relSlash + "/" + name if pkgName == "." || pkgName == "code.gitea.io/gitea" {
} continue
} }
entries = append(entries, LicenseEntry{ entries = append(entries, LicenseEntry{
Name: entryName, Name: pkgName,
Path: entryPath, Path: pkgPath,
LicenseText: string(content), LicenseText: string(licenseText),
}) })
} }
// When multiple license files exist, prefer primary files (e.g. LICENSE)
// over variants with suffixes (e.g. LICENSE.docs, LICENSE-2.0.txt).
// If no primary file exists, keep only the first variant.
if len(entries) > 1 {
var primary []LicenseEntry
for _, e := range entries {
fileName := e.Path[strings.LastIndex(e.Path, "/")+1:]
if primaryLicenseRe.MatchString(fileName) {
primary = append(primary, e)
}
}
if len(primary) > 0 {
return primary
}
return entries[:1]
}
return entries
}
func main() {
if len(os.Args) != 2 {
fmt.Println("usage: go run generate-go-licenses.go <out-json-file>")
os.Exit(1)
}
out := os.Args[1]
goCmd := "go"
if env := os.Getenv("GO"); env != "" {
goCmd = env
}
modules := getModules(goCmd)
var entries []LicenseEntry
for _, mod := range modules {
entries = append(entries, findLicenseFiles(mod)...)
}
entries = slices.DeleteFunc(entries, func(e LicenseEntry) bool {
return ignoredNames[e.Name]
})
sort.Slice(entries, func(i, j int) bool {
return entries[i].Path < entries[j].Path
})
jsonBytes, err := json.MarshalIndent(entries, "", " ") jsonBytes, err := json.MarshalIndent(entries, "", " ")
if err != nil { if err != nil {
panic(err) panic(err)

View File

@@ -1,22 +1,52 @@
#!/bin/sh #!/bin/sh
# this script runs in alpine image which only has `sh` shell # this script runs in alpine image which only has `sh` shell
if [ ! -f ./options/locale/locale_en-US.json ]; then
set +e
if sed --version 2>/dev/null | grep -q GNU; then
SED_INPLACE="sed -i"
else
SED_INPLACE="sed -i ''"
fi
set -e
if [ ! -f ./options/locale/locale_en-US.ini ]; then
echo "please run this script in the root directory of the project" echo "please run this script in the root directory of the project"
exit 1 exit 1
fi fi
mv ./options/locale/locale_en-US.json ./options/ mv ./options/locale/locale_en-US.ini ./options/
# the "ini" library for locale has many quirks, its behavior is different from Crowdin.
# see i18n_test.go for more details
# this script helps to unquote the Crowdin outputs for the quirky ini library
# * find all `key="...\"..."` lines
# * remove the leading quote
# * remove the trailing quote
# * unescape the quotes
# * eg: key="...\"..." => key=..."...
$SED_INPLACE -r -e '/^[-.A-Za-z0-9_]+[ ]*=[ ]*".*"$/ {
s/^([-.A-Za-z0-9_]+)[ ]*=[ ]*"/\1=/
s/"$//
s/\\"/"/g
}' ./options/locale/*.ini
# * if the escaped line is incomplete like `key="...` or `key=..."`, quote it with backticks
# * eg: key="... => key=`"...`
# * eg: key=..." => key=`..."`
$SED_INPLACE -r -e 's/^([-.A-Za-z0-9_]+)[ ]*=[ ]*(".*[^"])$/\1=`\2`/' ./options/locale/*.ini
$SED_INPLACE -r -e 's/^([-.A-Za-z0-9_]+)[ ]*=[ ]*([^"].*")$/\1=`\2`/' ./options/locale/*.ini
# Remove translation under 25% of en_us # Remove translation under 25% of en_us
baselines=$(cat "./options/locale_en-US.json" | wc -l) baselines=$(wc -l "./options/locale_en-US.ini" | cut -d" " -f1)
baselines=$((baselines / 4)) baselines=$((baselines / 4))
for filename in ./options/locale/*.json; do for filename in ./options/locale/*.ini; do
lines=$(cat "$filename" | wc -l) lines=$(wc -l "$filename" | cut -d" " -f1)
if [ "$lines" -lt "$baselines" ]; then if [ $lines -lt $baselines ]; then
echo "Removing $filename: $lines/$baselines" echo "Removing $filename: $lines/$baselines"
rm "$filename" rm "$filename"
fi fi
done done
mv ./options/locale_en-US.json ./options/locale/ mv ./options/locale_en-US.ini ./options/locale/

View File

@@ -13,18 +13,17 @@ import (
"github.com/urfave/cli/v3" "github.com/urfave/cli/v3"
) )
func newActionsCommand() *cli.Command { var (
return &cli.Command{ // CmdActions represents the available actions sub-commands.
CmdActions = &cli.Command{
Name: "actions", Name: "actions",
Usage: "Manage Gitea Actions", Usage: "Manage Gitea Actions",
Commands: []*cli.Command{ Commands: []*cli.Command{
newActionsGenerateRunnerTokenCommand(), subcmdActionsGenRunnerToken,
}, },
} }
}
func newActionsGenerateRunnerTokenCommand() *cli.Command { subcmdActionsGenRunnerToken = &cli.Command{
return &cli.Command{
Name: "generate-runner-token", Name: "generate-runner-token",
Usage: "Generate a new token for a runner to use to register with the server", Usage: "Generate a new token for a runner to use to register with the server",
Action: runGenerateActionsRunnerToken, Action: runGenerateActionsRunnerToken,
@@ -38,7 +37,7 @@ func newActionsGenerateRunnerTokenCommand() *cli.Command {
}, },
}, },
} }
} )
func runGenerateActionsRunnerToken(ctx context.Context, c *cli.Command) error { func runGenerateActionsRunnerToken(ctx context.Context, c *cli.Command) error {
setting.MustInstalled() setting.MustInstalled()

View File

@@ -18,41 +18,36 @@ import (
"github.com/urfave/cli/v3" "github.com/urfave/cli/v3"
) )
func newAdminCommand() *cli.Command { var (
return &cli.Command{ // CmdAdmin represents the available admin sub-command.
CmdAdmin = &cli.Command{
Name: "admin", Name: "admin",
Usage: "Perform common administrative operations", Usage: "Perform common administrative operations",
Commands: []*cli.Command{ Commands: []*cli.Command{
newUserCommand(), subcmdUser,
newRepoSyncReleasesCommand(), subcmdRepoSyncReleases,
newRegenerateCommand(), subcmdRegenerate,
newAuthCommand(), subcmdAuth,
newSendMailCommand(), subcmdSendMail,
}, },
} }
}
func newRepoSyncReleasesCommand() *cli.Command { subcmdRepoSyncReleases = &cli.Command{
return &cli.Command{
Name: "repo-sync-releases", Name: "repo-sync-releases",
Usage: "Synchronize repository releases with tags", Usage: "Synchronize repository releases with tags",
Action: runRepoSyncReleases, Action: runRepoSyncReleases,
} }
}
func newRegenerateCommand() *cli.Command { subcmdRegenerate = &cli.Command{
return &cli.Command{
Name: "regenerate", Name: "regenerate",
Usage: "Regenerate specific files", Usage: "Regenerate specific files",
Commands: []*cli.Command{ Commands: []*cli.Command{
newRegenerateHooksCommand(), microcmdRegenHooks,
newRegenerateKeysCommand(), microcmdRegenKeys,
}, },
} }
}
func newAuthCommand() *cli.Command { subcmdAuth = &cli.Command{
return &cli.Command{
Name: "auth", Name: "auth",
Usage: "Modify external auth providers", Usage: "Modify external auth providers",
Commands: []*cli.Command{ Commands: []*cli.Command{
@@ -64,14 +59,12 @@ func newAuthCommand() *cli.Command {
microcmdAuthUpdateLdapSimpleAuth(), microcmdAuthUpdateLdapSimpleAuth(),
microcmdAuthAddSMTP(), microcmdAuthAddSMTP(),
microcmdAuthUpdateSMTP(), microcmdAuthUpdateSMTP(),
newAuthListCommand(), microcmdAuthList,
newAuthDeleteCommand(), microcmdAuthDelete,
}, },
} }
}
func newSendMailCommand() *cli.Command { subcmdSendMail = &cli.Command{
return &cli.Command{
Name: "sendmail", Name: "sendmail",
Usage: "Send a message to all users", Usage: "Send a message to all users",
Action: runSendMail, Action: runSendMail,
@@ -93,7 +86,7 @@ func newSendMailCommand() *cli.Command {
}, },
}, },
} }
} )
func idFlag() *cli.Int64Flag { func idFlag() *cli.Int64Flag {
return &cli.Int64Flag{ return &cli.Int64Flag{
@@ -128,7 +121,7 @@ func runRepoSyncReleases(ctx context.Context, _ *cli.Command) error {
} }
log.Trace("Processing next %d repos of %d", len(repos), count) log.Trace("Processing next %d repos of %d", len(repos), count)
for _, repo := range repos { for _, repo := range repos {
log.Trace("Synchronizing repo %s with path %s", repo.FullName(), repo.RelativePath()) log.Trace("Synchronizing repo %s with path %s", repo.FullName(), repo.RepoPath())
gitRepo, err := gitrepo.OpenRepository(ctx, repo) gitRepo, err := gitrepo.OpenRepository(ctx, repo)
if err != nil { if err != nil {
log.Warn("OpenRepository: %v", err) log.Warn("OpenRepository: %v", err)
@@ -141,7 +134,7 @@ func runRepoSyncReleases(ctx context.Context, _ *cli.Command) error {
} }
log.Trace(" currentNumReleases is %d, running SyncReleasesWithTags", oldnum) log.Trace(" currentNumReleases is %d, running SyncReleasesWithTags", oldnum)
if _, err = repo_module.SyncReleasesWithTags(ctx, repo, gitRepo); err != nil { if err = repo_module.SyncReleasesWithTags(ctx, repo, gitRepo); err != nil {
log.Warn(" SyncReleasesWithTags: %v", err) log.Warn(" SyncReleasesWithTags: %v", err)
gitRepo.Close() gitRepo.Close()
continue continue
@@ -154,7 +147,7 @@ func runRepoSyncReleases(ctx context.Context, _ *cli.Command) error {
continue continue
} }
log.Trace("repo %s releases synchronized to tags: from %d to %d", log.Trace(" repo %s releases synchronized to tags: from %d to %d",
repo.FullName(), oldnum, count) repo.FullName(), oldnum, count)
gitRepo.Close() gitRepo.Close()
} }

View File

@@ -17,17 +17,14 @@ import (
"github.com/urfave/cli/v3" "github.com/urfave/cli/v3"
) )
func newAuthDeleteCommand() *cli.Command { var (
return &cli.Command{ microcmdAuthDelete = &cli.Command{
Name: "delete", Name: "delete",
Usage: "Delete specific auth source", Usage: "Delete specific auth source",
Flags: []cli.Flag{idFlag()}, Flags: []cli.Flag{idFlag()},
Action: runDeleteAuth, Action: runDeleteAuth,
} }
} microcmdAuthList = &cli.Command{
func newAuthListCommand() *cli.Command {
return &cli.Command{
Name: "list", Name: "list",
Usage: "List auth sources", Usage: "List auth sources",
Action: runListAuth, Action: runListAuth,
@@ -58,7 +55,7 @@ func newAuthListCommand() *cli.Command {
}, },
}, },
} }
} )
func runListAuth(ctx context.Context, c *cli.Command) error { func runListAuth(ctx context.Context, c *cli.Command) error {
if err := initDB(ctx); err != nil { if err := initDB(ctx); err != nil {

View File

@@ -94,10 +94,6 @@ func commonLdapCLIFlags() []cli.Flag {
Name: "public-ssh-key-attribute", Name: "public-ssh-key-attribute",
Usage: "The attribute of the users LDAP record containing the users public ssh key.", Usage: "The attribute of the users LDAP record containing the users public ssh key.",
}, },
&cli.BoolFlag{
Name: "ssh-keys-are-verified",
Usage: "Set to true to automatically flag SSH keys in LDAP as verified.",
},
&cli.BoolFlag{ &cli.BoolFlag{
Name: "skip-local-2fa", Name: "skip-local-2fa",
Usage: "Set to true to skip local 2fa for users authenticated by this source", Usage: "Set to true to skip local 2fa for users authenticated by this source",
@@ -298,9 +294,6 @@ func parseLdapConfig(c *cli.Command, config *ldap.Source) error {
if c.IsSet("public-ssh-key-attribute") { if c.IsSet("public-ssh-key-attribute") {
config.AttributeSSHPublicKey = c.String("public-ssh-key-attribute") config.AttributeSSHPublicKey = c.String("public-ssh-key-attribute")
} }
if c.IsSet("ssh-keys-are-verified") {
config.SSHKeysAreVerified = c.Bool("ssh-keys-are-verified")
}
if c.IsSet("avatar-attribute") { if c.IsSet("avatar-attribute") {
config.AttributeAvatar = c.String("avatar-attribute") config.AttributeAvatar = c.String("avatar-attribute")
} }

View File

@@ -233,7 +233,7 @@ func TestAddLdapBindDn(t *testing.T) {
}, },
getAuthSourceByID: func(ctx context.Context, id int64) (*auth.Source, error) { getAuthSourceByID: func(ctx context.Context, id int64) (*auth.Source, error) {
assert.FailNow(t, "getAuthSourceByID called", "case %d: should not call getAuthSourceByID", n) assert.FailNow(t, "getAuthSourceByID called", "case %d: should not call getAuthSourceByID", n)
return nil, nil //nolint:nilnil // mock function covering improper behavior return nil, nil
}, },
} }
@@ -463,7 +463,7 @@ func TestAddLdapSimpleAuth(t *testing.T) {
}, },
getAuthSourceByID: func(ctx context.Context, id int64) (*auth.Source, error) { getAuthSourceByID: func(ctx context.Context, id int64) (*auth.Source, error) {
assert.FailNow(t, "getAuthSourceById called", "case %d: should not call getAuthSourceByID", n) assert.FailNow(t, "getAuthSourceById called", "case %d: should not call getAuthSourceByID", n)
return nil, nil //nolint:nilnil // mock function covering improper behavior return nil, nil
}, },
} }

View File

@@ -13,21 +13,19 @@ import (
"github.com/urfave/cli/v3" "github.com/urfave/cli/v3"
) )
func newRegenerateHooksCommand() *cli.Command { var (
return &cli.Command{ microcmdRegenHooks = &cli.Command{
Name: "hooks", Name: "hooks",
Usage: "Regenerate git-hooks", Usage: "Regenerate git-hooks",
Action: runRegenerateHooks, Action: runRegenerateHooks,
} }
}
func newRegenerateKeysCommand() *cli.Command { microcmdRegenKeys = &cli.Command{
return &cli.Command{
Name: "keys", Name: "keys",
Usage: "Regenerate authorized_keys file", Usage: "Regenerate authorized_keys file",
Action: runRegenerateKeys, Action: runRegenerateKeys,
} }
} )
func runRegenerateHooks(ctx context.Context, _ *cli.Command) error { func runRegenerateHooks(ctx context.Context, _ *cli.Command) error {
if err := initDB(ctx); err != nil { if err := initDB(ctx); err != nil {

View File

@@ -7,17 +7,15 @@ import (
"github.com/urfave/cli/v3" "github.com/urfave/cli/v3"
) )
func newUserCommand() *cli.Command { var subcmdUser = &cli.Command{
return &cli.Command{ Name: "user",
Name: "user", Usage: "Modify users",
Usage: "Modify users", Commands: []*cli.Command{
Commands: []*cli.Command{ microcmdUserCreate(),
microcmdUserCreate(), microcmdUserList,
newUserListCommand(), microcmdUserChangePassword(),
microcmdUserChangePassword(), microcmdUserDelete(),
microcmdUserDelete(), microcmdUserGenerateAccessToken,
newUserGenerateAccessTokenCommand(), microcmdUserMustChangePassword(),
microcmdUserMustChangePassword(), },
},
}
} }

View File

@@ -151,7 +151,6 @@ func runCreateUser(ctx context.Context, c *cli.Command) error {
if err != nil { if err != nil {
return err return err
} }
// codeql[disable-next-line=go/clear-text-logging]
fmt.Printf("generated random password is '%s'\n", password) fmt.Printf("generated random password is '%s'\n", password)
} else if userType == user_model.UserTypeIndividual { } 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")

View File

@@ -14,34 +14,32 @@ import (
"github.com/urfave/cli/v3" "github.com/urfave/cli/v3"
) )
func newUserGenerateAccessTokenCommand() *cli.Command { var microcmdUserGenerateAccessToken = &cli.Command{
return &cli.Command{ Name: "generate-access-token",
Name: "generate-access-token", Usage: "Generate an access token for a specific user",
Usage: "Generate an access token for a specific user", Flags: []cli.Flag{
Flags: []cli.Flag{ &cli.StringFlag{
&cli.StringFlag{ Name: "username",
Name: "username", Aliases: []string{"u"},
Aliases: []string{"u"}, Usage: "Username",
Usage: "Username",
},
&cli.StringFlag{
Name: "token-name",
Aliases: []string{"t"},
Usage: "Token name",
Value: "gitea-admin",
},
&cli.BoolFlag{
Name: "raw",
Usage: "Display only the token value",
},
&cli.StringFlag{
Name: "scopes",
Value: "all",
Usage: `Comma separated list of scopes to apply to access token, examples: "all", "public-only,read:issue", "write:repository,write:user"`,
},
}, },
Action: runGenerateAccessToken, &cli.StringFlag{
} Name: "token-name",
Aliases: []string{"t"},
Usage: "Token name",
Value: "gitea-admin",
},
&cli.BoolFlag{
Name: "raw",
Usage: "Display only the token value",
},
&cli.StringFlag{
Name: "scopes",
Value: "all",
Usage: `Comma separated list of scopes to apply to access token, examples: "all", "public-only,read:issue", "write:repository,write:user"`,
},
},
Action: runGenerateAccessToken,
} }
func runGenerateAccessToken(ctx context.Context, c *cli.Command) error { func runGenerateAccessToken(ctx context.Context, c *cli.Command) error {

View File

@@ -14,18 +14,16 @@ import (
"github.com/urfave/cli/v3" "github.com/urfave/cli/v3"
) )
func newUserListCommand() *cli.Command { var microcmdUserList = &cli.Command{
return &cli.Command{ Name: "list",
Name: "list", Usage: "List users",
Usage: "List users", Action: runListUsers,
Action: runListUsers, Flags: []cli.Flag{
Flags: []cli.Flag{ &cli.BoolFlag{
&cli.BoolFlag{ Name: "admin",
Name: "admin", Usage: "List only admin users",
Usage: "List only admin users",
},
}, },
} },
} }
func runListUsers(ctx context.Context, c *cli.Command) error { func runListUsers(ctx context.Context, c *cli.Command) error {

View File

@@ -58,7 +58,6 @@ func runMustChangePassword(ctx context.Context, c *cli.Command) error {
return err return err
} }
// codeql[disable-next-line=go/clear-text-logging]
fmt.Printf("Updated %d users setting MustChangePassword to %t\n", n, mustChangePassword) fmt.Printf("Updated %d users setting MustChangePassword to %t\n", n, mustChangePassword)
return nil return nil
} }

View File

@@ -1,156 +0,0 @@
// Copyright 2025 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package cmd
import (
"context"
"errors"
"fmt"
"os"
"code.gitea.io/gitea/modules/setting"
"github.com/urfave/cli/v3"
)
func cmdConfig() *cli.Command {
subcmdConfigEditIni := &cli.Command{
Name: "edit-ini",
Usage: "Load an existing INI file, apply environment variables, keep specified keys, and output to a new INI file.",
Description: `
Help users to edit the Gitea configuration INI file.
# Keep Specified Keys
If you need to re-create the configuration file with only a subset of keys,
you can provide an INI template file for the kept keys and use the "--config-keep-keys" flag.
For example, if a helm chart needs to reset the settings and only keep SECRET_KEY,
it can use a template file (only keys take effect, values are ignored):
[security]
SECRET_KEY=
$ ./gitea config edit-ini --config app-old.ini --config-keep-keys app-keys.ini --out app-new.ini
# Map Environment Variables to INI Configuration
Environment variables of the form "GITEA__section_name__KEY_NAME"
will be mapped to the ini section "[section_name]" and the key
"KEY_NAME" with the value as provided.
Environment variables of the form "GITEA__section_name__KEY_NAME__FILE"
will be mapped to the ini section "[section_name]" and the key
"KEY_NAME" with the value loaded from the specified file.
Environment variable keys can only contain characters "0-9A-Z_",
if a section or key name contains dot ".", it needs to be escaped as _0x2E_.
For example, to apply this config:
[git.config]
foo.bar=val
$ export GITEA__git_0x2E_config__foo_0x2E_bar=val
# Put All Together
$ ./gitea config edit-ini --config app.ini --config-keep-keys app-keys.ini --apply-env {--in-place|--out app-new.ini}
`,
Flags: []cli.Flag{
// "--config" flag is provided by global flags, and this flag is also used by "environment-to-ini" script wrapper
// "--in-place" is also used by "environment-to-ini" script wrapper for its old behavior: always overwrite the existing config file
&cli.BoolFlag{
Name: "in-place",
Usage: "Output to the same config file as input. This flag will be ignored if --out is set.",
},
&cli.StringFlag{
Name: "config-keep-keys",
Usage: "An INI template file containing keys for keeping. Only the keys defined in the INI template will be kept from old config. If not set, all keys will be kept.",
},
&cli.BoolFlag{
Name: "apply-env",
Usage: "Apply all GITEA__* variables from the environment to the config.",
},
&cli.StringFlag{
Name: "out",
Usage: "Destination config file to write to.",
},
},
Action: runConfigEditIni,
}
return &cli.Command{
Name: "config",
Usage: "Manage Gitea configuration",
Commands: []*cli.Command{
subcmdConfigEditIni,
},
}
}
func runConfigEditIni(_ context.Context, c *cli.Command) error {
// the config system may change the environment variables, so get a copy first, to be used later
env := append([]string{}, os.Environ()...)
// don't use the guessed setting.CustomConf, instead, require the user to provide --config explicitly
if !c.IsSet("config") {
return errors.New("flag is required but not set: --config")
}
configFileIn := c.String("config")
cfgIn, err := setting.NewConfigProviderFromFile(configFileIn)
if err != nil {
return fmt.Errorf("failed to load config file %q: %v", configFileIn, err)
}
// determine output config file: use "--out" flag or use "--in-place" flag to overwrite input file
inPlace := c.Bool("in-place")
configFileOut := c.String("out")
if configFileOut == "" {
if !inPlace {
return errors.New("either --in-place or --out must be specified")
}
configFileOut = configFileIn // in-place edit
}
needWriteOut := configFileOut != configFileIn
cfgOut := cfgIn
configKeepKeys := c.String("config-keep-keys")
if configKeepKeys != "" {
needWriteOut = true
cfgOut, err = setting.NewConfigProviderFromFile(configKeepKeys)
if err != nil {
return fmt.Errorf("failed to load config-keep-keys template file %q: %v", configKeepKeys, err)
}
for _, secOut := range cfgOut.Sections() {
for _, keyOut := range secOut.Keys() {
secIn := cfgIn.Section(secOut.Name())
keyIn := setting.ConfigSectionKey(secIn, keyOut.Name())
if keyIn != nil {
keyOut.SetValue(keyIn.String())
} else {
secOut.DeleteKey(keyOut.Name())
}
}
if len(secOut.Keys()) == 0 {
cfgOut.DeleteSection(secOut.Name())
}
}
}
if c.Bool("apply-env") {
if setting.EnvironmentToConfig(cfgOut, env) {
needWriteOut = true
}
}
if needWriteOut {
err = cfgOut.SaveTo(configFileOut)
if err != nil {
return err
}
}
return nil
}

View File

@@ -1,85 +0,0 @@
// Copyright 2025 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package cmd
import (
"os"
"testing"
"github.com/stretchr/testify/require"
)
func TestConfigEdit(t *testing.T) {
tmpDir := t.TempDir()
configOld := tmpDir + "/app-old.ini"
configTemplate := tmpDir + "/app-template.ini"
_ = os.WriteFile(configOld, []byte(`
[sec]
k1=v1
k2=v2
`), os.ModePerm)
_ = os.WriteFile(configTemplate, []byte(`
[sec]
k1=in-template
[sec2]
k3=v3
`), os.ModePerm)
t.Setenv("GITEA__EnV__KeY", "val")
t.Run("OutputToNewWithEnv", func(t *testing.T) {
configNew := tmpDir + "/app-new.ini"
err := NewMainApp(AppVersion{}).Run(t.Context(), []string{
"./gitea", "--config", configOld,
"config", "edit-ini",
"--apply-env",
"--config-keep-keys", configTemplate,
"--out", configNew,
})
require.NoError(t, err)
// "k1" old value is kept because its key is in the template
// "k2" is removed because it isn't in the template
// "k3" isn't in new config because it isn't in the old config
// [env] is applied from environment variable
data, _ := os.ReadFile(configNew)
require.Equal(t, `[sec]
k1 = v1
[env]
KeY = val
`, string(data))
})
t.Run("OutputToExisting(environment-to-ini)", func(t *testing.T) {
// the legacy "environment-to-ini" (now a wrapper script) behavior:
// if no "--out", then "--in-place" must be used to overwrite the existing "--config" file
err := NewMainApp(AppVersion{}).Run(t.Context(), []string{
"./gitea", "config", "edit-ini",
"--apply-env",
"--config", configOld,
})
require.ErrorContains(t, err, "either --in-place or --out must be specified")
// simulate the "environment-to-ini" behavior with "--in-place"
err = NewMainApp(AppVersion{}).Run(t.Context(), []string{
"./gitea", "config", "edit-ini",
"--in-place",
"--apply-env",
"--config", configOld,
})
require.NoError(t, err)
data, _ := os.ReadFile(configOld)
require.Equal(t, `[sec]
k1 = v1
k2 = v2
[env]
KeY = val
`, string(data))
})
}

View File

@@ -13,24 +13,23 @@ import (
"github.com/urfave/cli/v3" "github.com/urfave/cli/v3"
) )
func newDocsCommand() *cli.Command { // CmdDocs represents the available docs sub-command.
return &cli.Command{ var CmdDocs = &cli.Command{
Name: "docs", Name: "docs",
Usage: "Output CLI documentation", Usage: "Output CLI documentation",
Description: "A command to output Gitea's CLI documentation, optionally to a file.", Description: "A command to output Gitea's CLI documentation, optionally to a file.",
Action: runDocs, Action: runDocs,
Flags: []cli.Flag{ Flags: []cli.Flag{
&cli.BoolFlag{ &cli.BoolFlag{
Name: "man", Name: "man",
Usage: "Output man pages instead", Usage: "Output man pages instead",
},
&cli.StringFlag{
Name: "output",
Aliases: []string{"o"},
Usage: "Path to output to instead of stdout (will overwrite if exists)",
},
}, },
} &cli.StringFlag{
Name: "output",
Aliases: []string{"o"},
Usage: "Path to output to instead of stdout (will overwrite if exists)",
},
},
} }
func runDocs(_ context.Context, cmd *cli.Command) error { func runDocs(_ context.Context, cmd *cli.Command) error {

View File

@@ -24,77 +24,73 @@ import (
"xorm.io/xorm" "xorm.io/xorm"
) )
func newDoctorCommand() *cli.Command { // CmdDoctor represents the available doctor sub-command.
return &cli.Command{ var CmdDoctor = &cli.Command{
Name: "doctor", Name: "doctor",
Usage: "Diagnose and optionally fix problems, convert or re-create database tables", Usage: "Diagnose and optionally fix problems, convert or re-create database tables",
Description: "A command to diagnose problems with the current Gitea instance according to the given configuration. Some problems can optionally be fixed by modifying the database or data storage.", Description: "A command to diagnose problems with the current Gitea instance according to the given configuration. Some problems can optionally be fixed by modifying the database or data storage.",
Commands: []*cli.Command{
newDoctorCheckCommand(), Commands: []*cli.Command{
newRecreateTableCommand(), cmdDoctorCheck,
newDoctorConvertCommand(), cmdRecreateTable,
}, cmdDoctorConvert,
} },
} }
func newDoctorCheckCommand() *cli.Command { var cmdDoctorCheck = &cli.Command{
return &cli.Command{ Name: "check",
Name: "check", Usage: "Diagnose and optionally fix problems",
Usage: "Diagnose and optionally fix problems", Description: "A command to diagnose problems with the current Gitea instance according to the given configuration. Some problems can optionally be fixed by modifying the database or data storage.",
Description: "A command to diagnose problems with the current Gitea instance according to the given configuration. Some problems can optionally be fixed by modifying the database or data storage.", Action: runDoctorCheck,
Action: runDoctorCheck, Flags: []cli.Flag{
Flags: []cli.Flag{ &cli.BoolFlag{
&cli.BoolFlag{ Name: "list",
Name: "list", Usage: "List the available checks",
Usage: "List the available checks",
},
&cli.BoolFlag{
Name: "default",
Usage: "Run the default checks (if neither --run or --all is set, this is the default behaviour)",
},
&cli.StringSliceFlag{
Name: "run",
Usage: "Run the provided checks - (if --default is set, the default checks will also run)",
},
&cli.BoolFlag{
Name: "all",
Usage: "Run all the available checks",
},
&cli.BoolFlag{
Name: "fix",
Usage: "Automatically fix what we can",
},
&cli.StringFlag{
Name: "log-file",
Usage: `Name of the log file (no verbose log output by default). Set to "-" to output to stdout`,
},
&cli.BoolFlag{
Name: "color",
Aliases: []string{"H"},
Usage: "Use color for outputted information",
},
}, },
} &cli.BoolFlag{
Name: "default",
Usage: "Run the default checks (if neither --run or --all is set, this is the default behaviour)",
},
&cli.StringSliceFlag{
Name: "run",
Usage: "Run the provided checks - (if --default is set, the default checks will also run)",
},
&cli.BoolFlag{
Name: "all",
Usage: "Run all the available checks",
},
&cli.BoolFlag{
Name: "fix",
Usage: "Automatically fix what we can",
},
&cli.StringFlag{
Name: "log-file",
Usage: `Name of the log file (no verbose log output by default). Set to "-" to output to stdout`,
},
&cli.BoolFlag{
Name: "color",
Aliases: []string{"H"},
Usage: "Use color for outputted information",
},
},
} }
func newRecreateTableCommand() *cli.Command { var cmdRecreateTable = &cli.Command{
return &cli.Command{ Name: "recreate-table",
Name: "recreate-table", Usage: "Recreate tables from XORM definitions and copy the data.",
Usage: "Recreate tables from XORM definitions and copy the data.", ArgsUsage: "[TABLE]... : (TABLEs to recreate - leave blank for all)",
ArgsUsage: "[TABLE]... : (TABLEs to recreate - leave blank for all)", Flags: []cli.Flag{
Flags: []cli.Flag{ &cli.BoolFlag{
&cli.BoolFlag{ Name: "debug",
Name: "debug", Usage: "Print SQL commands sent",
Usage: "Print SQL commands sent",
},
}, },
Description: `The database definitions Gitea uses change across versions, sometimes changing default values and leaving old unused columns. },
Description: `The database definitions Gitea uses change across versions, sometimes changing default values and leaving old unused columns.
This command will cause Xorm to recreate tables, copying over the data and deleting the old table. This command will cause Xorm to recreate tables, copying over the data and deleting the old table.
You should back-up your database before doing this and ensure that your database is up-to-date first.`, You should back-up your database before doing this and ensure that your database is up-to-date first.`,
Action: runRecreateTable, Action: runRecreateTable,
}
} }
func runRecreateTable(ctx context.Context, cmd *cli.Command) error { func runRecreateTable(ctx context.Context, cmd *cli.Command) error {

View File

@@ -14,13 +14,12 @@ import (
"github.com/urfave/cli/v3" "github.com/urfave/cli/v3"
) )
func newDoctorConvertCommand() *cli.Command { // cmdDoctorConvert represents the available convert sub-command.
return &cli.Command{ var cmdDoctorConvert = &cli.Command{
Name: "convert", Name: "convert",
Usage: "Convert the database", Usage: "Convert the database",
Description: "A command to convert an existing MySQL database from utf8 to utf8mb4 or MSSQL database from varchar to nvarchar", Description: "A command to convert an existing MySQL database from utf8 to utf8mb4 or MSSQL database from varchar to nvarchar",
Action: runDoctorConvert, Action: runDoctorConvert,
}
} }
func runDoctorConvert(ctx context.Context, cmd *cli.Command) error { func runDoctorConvert(ctx context.Context, cmd *cli.Command) error {

View File

@@ -23,7 +23,7 @@ func TestDoctorRun(t *testing.T) {
SkipDatabaseInitialization: true, SkipDatabaseInitialization: true,
}) })
app := &cli.Command{ app := &cli.Command{
Commands: []*cli.Command{newDoctorCheckCommand()}, Commands: []*cli.Command{cmdDoctorCheck},
} }
err := app.Run(t.Context(), []string{"./gitea", "check", "--run", "test-check"}) err := app.Run(t.Context(), []string{"./gitea", "check", "--run", "test-check"})
assert.NoError(t, err) assert.NoError(t, err)

View File

@@ -23,79 +23,78 @@ import (
"github.com/urfave/cli/v3" "github.com/urfave/cli/v3"
) )
func newDumpCommand() *cli.Command { // CmdDump represents the available dump sub-command.
return &cli.Command{ var CmdDump = &cli.Command{
Name: "dump", Name: "dump",
Usage: "Dump Gitea files and database", Usage: "Dump Gitea files and database",
Description: `Dump compresses all related files and database into zip file. It can be used for backup and capture Gitea server image to send to maintainer`, Description: `Dump compresses all related files and database into zip file. It can be used for backup and capture Gitea server image to send to maintainer`,
Action: runDump, Action: runDump,
Flags: []cli.Flag{ Flags: []cli.Flag{
&cli.StringFlag{ &cli.StringFlag{
Name: "file", Name: "file",
Aliases: []string{"f"}, Aliases: []string{"f"},
Usage: `Name of the dump file which will be created, default to "gitea-dump-{time}.zip". Supply '-' for stdout. See type for available types.`, Usage: `Name of the dump file which will be created, default to "gitea-dump-{time}.zip". Supply '-' for stdout. See type for available types.`,
},
&cli.BoolFlag{
Name: "verbose",
Aliases: []string{"V"},
Usage: "Show process details",
},
&cli.BoolFlag{
Name: "quiet",
Aliases: []string{"q"},
Usage: "Only display warnings and errors",
},
&cli.StringFlag{
Name: "tempdir",
Aliases: []string{"t"},
Value: os.TempDir(),
Usage: "Temporary dir path",
},
&cli.StringFlag{
Name: "database",
Aliases: []string{"d"},
Usage: "Specify the database SQL syntax: sqlite3, mysql, mssql, postgres",
},
&cli.BoolFlag{
Name: "skip-repository",
Aliases: []string{"R"},
Usage: "Skip the repository dumping",
},
&cli.BoolFlag{
Name: "skip-log",
Aliases: []string{"L"},
Usage: "Skip the log dumping",
},
&cli.BoolFlag{
Name: "skip-custom-dir",
Usage: "Skip custom directory",
},
&cli.BoolFlag{
Name: "skip-lfs-data",
Usage: "Skip LFS data",
},
&cli.BoolFlag{
Name: "skip-attachment-data",
Usage: "Skip attachment data",
},
&cli.BoolFlag{
Name: "skip-package-data",
Usage: "Skip package data",
},
&cli.BoolFlag{
Name: "skip-index",
Usage: "Skip bleve index data",
},
&cli.BoolFlag{
Name: "skip-db",
Usage: "Skip database",
},
&cli.StringFlag{
Name: "type",
Usage: `Dump output format, default to "zip", supported types: ` + strings.Join(dump.SupportedOutputTypes, ", "),
},
}, },
} &cli.BoolFlag{
Name: "verbose",
Aliases: []string{"V"},
Usage: "Show process details",
},
&cli.BoolFlag{
Name: "quiet",
Aliases: []string{"q"},
Usage: "Only display warnings and errors",
},
&cli.StringFlag{
Name: "tempdir",
Aliases: []string{"t"},
Value: os.TempDir(),
Usage: "Temporary dir path",
},
&cli.StringFlag{
Name: "database",
Aliases: []string{"d"},
Usage: "Specify the database SQL syntax: sqlite3, mysql, mssql, postgres",
},
&cli.BoolFlag{
Name: "skip-repository",
Aliases: []string{"R"},
Usage: "Skip the repository dumping",
},
&cli.BoolFlag{
Name: "skip-log",
Aliases: []string{"L"},
Usage: "Skip the log dumping",
},
&cli.BoolFlag{
Name: "skip-custom-dir",
Usage: "Skip custom directory",
},
&cli.BoolFlag{
Name: "skip-lfs-data",
Usage: "Skip LFS data",
},
&cli.BoolFlag{
Name: "skip-attachment-data",
Usage: "Skip attachment data",
},
&cli.BoolFlag{
Name: "skip-package-data",
Usage: "Skip package data",
},
&cli.BoolFlag{
Name: "skip-index",
Usage: "Skip bleve index data",
},
&cli.BoolFlag{
Name: "skip-db",
Usage: "Skip database",
},
&cli.StringFlag{
Name: "type",
Usage: `Dump output format, default to "zip", supported types: ` + strings.Join(dump.SupportedOutputTypes, ", "),
},
},
} }
func fatal(format string, args ...any) { func fatal(format string, args ...any) {

View File

@@ -22,62 +22,61 @@ import (
"github.com/urfave/cli/v3" "github.com/urfave/cli/v3"
) )
func newDumpRepositoryCommand() *cli.Command { // CmdDumpRepository represents the available dump repository sub-command.
return &cli.Command{ var CmdDumpRepository = &cli.Command{
Name: "dump-repo", Name: "dump-repo",
Usage: "Dump the repository from git/github/gitea/gitlab", Usage: "Dump the repository from git/github/gitea/gitlab",
Description: "This is a command for dumping the repository data.", Description: "This is a command for dumping the repository data.",
Action: runDumpRepository, Action: runDumpRepository,
Flags: []cli.Flag{ Flags: []cli.Flag{
&cli.StringFlag{ &cli.StringFlag{
Name: "git_service", Name: "git_service",
Value: "", Value: "",
Usage: "Git service, git, github, gitea, gitlab. If clone_addr could be recognized, this could be ignored.", Usage: "Git service, git, github, gitea, gitlab. If clone_addr could be recognized, this could be ignored.",
},
&cli.StringFlag{
Name: "repo_dir",
Aliases: []string{"r"},
Value: "./data",
Usage: "Repository dir path to store the data",
},
&cli.StringFlag{
Name: "clone_addr",
Value: "",
Usage: "The URL will be clone, currently could be a git/github/gitea/gitlab http/https URL",
},
&cli.StringFlag{
Name: "auth_username",
Value: "",
Usage: "The username to visit the clone_addr",
},
&cli.StringFlag{
Name: "auth_password",
Value: "",
Usage: "The password to visit the clone_addr",
},
&cli.StringFlag{
Name: "auth_token",
Value: "",
Usage: "The personal token to visit the clone_addr",
},
&cli.StringFlag{
Name: "owner_name",
Value: "",
Usage: "The data will be stored on a directory with owner name if not empty",
},
&cli.StringFlag{
Name: "repo_name",
Value: "",
Usage: "The data will be stored on a directory with repository name if not empty",
},
&cli.StringFlag{
Name: "units",
Value: "",
Usage: `Which items will be migrated, one or more units should be separated as comma.
wiki, issues, labels, releases, release_assets, milestones, pull_requests, comments are allowed. Empty means all units.`,
},
}, },
} &cli.StringFlag{
Name: "repo_dir",
Aliases: []string{"r"},
Value: "./data",
Usage: "Repository dir path to store the data",
},
&cli.StringFlag{
Name: "clone_addr",
Value: "",
Usage: "The URL will be clone, currently could be a git/github/gitea/gitlab http/https URL",
},
&cli.StringFlag{
Name: "auth_username",
Value: "",
Usage: "The username to visit the clone_addr",
},
&cli.StringFlag{
Name: "auth_password",
Value: "",
Usage: "The password to visit the clone_addr",
},
&cli.StringFlag{
Name: "auth_token",
Value: "",
Usage: "The personal token to visit the clone_addr",
},
&cli.StringFlag{
Name: "owner_name",
Value: "",
Usage: "The data will be stored on a directory with owner name if not empty",
},
&cli.StringFlag{
Name: "repo_name",
Value: "",
Usage: "The data will be stored on a directory with repository name if not empty",
},
&cli.StringFlag{
Name: "units",
Value: "",
Usage: `Which items will be migrated, one or more units should be separated as comma.
wiki, issues, labels, releases, release_assets, milestones, pull_requests, comments are allowed. Empty means all units.`,
},
},
} }
func runDumpRepository(ctx context.Context, cmd *cli.Command) error { func runDumpRepository(ctx context.Context, cmd *cli.Command) error {

View File

@@ -23,23 +23,20 @@ import (
"github.com/urfave/cli/v3" "github.com/urfave/cli/v3"
) )
var matchedAssetFiles []assetFile // CmdEmbedded represents the available extract sub-command.
var (
func newEmbeddedCommand() *cli.Command { CmdEmbedded = &cli.Command{
return &cli.Command{
Name: "embedded", Name: "embedded",
Usage: "Extract embedded resources", Usage: "Extract embedded resources",
Description: "A command for extracting embedded resources, like templates and images", Description: "A command for extracting embedded resources, like templates and images",
Commands: []*cli.Command{ Commands: []*cli.Command{
newEmbeddedListCommand(), subcmdList,
newEmbeddedViewCommand(), subcmdView,
newEmbeddedExtractCommand(), subcmdExtract,
}, },
} }
}
func newEmbeddedListCommand() *cli.Command { subcmdList = &cli.Command{
return &cli.Command{
Name: "list", Name: "list",
Usage: "List files matching the given pattern", Usage: "List files matching the given pattern",
Action: runList, Action: runList,
@@ -51,10 +48,8 @@ func newEmbeddedListCommand() *cli.Command {
}, },
}, },
} }
}
func newEmbeddedViewCommand() *cli.Command { subcmdView = &cli.Command{
return &cli.Command{
Name: "view", Name: "view",
Usage: "View a file matching the given pattern", Usage: "View a file matching the given pattern",
Action: runView, Action: runView,
@@ -66,10 +61,8 @@ func newEmbeddedViewCommand() *cli.Command {
}, },
}, },
} }
}
func newEmbeddedExtractCommand() *cli.Command { subcmdExtract = &cli.Command{
return &cli.Command{
Name: "extract", Name: "extract",
Usage: "Extract resources", Usage: "Extract resources",
Action: runExtract, Action: runExtract,
@@ -98,7 +91,9 @@ func newEmbeddedExtractCommand() *cli.Command {
}, },
}, },
} }
}
matchedAssetFiles []assetFile
)
type assetFile struct { type assetFile struct {
fs *assetfs.LayeredFS fs *assetfs.LayeredFS

View File

@@ -15,52 +15,45 @@ import (
"github.com/urfave/cli/v3" "github.com/urfave/cli/v3"
) )
func newGenerateCommand() *cli.Command { var (
return &cli.Command{ // CmdGenerate represents the available generate sub-command.
CmdGenerate = &cli.Command{
Name: "generate", Name: "generate",
Usage: "Generate Gitea's secrets/keys/tokens", Usage: "Generate Gitea's secrets/keys/tokens",
Commands: []*cli.Command{ Commands: []*cli.Command{
newGenerateSecretCommand(), subcmdSecret,
}, },
} }
}
func newGenerateSecretCommand() *cli.Command { subcmdSecret = &cli.Command{
return &cli.Command{
Name: "secret", Name: "secret",
Usage: "Generate a secret token", Usage: "Generate a secret token",
Commands: []*cli.Command{ Commands: []*cli.Command{
newGenerateInternalTokenCommand(), microcmdGenerateInternalToken,
newGenerateLfsJWTSecretCommand(), microcmdGenerateLfsJwtSecret,
newGenerateSecretKeyCommand(), microcmdGenerateSecretKey,
}, },
} }
}
func newGenerateInternalTokenCommand() *cli.Command { microcmdGenerateInternalToken = &cli.Command{
return &cli.Command{
Name: "INTERNAL_TOKEN", Name: "INTERNAL_TOKEN",
Usage: "Generate a new INTERNAL_TOKEN", Usage: "Generate a new INTERNAL_TOKEN",
Action: runGenerateInternalToken, Action: runGenerateInternalToken,
} }
}
func newGenerateLfsJWTSecretCommand() *cli.Command { microcmdGenerateLfsJwtSecret = &cli.Command{
return &cli.Command{
Name: "JWT_SECRET", Name: "JWT_SECRET",
Aliases: []string{"LFS_JWT_SECRET"}, Aliases: []string{"LFS_JWT_SECRET"},
Usage: "Generate a new JWT_SECRET", Usage: "Generate a new JWT_SECRET",
Action: runGenerateLfsJwtSecret, Action: runGenerateLfsJwtSecret,
} }
}
func newGenerateSecretKeyCommand() *cli.Command { microcmdGenerateSecretKey = &cli.Command{
return &cli.Command{
Name: "SECRET_KEY", Name: "SECRET_KEY",
Usage: "Generate a new SECRET_KEY", Usage: "Generate a new SECRET_KEY",
Action: runGenerateSecretKey, Action: runGenerateSecretKey,
} }
} )
func runGenerateInternalToken(_ context.Context, c *cli.Command) error { func runGenerateInternalToken(_ context.Context, c *cli.Command) error {
internalToken, err := generate.NewInternalToken() internalToken, err := generate.NewInternalToken()
@@ -78,7 +71,11 @@ func runGenerateInternalToken(_ context.Context, c *cli.Command) error {
} }
func runGenerateLfsJwtSecret(_ context.Context, c *cli.Command) error { func runGenerateLfsJwtSecret(_ context.Context, c *cli.Command) error {
_, jwtSecretBase64 := generate.NewJwtSecretWithBase64() _, jwtSecretBase64, err := generate.NewJwtSecretWithBase64()
if err != nil {
return err
}
fmt.Printf("%s", jwtSecretBase64) fmt.Printf("%s", jwtSecretBase64)
if isatty.IsTerminal(os.Stdout.Fd()) { if isatty.IsTerminal(os.Stdout.Fd()) {
@@ -94,7 +91,6 @@ func runGenerateSecretKey(_ context.Context, c *cli.Command) error {
return err return err
} }
// codeql[disable-next-line=go/clear-text-logging]
fmt.Printf("%s", secretKey) fmt.Printf("%s", secretKey)
if isatty.IsTerminal(os.Stdout.Fd()) { if isatty.IsTerminal(os.Stdout.Fd()) {

View File

@@ -28,24 +28,23 @@ const (
hookBatchSize = 500 hookBatchSize = 500
) )
func newHookCommand() *cli.Command { var (
return &cli.Command{ // CmdHook represents the available hooks sub-command.
CmdHook = &cli.Command{
Name: "hook", Name: "hook",
Usage: "(internal) Should only be called by Git", Usage: "(internal) Should only be called by Git",
Hidden: true, // internal commands shouldn't be visible Hidden: true, // internal commands shouldn't be visible
Description: "Delegate commands to corresponding Git hooks", Description: "Delegate commands to corresponding Git hooks",
Before: PrepareConsoleLoggerLevel(log.FATAL), Before: PrepareConsoleLoggerLevel(log.FATAL),
Commands: []*cli.Command{ Commands: []*cli.Command{
newHookPreReceiveCommand(), subcmdHookPreReceive,
newHookUpdateCommand(), subcmdHookUpdate,
newHookPostReceiveCommand(), subcmdHookPostReceive,
newHookProcReceiveCommand(), subcmdHookProcReceive,
}, },
} }
}
func newHookPreReceiveCommand() *cli.Command { subcmdHookPreReceive = &cli.Command{
return &cli.Command{
Name: "pre-receive", Name: "pre-receive",
Usage: "Delegate pre-receive Git hook", Usage: "Delegate pre-receive Git hook",
Description: "This command should only be called by Git", Description: "This command should only be called by Git",
@@ -56,10 +55,7 @@ func newHookPreReceiveCommand() *cli.Command {
}, },
}, },
} }
} subcmdHookUpdate = &cli.Command{
func newHookUpdateCommand() *cli.Command {
return &cli.Command{
Name: "update", Name: "update",
Usage: "Delegate update Git hook", Usage: "Delegate update Git hook",
Description: "This command should only be called by Git", Description: "This command should only be called by Git",
@@ -70,10 +66,7 @@ func newHookUpdateCommand() *cli.Command {
}, },
}, },
} }
} subcmdHookPostReceive = &cli.Command{
func newHookPostReceiveCommand() *cli.Command {
return &cli.Command{
Name: "post-receive", Name: "post-receive",
Usage: "Delegate post-receive Git hook", Usage: "Delegate post-receive Git hook",
Description: "This command should only be called by Git", Description: "This command should only be called by Git",
@@ -84,11 +77,8 @@ func newHookPostReceiveCommand() *cli.Command {
}, },
}, },
} }
} // Note: new hook since git 2.29
subcmdHookProcReceive = &cli.Command{
// Note: new hook since git 2.29
func newHookProcReceiveCommand() *cli.Command {
return &cli.Command{
Name: "proc-receive", Name: "proc-receive",
Usage: "Delegate proc-receive Git hook", Usage: "Delegate proc-receive Git hook",
Description: "This command should only be called by Git", Description: "This command should only be called by Git",
@@ -99,7 +89,7 @@ func newHookProcReceiveCommand() *cli.Command {
}, },
}, },
} }
} )
type delayWriter struct { type delayWriter struct {
internal io.Writer internal io.Writer
@@ -173,14 +163,6 @@ func (n *nilWriter) WriteString(s string) (int, error) {
return len(s), nil return len(s), nil
} }
func parseGitHookCommitRefLine(line string) (oldCommitID, newCommitID string, refFullName git.RefName, ok bool) {
fields := strings.Split(line, " ")
if len(fields) != 3 {
return "", "", "", false
}
return fields[0], fields[1], git.RefName(fields[2]), true
}
func runHookPreReceive(ctx context.Context, c *cli.Command) error { func runHookPreReceive(ctx context.Context, c *cli.Command) error {
if isInternal, _ := strconv.ParseBool(os.Getenv(repo_module.EnvIsInternal)); isInternal { if isInternal, _ := strconv.ParseBool(os.Getenv(repo_module.EnvIsInternal)); isInternal {
return nil return nil
@@ -204,7 +186,7 @@ Gitea or set your environment appropriately.`, "")
userID, _ := strconv.ParseInt(os.Getenv(repo_module.EnvPusherID), 10, 64) userID, _ := strconv.ParseInt(os.Getenv(repo_module.EnvPusherID), 10, 64)
prID, _ := strconv.ParseInt(os.Getenv(repo_module.EnvPRID), 10, 64) prID, _ := strconv.ParseInt(os.Getenv(repo_module.EnvPRID), 10, 64)
deployKeyID, _ := strconv.ParseInt(os.Getenv(repo_module.EnvDeployKeyID), 10, 64) deployKeyID, _ := strconv.ParseInt(os.Getenv(repo_module.EnvDeployKeyID), 10, 64)
actionsTaskID, _ := strconv.ParseInt(os.Getenv(repo_module.EnvActionsTaskID), 10, 64) actionPerm, _ := strconv.ParseInt(os.Getenv(repo_module.EnvActionPerm), 10, 64)
hookOptions := private.HookOptions{ hookOptions := private.HookOptions{
UserID: userID, UserID: userID,
@@ -214,8 +196,7 @@ Gitea or set your environment appropriately.`, "")
GitPushOptions: pushOptions(), GitPushOptions: pushOptions(),
PullRequestID: prID, PullRequestID: prID,
DeployKeyID: deployKeyID, DeployKeyID: deployKeyID,
ActionsTaskID: actionsTaskID, ActionPerm: int(actionPerm),
IsWiki: isWiki,
} }
scanner := bufio.NewScanner(os.Stdin) scanner := bufio.NewScanner(os.Stdin)
@@ -247,11 +228,14 @@ Gitea or set your environment appropriately.`, "")
continue continue
} }
oldCommitID, newCommitID, refFullName, ok := parseGitHookCommitRefLine(scanner.Text()) fields := bytes.Fields(scanner.Bytes())
if !ok { if len(fields) != 3 {
continue continue
} }
oldCommitID := string(fields[0])
newCommitID := string(fields[1])
refFullName := git.RefName(fields[2])
total++ total++
lastline++ lastline++
@@ -286,9 +270,6 @@ Gitea or set your environment appropriately.`, "")
lastline = 0 lastline = 0
} }
} }
if err := scanner.Err(); err != nil {
return fail(ctx, "Hook failed: stdin read error", "scanner error: %v", err)
}
if count > 0 { if count > 0 {
hookOptions.OldCommitIDs = oldCommitIDs[:count] hookOptions.OldCommitIDs = oldCommitIDs[:count]
@@ -332,7 +313,7 @@ func runHookPostReceive(ctx context.Context, c *cli.Command) 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 := gitcmd.NewCommand("update-server-info").RunWithStderr(ctx); err != nil { if _, _, err := gitcmd.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)
} }
@@ -380,7 +361,6 @@ Gitea or set your environment appropriately.`, "")
GitPushOptions: pushOptions(), GitPushOptions: pushOptions(),
PullRequestID: prID, PullRequestID: prID,
PushTrigger: repo_module.PushTrigger(os.Getenv(repo_module.EnvPushTrigger)), PushTrigger: repo_module.PushTrigger(os.Getenv(repo_module.EnvPushTrigger)),
IsWiki: isWiki,
} }
oldCommitIDs := make([]string, hookBatchSize) oldCommitIDs := make([]string, hookBatchSize)
newCommitIDs := make([]string, hookBatchSize) newCommitIDs := make([]string, hookBatchSize)
@@ -398,13 +378,16 @@ Gitea or set your environment appropriately.`, "")
continue continue
} }
var ok bool fields := bytes.Fields(scanner.Bytes())
oldCommitIDs[count], newCommitIDs[count], refFullNames[count], ok = parseGitHookCommitRefLine(scanner.Text()) if len(fields) != 3 {
if !ok {
continue continue
} }
fmt.Fprintf(out, ".") fmt.Fprintf(out, ".")
oldCommitIDs[count] = string(fields[0])
newCommitIDs[count] = string(fields[1])
refFullNames[count] = git.RefName(fields[2])
commitID, _ := git.NewIDFromString(newCommitIDs[count]) commitID, _ := git.NewIDFromString(newCommitIDs[count])
if refFullNames[count] == git.BranchPrefix+"master" && !commitID.IsZero() && count == total { if refFullNames[count] == git.BranchPrefix+"master" && !commitID.IsZero() && count == total {
masterPushed = true masterPushed = true
@@ -428,11 +411,6 @@ Gitea or set your environment appropriately.`, "")
count = 0 count = 0
} }
} }
if err := scanner.Err(); err != nil {
_ = dWriter.Close()
hookPrintResults(results)
return fail(ctx, "Hook failed: stdin read error", "scanner error: %v", err)
}
if count == 0 { if count == 0 {
if wasEmpty && masterPushed { if wasEmpty && masterPushed {
@@ -533,7 +511,6 @@ Gitea or set your environment appropriately.`, "")
reader := bufio.NewReader(os.Stdin) reader := bufio.NewReader(os.Stdin)
repoUser := os.Getenv(repo_module.EnvRepoUsername) repoUser := os.Getenv(repo_module.EnvRepoUsername)
isWiki, _ := strconv.ParseBool(os.Getenv(repo_module.EnvRepoIsWiki))
repoName := os.Getenv(repo_module.EnvRepoName) repoName := os.Getenv(repo_module.EnvRepoName)
pusherID, _ := strconv.ParseInt(os.Getenv(repo_module.EnvPusherID), 10, 64) pusherID, _ := strconv.ParseInt(os.Getenv(repo_module.EnvPusherID), 10, 64)
pusherName := os.Getenv(repo_module.EnvPusherName) pusherName := os.Getenv(repo_module.EnvPusherName)
@@ -611,15 +588,14 @@ Gitea or set your environment appropriately.`, "")
UserName: pusherName, UserName: pusherName,
UserID: pusherID, UserID: pusherID,
GitPushOptions: make(map[string]string), GitPushOptions: make(map[string]string),
IsWiki: isWiki,
} }
hookOptions.OldCommitIDs = make([]string, 0, hookBatchSize) hookOptions.OldCommitIDs = make([]string, 0, hookBatchSize)
hookOptions.NewCommitIDs = make([]string, 0, hookBatchSize) hookOptions.NewCommitIDs = make([]string, 0, hookBatchSize)
hookOptions.RefFullNames = make([]git.RefName, 0, hookBatchSize) hookOptions.RefFullNames = make([]git.RefName, 0, hookBatchSize)
for { for {
// note: pktLineTypeUnknown means pktLineTypeFlush and pktLineTypeData all allowed // note: pktLineTypeUnknow means pktLineTypeFlush and pktLineTypeData all allowed
rs, err = readPktLine(ctx, reader, pktLineTypeUnknown) rs, err = readPktLine(ctx, reader, pktLineTypeUnknow)
if err != nil { if err != nil {
return err return err
} }
@@ -638,7 +614,7 @@ Gitea or set your environment appropriately.`, "")
if hasPushOptions { if hasPushOptions {
for { for {
rs, err = readPktLine(ctx, reader, pktLineTypeUnknown) rs, err = readPktLine(ctx, reader, pktLineTypeUnknow)
if err != nil { if err != nil {
return err return err
} }
@@ -735,8 +711,8 @@ Gitea or set your environment appropriately.`, "")
type pktLineType int64 type pktLineType int64
const ( const (
// Unknown type // UnKnow type
pktLineTypeUnknown pktLineType = 0 pktLineTypeUnknow pktLineType = 0
// flush-pkt "0000" // flush-pkt "0000"
pktLineTypeFlush pktLineType = iota pktLineTypeFlush pktLineType = iota
// data line // data line

View File

@@ -39,17 +39,3 @@ func TestPktLine(t *testing.T) {
assert.NoError(t, err) assert.NoError(t, err)
assert.Equal(t, []byte("0007a\nb"), w.Bytes()) assert.Equal(t, []byte("0007a\nb"), w.Bytes())
} }
func TestParseGitHookCommitRefLine(t *testing.T) {
oldCommitID, newCommitID, refName, ok := parseGitHookCommitRefLine("a b c")
assert.True(t, ok)
assert.Equal(t, "a", oldCommitID)
assert.Equal(t, "b", newCommitID)
assert.Equal(t, "c", string(refName))
_, _, _, ok = parseGitHookCommitRefLine("a\tb\tc")
assert.False(t, ok)
_, _, _, ok = parseGitHookCommitRefLine("a b")
assert.False(t, ok)
}

View File

@@ -15,42 +15,40 @@ import (
"github.com/urfave/cli/v3" "github.com/urfave/cli/v3"
) )
// NewKeysCommand returns the internal SSH key lookup sub-command. // CmdKeys represents the available keys sub-command
func NewKeysCommand() *cli.Command { var CmdKeys = &cli.Command{
return &cli.Command{ Name: "keys",
Name: "keys", Usage: "(internal) Should only be called by SSH server",
Usage: "(internal) Should only be called by SSH server", Hidden: true, // internal commands shouldn't be visible
Hidden: true, // internal commands shouldn't be visible Description: "Queries the Gitea database to get the authorized command for a given ssh key fingerprint",
Description: "Queries the Gitea database to get the authorized command for a given ssh key fingerprint", Before: PrepareConsoleLoggerLevel(log.FATAL),
Before: PrepareConsoleLoggerLevel(log.FATAL), Action: runKeys,
Action: runKeys, Flags: []cli.Flag{
Flags: []cli.Flag{ &cli.StringFlag{
&cli.StringFlag{ Name: "expected",
Name: "expected", Aliases: []string{"e"},
Aliases: []string{"e"}, Value: "git",
Value: "git", Usage: "Expected user for whom provide key commands",
Usage: "Expected user for whom provide key commands",
},
&cli.StringFlag{
Name: "username",
Aliases: []string{"u"},
Value: "",
Usage: "Username trying to log in by SSH",
},
&cli.StringFlag{
Name: "type",
Aliases: []string{"t"},
Value: "",
Usage: "Type of the SSH key provided to the SSH Server (requires content to be provided too)",
},
&cli.StringFlag{
Name: "content",
Aliases: []string{"k"},
Value: "",
Usage: "Base64 encoded content of the SSH key provided to the SSH Server (requires type to be provided too)",
},
}, },
} &cli.StringFlag{
Name: "username",
Aliases: []string{"u"},
Value: "",
Usage: "Username trying to log in by SSH",
},
&cli.StringFlag{
Name: "type",
Aliases: []string{"t"},
Value: "",
Usage: "Type of the SSH key provided to the SSH Server (requires content to be provided too)",
},
&cli.StringFlag{
Name: "content",
Aliases: []string{"k"},
Value: "",
Usage: "Base64 encoded content of the SSH key provided to the SSH Server (requires type to be provided too)",
},
},
} }
func runKeys(ctx context.Context, c *cli.Command) error { func runKeys(ctx context.Context, c *cli.Command) error {

View File

@@ -17,10 +17,10 @@ func runSendMail(ctx context.Context, c *cli.Command) error {
setting.MustInstalled() setting.MustInstalled()
subject := c.String("title") subject := c.String("title")
confirmSkipped := c.Bool("force") confirmSkiped := c.Bool("force")
body := c.String("content") body := c.String("content")
if !confirmSkipped { if !confirmSkiped {
if len(body) == 0 { if len(body) == 0 {
fmt.Print("warning: Content is empty") fmt.Print("warning: Content is empty")
} }

View File

@@ -112,36 +112,34 @@ func NewMainApp(appVer AppVersion) *cli.Command {
Usage: "Set custom path (defaults to '{WorkPath}/custom')", Usage: "Set custom path (defaults to '{WorkPath}/custom')",
}, },
} }
webCmd := newWebCommand()
// these sub-commands need to use a config file // these sub-commands need to use a config file
subCmdWithConfig := []*cli.Command{ subCmdWithConfig := []*cli.Command{
webCmd, CmdWeb,
newServCommand(), CmdServ,
newHookCommand(), CmdHook,
NewKeysCommand(), CmdKeys,
newDumpCommand(), CmdDump,
newAdminCommand(), CmdAdmin,
newMigrateCommand(), CmdMigrate,
newDoctorCommand(), CmdDoctor,
newManagerCommand(), CmdManager,
newEmbeddedCommand(), CmdEmbedded,
newMigrateStorageCommand(), CmdMigrateStorage,
newDumpRepositoryCommand(), CmdDumpRepository,
newRestoreRepositoryCommand(), CmdRestoreRepository,
newActionsCommand(), CmdActions,
} }
// these sub-commands do not need the config file, and they do not depend on any path or environment variable. // these sub-commands do not need the config file, and they do not depend on any path or environment variable.
subCmdStandalone := []*cli.Command{ subCmdStandalone := []*cli.Command{
cmdConfig(),
cmdCert(), cmdCert(),
newGenerateCommand(), CmdGenerate,
newDocsCommand(), CmdDocs,
} }
// TODO: we should eventually drop the default command, // TODO: we should eventually drop the default command,
// but not sure whether it would break Windows users who used to double-click the EXE to run. // but not sure whether it would break Windows users who used to double-click the EXE to run.
app.DefaultCommand = webCmd.Name app.DefaultCommand = CmdWeb.Name
app.Before = PrepareConsoleLoggerLevel(log.INFO) app.Before = PrepareConsoleLoggerLevel(log.INFO)
for i := range subCmdWithConfig { for i := range subCmdWithConfig {
@@ -150,7 +148,7 @@ func NewMainApp(appVer AppVersion) *cli.Command {
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.UnsetUnnecessaryEnvVars() setting.InitGiteaEnvVars()
return app return app
} }

View File

@@ -157,7 +157,6 @@ func TestCliCmd(t *testing.T) {
for _, c := range cases { for _, c := range cases {
t.Run(c.cmd, func(t *testing.T) { t.Run(c.cmd, func(t *testing.T) {
defer test.MockVariableValue(&setting.InstallLock, false)()
app := newTestApp(cli.Command{ app := newTestApp(cli.Command{
Action: func(ctx context.Context, cmd *cli.Command) error { Action: func(ctx context.Context, cmd *cli.Command) error {
_, _ = fmt.Fprint(cmd.Root().Writer, makePathOutput(setting.AppWorkPath, setting.CustomPath, setting.CustomConf)) _, _ = fmt.Fprint(cmd.Root().Writer, makePathOutput(setting.AppWorkPath, setting.CustomPath, setting.CustomConf))
@@ -171,10 +170,7 @@ func TestCliCmd(t *testing.T) {
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)
if !assert.Contains(t, r.Stdout, c.exp, c.cmd) { assert.Contains(t, r.Stdout, c.exp, c.cmd)
t.Log("Full output:\n" + r.Stdout)
t.Log("Expected:\n" + c.exp)
}
}) })
} }
} }

View File

@@ -13,24 +13,22 @@ import (
"github.com/urfave/cli/v3" "github.com/urfave/cli/v3"
) )
func newManagerCommand() *cli.Command { var (
return &cli.Command{ // CmdManager represents the manager command
CmdManager = &cli.Command{
Name: "manager", Name: "manager",
Usage: "Manage the running gitea process", Usage: "Manage the running gitea process",
Description: "This is a command for managing the running gitea process", Description: "This is a command for managing the running gitea process",
Commands: []*cli.Command{ Commands: []*cli.Command{
newShutdownCommand(), subcmdShutdown,
newRestartCommand(), subcmdRestart,
newReloadTemplatesCommand(), subcmdReloadTemplates,
newFlushQueuesCommand(), subcmdFlushQueues,
newLoggingCommand(), subcmdLogging,
newProcessesCommand(), subCmdProcesses,
}, },
} }
} subcmdShutdown = &cli.Command{
func newShutdownCommand() *cli.Command {
return &cli.Command{
Name: "shutdown", Name: "shutdown",
Usage: "Gracefully shutdown the running process", Usage: "Gracefully shutdown the running process",
Flags: []cli.Flag{ Flags: []cli.Flag{
@@ -40,10 +38,7 @@ func newShutdownCommand() *cli.Command {
}, },
Action: runShutdown, Action: runShutdown,
} }
} subcmdRestart = &cli.Command{
func newRestartCommand() *cli.Command {
return &cli.Command{
Name: "restart", Name: "restart",
Usage: "Gracefully restart the running process - (not implemented for windows servers)", Usage: "Gracefully restart the running process - (not implemented for windows servers)",
Flags: []cli.Flag{ Flags: []cli.Flag{
@@ -53,10 +48,7 @@ func newRestartCommand() *cli.Command {
}, },
Action: runRestart, Action: runRestart,
} }
} subcmdReloadTemplates = &cli.Command{
func newReloadTemplatesCommand() *cli.Command {
return &cli.Command{
Name: "reload-templates", Name: "reload-templates",
Usage: "Reload template files in the running process", Usage: "Reload template files in the running process",
Flags: []cli.Flag{ Flags: []cli.Flag{
@@ -66,10 +58,7 @@ func newReloadTemplatesCommand() *cli.Command {
}, },
Action: runReloadTemplates, Action: runReloadTemplates,
} }
} subcmdFlushQueues = &cli.Command{
func newFlushQueuesCommand() *cli.Command {
return &cli.Command{
Name: "flush-queues", Name: "flush-queues",
Usage: "Flush queues in the running process", Usage: "Flush queues in the running process",
Action: runFlushQueues, Action: runFlushQueues,
@@ -88,10 +77,7 @@ func newFlushQueuesCommand() *cli.Command {
}, },
}, },
} }
} subCmdProcesses = &cli.Command{
func newProcessesCommand() *cli.Command {
return &cli.Command{
Name: "processes", Name: "processes",
Usage: "Display running processes within the current process", Usage: "Display running processes within the current process",
Action: runProcesses, Action: runProcesses,
@@ -121,7 +107,7 @@ func newProcessesCommand() *cli.Command {
}, },
}, },
} }
} )
func runShutdown(ctx context.Context, c *cli.Command) error { func runShutdown(ctx context.Context, c *cli.Command) error {
setup(ctx, c.Bool("debug")) setup(ctx, c.Bool("debug"))

View File

@@ -15,8 +15,8 @@ import (
"github.com/urfave/cli/v3" "github.com/urfave/cli/v3"
) )
func defaultLoggingFlags() []cli.Flag { var (
return []cli.Flag{ defaultLoggingFlags = []cli.Flag{
&cli.StringFlag{ &cli.StringFlag{
Name: "logger", Name: "logger",
Usage: `Logger name - will default to "default"`, Usage: `Logger name - will default to "default"`,
@@ -57,10 +57,8 @@ func defaultLoggingFlags() []cli.Flag {
Name: "debug", Name: "debug",
}, },
} }
}
func newLoggingCommand() *cli.Command { subcmdLogging = &cli.Command{
return &cli.Command{
Name: "logging", Name: "logging",
Usage: "Adjust logging commands", Usage: "Adjust logging commands",
Commands: []*cli.Command{ Commands: []*cli.Command{
@@ -111,7 +109,7 @@ func newLoggingCommand() *cli.Command {
{ {
Name: "file", Name: "file",
Usage: "Add a file logger", Usage: "Add a file logger",
Flags: append(defaultLoggingFlags(), []cli.Flag{ Flags: append(defaultLoggingFlags, []cli.Flag{
&cli.StringFlag{ &cli.StringFlag{
Name: "filename", Name: "filename",
Aliases: []string{"f"}, Aliases: []string{"f"},
@@ -152,7 +150,7 @@ func newLoggingCommand() *cli.Command {
}, { }, {
Name: "conn", Name: "conn",
Usage: "Add a net conn logger", Usage: "Add a net conn logger",
Flags: append(defaultLoggingFlags(), []cli.Flag{ Flags: append(defaultLoggingFlags, []cli.Flag{
&cli.BoolFlag{ &cli.BoolFlag{
Name: "reconnect-on-message", Name: "reconnect-on-message",
Aliases: []string{"R"}, Aliases: []string{"R"},
@@ -193,7 +191,7 @@ func newLoggingCommand() *cli.Command {
}, },
}, },
} }
} )
func runRemoveLogger(ctx context.Context, c *cli.Command) error { func runRemoveLogger(ctx context.Context, c *cli.Command) error {
setup(ctx, c.Bool("debug")) setup(ctx, c.Bool("debug"))

View File

@@ -14,13 +14,12 @@ import (
"github.com/urfave/cli/v3" "github.com/urfave/cli/v3"
) )
func newMigrateCommand() *cli.Command { // CmdMigrate represents the available migrate sub-command.
return &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,
}
} }
func runMigrate(ctx context.Context, c *cli.Command) error { func runMigrate(ctx context.Context, c *cli.Command) error {

View File

@@ -25,108 +25,107 @@ import (
"github.com/urfave/cli/v3" "github.com/urfave/cli/v3"
) )
func newMigrateStorageCommand() *cli.Command { // CmdMigrateStorage represents the available migrate storage sub-command.
return &cli.Command{ var CmdMigrateStorage = &cli.Command{
Name: "migrate-storage", Name: "migrate-storage",
Usage: "Migrate the storage", Usage: "Migrate the storage",
Description: "Copies stored files from storage configured in app.ini to parameter-configured storage", Description: "Copies stored files from storage configured in app.ini to parameter-configured storage",
Action: runMigrateStorage, Action: runMigrateStorage,
Flags: []cli.Flag{ Flags: []cli.Flag{
&cli.StringFlag{ &cli.StringFlag{
Name: "type", Name: "type",
Aliases: []string{"t"}, Aliases: []string{"t"},
Value: "", Value: "",
Usage: "Type of stored files to copy. Allowed types: 'attachments', 'lfs', 'avatars', 'repo-avatars', 'repo-archivers', 'packages', 'actions-log', 'actions-artifacts'", Usage: "Type of stored files to copy. Allowed types: 'attachments', 'lfs', 'avatars', 'repo-avatars', 'repo-archivers', 'packages', 'actions-log', 'actions-artifacts",
},
&cli.StringFlag{
Name: "storage",
Aliases: []string{"s"},
Value: "",
Usage: "New storage type: local (default), minio or azureblob",
},
&cli.StringFlag{
Name: "path",
Aliases: []string{"p"},
Value: "",
Usage: "New storage placement if store is local (leave blank for default)",
},
// Minio Storage special configurations
&cli.StringFlag{
Name: "minio-endpoint",
Value: "",
Usage: "Minio storage endpoint",
},
&cli.StringFlag{
Name: "minio-access-key-id",
Value: "",
Usage: "Minio storage accessKeyID",
},
&cli.StringFlag{
Name: "minio-secret-access-key",
Value: "",
Usage: "Minio storage secretAccessKey",
},
&cli.StringFlag{
Name: "minio-bucket",
Value: "",
Usage: "Minio storage bucket",
},
&cli.StringFlag{
Name: "minio-location",
Value: "",
Usage: "Minio storage location to create bucket",
},
&cli.StringFlag{
Name: "minio-base-path",
Value: "",
Usage: "Minio storage base path on the bucket",
},
&cli.BoolFlag{
Name: "minio-use-ssl",
Usage: "Enable SSL for minio",
},
&cli.BoolFlag{
Name: "minio-insecure-skip-verify",
Usage: "Skip SSL verification",
},
&cli.StringFlag{
Name: "minio-checksum-algorithm",
Value: "",
Usage: "Minio checksum algorithm (default/md5)",
},
&cli.StringFlag{
Name: "minio-bucket-lookup-type",
Value: "",
Usage: "Minio bucket lookup type",
},
// Azure Blob Storage special configurations
&cli.StringFlag{
Name: "azureblob-endpoint",
Value: "",
Usage: "Azure Blob storage endpoint",
},
&cli.StringFlag{
Name: "azureblob-account-name",
Value: "",
Usage: "Azure Blob storage account name",
},
&cli.StringFlag{
Name: "azureblob-account-key",
Value: "",
Usage: "Azure Blob storage account key",
},
&cli.StringFlag{
Name: "azureblob-container",
Value: "",
Usage: "Azure Blob storage container",
},
&cli.StringFlag{
Name: "azureblob-base-path",
Value: "",
Usage: "Azure Blob storage base path",
},
}, },
} &cli.StringFlag{
Name: "storage",
Aliases: []string{"s"},
Value: "",
Usage: "New storage type: local (default), minio or azureblob",
},
&cli.StringFlag{
Name: "path",
Aliases: []string{"p"},
Value: "",
Usage: "New storage placement if store is local (leave blank for default)",
},
// Minio Storage special configurations
&cli.StringFlag{
Name: "minio-endpoint",
Value: "",
Usage: "Minio storage endpoint",
},
&cli.StringFlag{
Name: "minio-access-key-id",
Value: "",
Usage: "Minio storage accessKeyID",
},
&cli.StringFlag{
Name: "minio-secret-access-key",
Value: "",
Usage: "Minio storage secretAccessKey",
},
&cli.StringFlag{
Name: "minio-bucket",
Value: "",
Usage: "Minio storage bucket",
},
&cli.StringFlag{
Name: "minio-location",
Value: "",
Usage: "Minio storage location to create bucket",
},
&cli.StringFlag{
Name: "minio-base-path",
Value: "",
Usage: "Minio storage base path on the bucket",
},
&cli.BoolFlag{
Name: "minio-use-ssl",
Usage: "Enable SSL for minio",
},
&cli.BoolFlag{
Name: "minio-insecure-skip-verify",
Usage: "Skip SSL verification",
},
&cli.StringFlag{
Name: "minio-checksum-algorithm",
Value: "",
Usage: "Minio checksum algorithm (default/md5)",
},
&cli.StringFlag{
Name: "minio-bucket-lookup-type",
Value: "",
Usage: "Minio bucket lookup type",
},
// Azure Blob Storage special configurations
&cli.StringFlag{
Name: "azureblob-endpoint",
Value: "",
Usage: "Azure Blob storage endpoint",
},
&cli.StringFlag{
Name: "azureblob-account-name",
Value: "",
Usage: "Azure Blob storage account name",
},
&cli.StringFlag{
Name: "azureblob-account-key",
Value: "",
Usage: "Azure Blob storage account key",
},
&cli.StringFlag{
Name: "azureblob-container",
Value: "",
Usage: "Azure Blob storage container",
},
&cli.StringFlag{
Name: "azureblob-base-path",
Value: "",
Usage: "Azure Blob storage base path",
},
},
} }
func migrateAttachments(ctx context.Context, dstStorage storage.ObjectStorage) error { func migrateAttachments(ctx context.Context, dstStorage storage.ObjectStorage) error {

View File

@@ -13,41 +13,40 @@ import (
"github.com/urfave/cli/v3" "github.com/urfave/cli/v3"
) )
func newRestoreRepositoryCommand() *cli.Command { // CmdRestoreRepository represents the available restore a repository sub-command.
return &cli.Command{ var CmdRestoreRepository = &cli.Command{
Name: "restore-repo", Name: "restore-repo",
Usage: "Restore the repository from disk", Usage: "Restore the repository from disk",
Description: "This is a command for restoring the repository data.", Description: "This is a command for restoring the repository data.",
Action: runRestoreRepository, Action: runRestoreRepository,
Flags: []cli.Flag{ Flags: []cli.Flag{
&cli.StringFlag{ &cli.StringFlag{
Name: "repo_dir", Name: "repo_dir",
Aliases: []string{"r"}, Aliases: []string{"r"},
Value: "./data", Value: "./data",
Usage: "Repository dir path to restore from", Usage: "Repository dir path to restore from",
},
&cli.StringFlag{
Name: "owner_name",
Value: "",
Usage: "Restore destination owner name",
},
&cli.StringFlag{
Name: "repo_name",
Value: "",
Usage: "Restore destination repository name",
},
&cli.StringFlag{
Name: "units",
Value: "",
Usage: `Which items will be restored, one or more units should be separated as comma.
wiki, issues, labels, releases, release_assets, milestones, pull_requests, comments are allowed. Empty means all units.`,
},
&cli.BoolFlag{
Name: "validation",
Usage: "Sanity check the content of the files before trying to load them",
},
}, },
} &cli.StringFlag{
Name: "owner_name",
Value: "",
Usage: "Restore destination owner name",
},
&cli.StringFlag{
Name: "repo_name",
Value: "",
Usage: "Restore destination repository name",
},
&cli.StringFlag{
Name: "units",
Value: "",
Usage: `Which items will be restored, one or more units should be separated as comma.
wiki, issues, labels, releases, release_assets, milestones, pull_requests, comments are allowed. Empty means all units.`,
},
&cli.BoolFlag{
Name: "validation",
Usage: "Sanity check the content of the files before trying to load them",
},
},
} }
func runRestoreRepository(ctx context.Context, c *cli.Command) error { func runRestoreRepository(ctx context.Context, c *cli.Command) error {

View File

@@ -35,23 +35,22 @@ import (
"github.com/urfave/cli/v3" "github.com/urfave/cli/v3"
) )
func newServCommand() *cli.Command { // CmdServ represents the available serv sub-command.
return &cli.Command{ var CmdServ = &cli.Command{
Name: "serv", Name: "serv",
Usage: "(internal) Should only be called by SSH shell", Usage: "(internal) Should only be called by SSH shell",
Description: "Serv provides access auth for repositories", Description: "Serv provides access auth for repositories",
Hidden: true, // Internal commands shouldn't be visible in help Hidden: true, // Internal commands shouldn't be visible in help
Before: PrepareConsoleLoggerLevel(log.FATAL), Before: PrepareConsoleLoggerLevel(log.FATAL),
Action: runServ, Action: runServ,
Flags: []cli.Flag{ Flags: []cli.Flag{
&cli.BoolFlag{ &cli.BoolFlag{
Name: "enable-pprof", Name: "enable-pprof",
},
&cli.BoolFlag{
Name: "debug",
},
}, },
} &cli.BoolFlag{
Name: "debug",
},
},
} }
func setup(ctx context.Context, debug bool) { func setup(ctx context.Context, debug bool) {

View File

@@ -8,13 +8,14 @@ import (
"fmt" "fmt"
"net" "net"
"net/http" "net/http"
"net/http/pprof"
"os" "os"
"path/filepath" "path/filepath"
"strconv" "strconv"
"strings" "strings"
"time" "time"
_ "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/gtprof"
@@ -22,7 +23,6 @@ import (
"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/templates"
"code.gitea.io/gitea/modules/util" "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"
@@ -34,43 +34,42 @@ import (
// PIDFile could be set from build tag // PIDFile could be set from build tag
var PIDFile = "/run/gitea.pid" var PIDFile = "/run/gitea.pid"
func newWebCommand() *cli.Command { // CmdWeb represents the available web sub-command.
return &cli.Command{ var CmdWeb = &cli.Command{
Name: "web", Name: "web",
Usage: "Start Gitea web server", Usage: "Start Gitea web server",
Description: `Gitea web server is the only thing you need to run, Description: `Gitea web server is the only thing you need to run,
and it takes care of all the other things for you`, and it takes care of all the other things for you`,
Before: PrepareConsoleLoggerLevel(log.INFO), Before: PrepareConsoleLoggerLevel(log.INFO),
Action: runWeb, Action: runWeb,
Flags: []cli.Flag{ Flags: []cli.Flag{
&cli.StringFlag{ &cli.StringFlag{
Name: "port", Name: "port",
Aliases: []string{"p"}, Aliases: []string{"p"},
Value: "3000", Value: "3000",
Usage: "Temporary port number to prevent conflict", Usage: "Temporary port number to prevent conflict",
},
&cli.StringFlag{
Name: "install-port",
Value: "3000",
Usage: "Temporary port number to run the install page on to prevent conflict",
},
&cli.StringFlag{
Name: "pid",
Aliases: []string{"P"},
Value: PIDFile,
Usage: "Custom pid file path",
},
&cli.BoolFlag{
Name: "quiet",
Aliases: []string{"q"},
Usage: "Only display Fatal logging errors until logging is set-up",
},
&cli.BoolFlag{
Name: "verbose",
Usage: "Set initial logging to TRACE level until logging is properly set-up",
},
}, },
} &cli.StringFlag{
Name: "install-port",
Value: "3000",
Usage: "Temporary port number to run the install page on to prevent conflict",
},
&cli.StringFlag{
Name: "pid",
Aliases: []string{"P"},
Value: PIDFile,
Usage: "Custom pid file path",
},
&cli.BoolFlag{
Name: "quiet",
Aliases: []string{"q"},
Usage: "Only display Fatal logging errors until logging is set-up",
},
&cli.BoolFlag{
Name: "verbose",
Usage: "Set initial logging to TRACE level until logging is properly set-up",
},
},
} }
func runHTTPRedirector() { func runHTTPRedirector() {
@@ -157,6 +156,7 @@ func serveInstall(cmd *cli.Command) error {
case <-graceful.GetManager().IsShutdown(): case <-graceful.GetManager().IsShutdown():
<-graceful.GetManager().Done() <-graceful.GetManager().Done()
log.Info("PID: %d Gitea Web Finished", os.Getpid()) log.Info("PID: %d Gitea Web Finished", os.Getpid())
log.GetManager().Close()
return err return err
default: default:
} }
@@ -164,6 +164,8 @@ func serveInstall(cmd *cli.Command) error {
} }
func serveInstalled(c *cli.Command) error { func serveInstalled(c *cli.Command) error {
setting.InitCfgProvider(setting.CustomConf)
setting.LoadCommonSettings()
setting.MustInstalled() setting.MustInstalled()
showWebStartupMessage("Prepare to run web server") showWebStartupMessage("Prepare to run web server")
@@ -229,26 +231,27 @@ func serveInstalled(c *cli.Command) error {
err := listen(webRoutes, true) err := listen(webRoutes, true)
<-graceful.GetManager().Done() <-graceful.GetManager().Done()
log.Info("PID: %d Gitea Web Finished", os.Getpid()) log.Info("PID: %d Gitea Web Finished", os.Getpid())
log.GetManager().Close()
return err return err
} }
func servePprof() { func servePprof() {
mux := http.NewServeMux() // FIXME: it shouldn't use the global DefaultServeMux, and it should use a proper context
mux.HandleFunc("/debug/pprof/", pprof.Index) http.DefaultServeMux.Handle("/debug/fgprof", fgprof.Handler())
mux.HandleFunc("/debug/pprof/cmdline", pprof.Cmdline)
mux.HandleFunc("/debug/pprof/profile", pprof.Profile)
mux.HandleFunc("/debug/pprof/symbol", pprof.Symbol)
mux.HandleFunc("/debug/pprof/trace", pprof.Trace)
mux.Handle("/debug/fgprof", fgprof.Handler())
// FIXME: it should use a proper context
_, _, finished := process.GetManager().AddTypedContext(context.TODO(), "Web: PProf Server", process.SystemProcessType, true) _, _, finished := process.GetManager().AddTypedContext(context.TODO(), "Web: PProf Server", process.SystemProcessType, true)
// The pprof server is for debug purpose only, it shouldn't be exposed on public network. At the moment, it's not worth introducing a configurable option for it. // The pprof server is for debug purpose only, it shouldn't be exposed on public network. At the moment, it's not worth introducing a configurable option for it.
log.Info("Starting pprof server on localhost:6060") log.Info("Starting pprof server on localhost:6060")
log.Info("Stopped pprof server: %v", http.ListenAndServe("localhost:6060", mux)) log.Info("Stopped pprof server: %v", http.ListenAndServe("localhost:6060", nil))
finished() finished()
} }
func runWeb(ctx context.Context, cmd *cli.Command) error { func runWeb(ctx context.Context, cmd *cli.Command) error {
defer func() {
if panicked := recover(); panicked != nil {
log.Fatal("PANIC: %v\n%s", panicked, log.Stack(2))
}
}()
if subCmdName, valid := isValidDefaultSubCommand(cmd); !valid { if subCmdName, valid := isValidDefaultSubCommand(cmd); !valid {
return fmt.Errorf("unknown command: %s", subCmdName) return fmt.Errorf("unknown command: %s", subCmdName)
} }
@@ -268,10 +271,6 @@ func runWeb(ctx context.Context, cmd *cli.Command) error {
createPIDFile(cmd.String("pid")) createPIDFile(cmd.String("pid"))
} }
// init the HTML renderer and load templates, if error happens, it will report the error immediately and exit with error log
// in dev mode, it won't exit, but watch the template files for changes
_ = templates.PageRenderer()
if !setting.InstallLock { if !setting.InstallLock {
if err := serveInstall(cmd); err != nil { if err := serveInstall(cmd); err != nil {
return err return err

View File

@@ -7,7 +7,6 @@ import (
"crypto/x509" "crypto/x509"
"encoding/pem" "encoding/pem"
"fmt" "fmt"
"net"
"net/http" "net/http"
"os" "os"
"strconv" "strconv"
@@ -125,8 +124,8 @@ func runACME(listenAddr string, m http.Handler) error {
defer finished() defer finished()
log.Info("Running Let's Encrypt handler on %s", setting.HTTPAddr+":"+setting.PortToRedirect) log.Info("Running Let's Encrypt handler on %s", setting.HTTPAddr+":"+setting.PortToRedirect)
// all traffic coming into HTTP will be redirected to HTTPS automatically (LE HTTP-01 validation happens here) // all traffic coming into HTTP will be redirect to HTTPS automatically (LE HTTP-01 validation happens here)
err := runHTTP("tcp", net.JoinHostPort(setting.HTTPAddr, setting.PortToRedirect), "Let's Encrypt HTTP Challenge", myACME.HTTPChallengeHandler(http.HandlerFunc(runLetsEncryptFallbackHandler)), setting.RedirectorUseProxyProtocol) err := runHTTP("tcp", setting.HTTPAddr+":"+setting.PortToRedirect, "Let's Encrypt HTTP Challenge", myACME.HTTPChallengeHandler(http.HandlerFunc(runLetsEncryptFallbackHandler)), setting.RedirectorUseProxyProtocol)
if err != nil { if err != nil {
log.Fatal("Failed to start the Let's Encrypt handler on port %s: %v", setting.PortToRedirect, err) log.Fatal("Failed to start the Let's Encrypt handler on port %s: %v", setting.PortToRedirect, err)
} }

View File

@@ -16,7 +16,7 @@ import (
"strconv" "strconv"
"strings" "strings"
"github.com/google/go-github/v84/github" "github.com/google/go-github/v74/github"
"github.com/urfave/cli/v3" "github.com/urfave/cli/v3"
"gopkg.in/yaml.v3" "gopkg.in/yaml.v3"
) )

View File

@@ -0,0 +1,47 @@
Environment To Ini
==================
Multiple docker users have requested that the Gitea docker is changed
to permit arbitrary configuration via environment variables.
Gitea needs to use an ini file for configuration because the running
environment that starts the docker may not be the same as that used
by the hooks. An ini file also gives a good default and means that
users do not have to completely provide a full environment.
With those caveats above, this command provides a generic way of
converting suitably structured environment variables into any ini
value.
To use the command is very simple just run it and the default gitea
app.ini will be rewritten to take account of the variables provided,
however there are various options to give slightly different
behavior and these can be interrogated with the `-h` option.
The environment variables should be of the form:
GITEA__SECTION_NAME__KEY_NAME
Note, SECTION_NAME in the notation above is case-insensitive.
Environment variables are usually restricted to a reduced character
set "0-9A-Z_" - in order to allow the setting of sections with
characters outside of that set, they should be escaped as following:
"_0X2E_" for "." and "_0X2D_" for "-". The entire section and key names
can be escaped as a UTF8 byte string if necessary. E.g. to configure:
"""
...
[log.console]
COLORIZE=false
STDERR=true
...
"""
You would set the environment variables: "GITEA__LOG_0x2E_CONSOLE__COLORIZE=false"
and "GITEA__LOG_0x2E_CONSOLE__STDERR=false". Other examples can be found
on the configuration cheat sheet.
To build locally, run:
go build contrib/environment-to-ini/environment-to-ini.go

View File

@@ -0,0 +1,112 @@
// Copyright 2019 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package main
import (
"context"
"os"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting"
"github.com/urfave/cli/v3"
)
func main() {
app := cli.Command{}
app.Name = "environment-to-ini"
app.Usage = "Use provided environment to update configuration ini"
app.Description = `As a helper to allow docker users to update the gitea configuration
through the environment, this command allows environment variables to
be mapped to values in the ini.
Environment variables of the form "GITEA__SECTION_NAME__KEY_NAME"
will be mapped to the ini section "[section_name]" and the key
"KEY_NAME" with the value as provided.
Environment variables of the form "GITEA__SECTION_NAME__KEY_NAME__FILE"
will be mapped to the ini section "[section_name]" and the key
"KEY_NAME" with the value loaded from the specified file.
Environment variables are usually restricted to a reduced character
set "0-9A-Z_" - in order to allow the setting of sections with
characters outside of that set, they should be escaped as following:
"_0X2E_" for ".". The entire section and key names can be escaped as
a UTF8 byte string if necessary. E.g. to configure:
"""
...
[log.console]
COLORIZE=false
STDERR=true
...
"""
You would set the environment variables: "GITEA__LOG_0x2E_CONSOLE__COLORIZE=false"
and "GITEA__LOG_0x2E_CONSOLE__STDERR=false". Other examples can be found
on the configuration cheat sheet.`
app.Flags = []cli.Flag{
&cli.StringFlag{
Name: "custom-path",
Aliases: []string{"C"},
Value: setting.CustomPath,
Usage: "Custom path file path",
},
&cli.StringFlag{
Name: "config",
Aliases: []string{"c"},
Value: setting.CustomConf,
Usage: "Custom configuration file path",
},
&cli.StringFlag{
Name: "work-path",
Aliases: []string{"w"},
Value: setting.AppWorkPath,
Usage: "Set the gitea working path",
},
&cli.StringFlag{
Name: "out",
Aliases: []string{"o"},
Value: "",
Usage: "Destination file to write to",
},
}
app.Action = runEnvironmentToIni
err := app.Run(context.Background(), os.Args)
if err != nil {
log.Fatal("Failed to run app with %s: %v", os.Args, err)
}
}
func runEnvironmentToIni(_ context.Context, c *cli.Command) error {
// the config system may change the environment variables, so get a copy first, to be used later
env := append([]string{}, os.Environ()...)
setting.InitWorkPathAndCfgProvider(os.Getenv, setting.ArgWorkPathAndCustomConf{
WorkPath: c.String("work-path"),
CustomPath: c.String("custom-path"),
CustomConf: c.String("config"),
})
cfg, err := setting.NewConfigProviderFromFile(setting.CustomConf)
if err != nil {
log.Fatal("Failed to load custom conf '%s': %v", setting.CustomConf, err)
}
changed := setting.EnvironmentToConfig(cfg, env)
// try to save the config file
destination := c.String("out")
if len(destination) == 0 {
destination = setting.CustomConf
}
if destination != setting.CustomConf || changed {
log.Info("Settings saved to: %q", destination)
err = cfg.SaveTo(destination)
if err != nil {
return err
}
}
return nil
}

View File

@@ -108,9 +108,7 @@ curl --connect-timeout 10 --silent --show-error --fail --location -O "$binurl{,.
sha256sum -c "${binname}.xz.sha256" sha256sum -c "${binname}.xz.sha256"
if [[ -z "${ignore_gpg:-}" ]]; then if [[ -z "${ignore_gpg:-}" ]]; then
require gpg require gpg
# try to use curl first, it uses standard tcp 443 port and works better behind strict firewall rules gpg --keyserver keys.openpgp.org --recv 7C9E68152594688862D62AF62D9AE806EC1592E2
curl -fsSL --connect-timeout 10 "https://keys.openpgp.org/vks/v1/by-fingerprint/7C9E68152594688862D62AF62D9AE806EC1592E2" | gpg --import \
|| gpg --keyserver keys.openpgp.org --recv 7C9E68152594688862D62AF62D9AE806EC1592E2
gpg --verify "${binname}.xz.asc" "${binname}.xz" || { echo 'Signature does not match'; exit 1; } gpg --verify "${binname}.xz.asc" "${binname}.xz" || { echo 'Signature does not match'; exit 1; }
fi fi
rm "${binname}".xz.{sha256,asc} rm "${binname}".xz.{sha256,asc}
@@ -129,8 +127,6 @@ echo "Creating backup in $giteahome"
giteacmd dump $backupopts giteacmd dump $backupopts
echo "Updating binary at $giteabin" echo "Updating binary at $giteabin"
cp -f "$giteabin" "$giteabin.bak" && mv -f "$binname" "$giteabin" cp -f "$giteabin" "$giteabin.bak" && mv -f "$binname" "$giteabin"
# Restore SELinux context if applicable (e.g. RHEL/Fedora)
command -v restorecon &>/dev/null && restorecon -v "$giteabin" || true
$service_start $service_start
$service_status $service_status

View File

@@ -4,9 +4,9 @@ base_path: "."
base_url: "https://api.crowdin.com" base_url: "https://api.crowdin.com"
preserve_hierarchy: true preserve_hierarchy: true
files: files:
- source: "/options/locale/locale_en-US.json" - source: "/options/locale/locale_en-US.ini"
translation: "/options/locale/locale_%locale%.json" translation: "/options/locale/locale_%locale%.ini"
type: "json" type: "ini"
skip_untranslated_strings: true skip_untranslated_strings: true
export_only_approved: true export_only_approved: true
update_option: "update_as_unapproved" update_option: "update_as_unapproved"

View File

@@ -41,10 +41,10 @@
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ;;
;; App name that shows in every page title ;; App name that shows in every page title
;APP_NAME = Gitea: Git with a cup of tea APP_NAME = ; Gitea: Git with a cup of tea
;; ;;
;; RUN_USER will automatically detect the current user - but you can set it here change it if you run locally ;; RUN_USER will automatically detect the current user - but you can set it here change it if you run locally
;RUN_USER = RUN_USER = ; git
;; ;;
;; Application run mode, affects performance and debugging: "dev" or "prod", default is "prod" ;; Application run mode, affects performance and debugging: "dev" or "prod", default is "prod"
;; Mode "dev" makes Gitea easier to develop and debug, values other than "dev" are treated as "prod" which is for production use. ;; Mode "dev" makes Gitea easier to develop and debug, values other than "dev" are treated as "prod" which is for production use.
@@ -69,12 +69,12 @@
;; Most users should set it to the real website URL of their Gitea instance when there is a reverse proxy. ;; Most users should set it to the real website URL of their Gitea instance when there is a reverse proxy.
;ROOT_URL = ;ROOT_URL =
;; ;;
;; Controls how to detect the public URL. Most instances should use the "auto" behavior, ;; Controls how to detect the public URL.
;; Although it defaults to "legacy" (to avoid breaking existing users), most instances should use the "auto" behavior,
;; especially when the Gitea instance needs to be accessed in a container network. ;; especially when the Gitea instance needs to be accessed in a container network.
;; * legacy: (default <= 1.25) detect the public URL from "Host" header if "X-Forwarded-Proto" header exists, otherwise use "ROOT_URL". ;; * legacy: detect the public URL from "Host" header if "X-Forwarded-Proto" header exists, otherwise use "ROOT_URL".
;; * auto: (default >= 1.26) always use "Host" header, and also use "X-Forwarded-Proto" header if it exists. If no "Host" header, use "ROOT_URL". ;; * auto: always use "Host" header, and also use "X-Forwarded-Proto" header if it exists. If no "Host" header, use "ROOT_URL".
;; * never: always use "ROOT_URL", never detect from request headers. ;PUBLIC_URL_DETECTION = legacy
;PUBLIC_URL_DETECTION = auto
;; ;;
;; 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!!!
@@ -175,15 +175,14 @@
;; The port number the builtin SSH server should listen on, defaults to SSH_PORT ;; The port number the builtin SSH server should listen on, defaults to SSH_PORT
;SSH_LISTEN_PORT = ;SSH_LISTEN_PORT =
;; ;;
;; Root path of SSH user directory for the system's standalone SSH server if Gitea is not using its builtin SSH server. ;; Root path of SSH directory, default is '~/.ssh', but you have to use '/home/git/.ssh'.
;; Default is the '.ssh' directory in the run user's home directory.
;SSH_ROOT_PATH = ;SSH_ROOT_PATH =
;; ;;
;; Gitea will create an authorized_keys file by default when it is not using the builtin SSH server ;; Gitea will create a authorized_keys file by default when it is not using the internal ssh server
;; If you intend to use the AuthorizedKeysCommand functionality then you should turn this off. ;; If you intend to use the AuthorizedKeysCommand functionality then you should turn this off.
;SSH_CREATE_AUTHORIZED_KEYS_FILE = true ;SSH_CREATE_AUTHORIZED_KEYS_FILE = true
;; ;;
;; Gitea will create an authorized_principals file by default when it is not using the builtin SSH server ;; Gitea will create a authorized_principals file by default when it is not using the internal ssh server
;; If you intend to use the AuthorizedPrincipalsCommand functionality then you should turn this off. ;; If you intend to use the AuthorizedPrincipalsCommand functionality then you should turn this off.
;SSH_CREATE_AUTHORIZED_PRINCIPALS_FILE = true ;SSH_CREATE_AUTHORIZED_PRINCIPALS_FILE = true
;; ;;
@@ -239,6 +238,9 @@
;; Indicate whether to check minimum key size with corresponding type ;; Indicate whether to check minimum key size with corresponding type
;MINIMUM_KEY_SIZE_CHECK = false ;MINIMUM_KEY_SIZE_CHECK = false
;; ;;
;; Disable CDN even in "prod" mode
;OFFLINE_MODE = true
;;
;; TLS Settings: Either ACME or manual ;; TLS Settings: Either ACME or manual
;; (Other common TLS configuration are found before) ;; (Other common TLS configuration are found before)
;ENABLE_ACME = false ;ENABLE_ACME = false
@@ -461,11 +463,6 @@ INTERNAL_TOKEN =
;; Name of cookie used to store authentication information. ;; Name of cookie used to store authentication information.
;COOKIE_REMEMBER_NAME = gitea_incredible ;COOKIE_REMEMBER_NAME = gitea_incredible
;; ;;
;; URL or path that Gitea should redirect users to *after* performing its own logout.
;; Use this, if needed, when authentication is handled by a reverse proxy or SSO.
;; For example: "/my-sso/logout?return=/my-sso/home"
;REVERSE_PROXY_LOGOUT_REDIRECT =
;;
;; Reverse proxy authentication header name of user name, email, and full name ;; Reverse proxy authentication header name of user name, email, and full name
;REVERSE_PROXY_AUTHENTICATION_USER = X-WEBAUTH-USER ;REVERSE_PROXY_AUTHENTICATION_USER = X-WEBAUTH-USER
;REVERSE_PROXY_AUTHENTICATION_EMAIL = X-WEBAUTH-EMAIL ;REVERSE_PROXY_AUTHENTICATION_EMAIL = X-WEBAUTH-EMAIL
@@ -506,6 +503,9 @@ INTERNAL_TOKEN =
;; Password Hash algorithm, either "argon2", "pbkdf2", "scrypt" or "bcrypt" ;; Password Hash algorithm, either "argon2", "pbkdf2", "scrypt" or "bcrypt"
;PASSWORD_HASH_ALGO = pbkdf2 ;PASSWORD_HASH_ALGO = pbkdf2
;; ;;
;; Set false to allow JavaScript to read CSRF cookie
;CSRF_COOKIE_HTTP_ONLY = true
;;
;; Validate against https://haveibeenpwned.com/Passwords to see if a password has been exposed ;; Validate against https://haveibeenpwned.com/Passwords to see if a password has been exposed
;PASSWORD_CHECK_PWN = false ;PASSWORD_CHECK_PWN = false
;; ;;
@@ -524,9 +524,6 @@ INTERNAL_TOKEN =
;; Set the two-factor auth behavior. ;; Set the two-factor auth behavior.
;; Set to "enforced", to force users to enroll into Two-Factor Authentication, users without 2FA have no access to repositories via API or web. ;; Set to "enforced", to force users to enroll into Two-Factor Authentication, users without 2FA have no access to repositories via API or web.
;TWO_FACTOR_AUTH = ;TWO_FACTOR_AUTH =
;;
;; The value of the X-Frame-Options HTTP header for HTML responses. Use "unset" to remove the header.
;X_FRAME_OPTIONS = SAMEORIGIN
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@@ -736,15 +733,15 @@ LEVEL = Info
;DISABLE_CORE_PROTECT_NTFS=false ;DISABLE_CORE_PROTECT_NTFS=false
;; Disable the usage of using partial clones for git. ;; Disable the usage of using partial clones for git.
;DISABLE_PARTIAL_CLONE = false ;DISABLE_PARTIAL_CLONE = false
;; Set the similarity threshold passed to git commands via `--find-renames=<threshold>`.
;; Default is 50%, the same as git. Must be a integer percentage between 0% and 100%.
;DIFF_RENAME_SIMILARITY_THRESHOLD = 50%
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Git Operation timeout in seconds ;; Git Operation timeout in seconds
;[git.timeout] ;[git.timeout]
;DEFAULT = 360
;MIGRATE = 600 ;MIGRATE = 600
;MIRROR = 300 ;MIRROR = 300
;CLONE = 300
;PULL = 300
;GC = 60 ;GC = 60
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@@ -1158,15 +1155,15 @@ LEVEL = Info
;; 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
;; ;;
;; In addition to testing patches using the three-way merge method, re-test conflicting patches with git apply
;TEST_CONFLICTING_PATCHES_WITH_GIT_APPLY = false
;;
;; Retarget child pull requests to the parent pull request branch target on merge of parent pull request. It only works on merged PRs where the head and base branch target the same repo. ;; Retarget child pull requests to the parent pull request branch target on merge of parent pull request. It only works on merged PRs where the head and base branch target the same repo.
;RETARGET_CHILDREN_ON_MERGE = true ;RETARGET_CHILDREN_ON_MERGE = true
;; ;;
;; Delay mergeable check until page view or API access, for pull requests that have not been updated in the specified days when their base branches get updated. ;; Delay mergeable check until page view or API access, for pull requests that have not been updated in the specified days when their base branches get updated.
;; Use "-1" to always check all pull requests (old behavior). Use "0" to always delay the checks. ;; Use "-1" to always check all pull requests (old behavior). Use "0" to always delay the checks.
;DELAY_CHECK_FOR_INACTIVE_DAYS = 7 ;DELAY_CHECK_FOR_INACTIVE_DAYS = 7
;;
;; Set the default value for "Delete pull request branch after merge by default" for new repositories
;DEFAULT_DELETE_BRANCH_AFTER_MERGE = false
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@@ -1184,17 +1181,9 @@ LEVEL = Info
;[repository.release] ;[repository.release]
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Comma-separated list of allowed release attachment 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 =
;;
;; Number of releases that are displayed on release page
;DEFAULT_PAGING_NUM = 10 ;DEFAULT_PAGING_NUM = 10
;;
;; Max size of each release attachment file in megabytes. Defaults to 2GB
;FILE_MAX_SIZE = 2048
;;
;; Max number of release attachment files per upload. Defaults to 5
;MAX_FILES = 5
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@@ -1296,6 +1285,9 @@ LEVEL = Info
;; ;;
;; headers to permit ;; headers to permit
;HEADERS = Content-Type,User-Agent ;HEADERS = Content-Type,User-Agent
;;
;; set X-FRAME-OPTIONS header
;X_FRAME_OPTIONS = SAMEORIGIN
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@@ -1340,12 +1332,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 icon theme for files (basic/material) ;; 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 ;FILE_ICON_THEME = material
;; ;;
;; The icon theme for folders (basic/material)
;FOLDER_ICON_THEME = basic
;;
;; 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
@@ -1986,12 +1975,12 @@ LEVEL = Info
;; or a custom avatar source, like: http://cn.gravatar.com/avatar/ ;; or a custom avatar source, like: http://cn.gravatar.com/avatar/
;GRAVATAR_SOURCE = gravatar ;GRAVATAR_SOURCE = gravatar
;; ;;
;; Deprecated, see Web UI Admin Panel -> Config -> Settings ;; This value will always be true in offline mode.
;DISABLE_GRAVATAR = false ;DISABLE_GRAVATAR = false
;; ;;
;; Federated avatar lookup uses DNS to discover avatar associated ;; Federated avatar lookup uses DNS to discover avatar associated
;; with emails, see https://www.libravatar.org ;; with emails, see https://www.libravatar.org
;; Deprecated, see Web UI Admin Panel -> Config -> Settings ;; This value will always be false in offline mode or when Gravatar is disabled.
;ENABLE_FEDERATED_AVATAR = false ;ENABLE_FEDERATED_AVATAR = false
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@@ -2000,18 +1989,16 @@ LEVEL = Info
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ;;
;; Whether issue, pull-request and release attachments are enabled. Defaults to `true` ;; Whether issue and pull request attachments are enabled. Defaults to `true`
;; ALLOWED_TYPES/MAX_SIZE/MAX_FILES in this section only affect issue and pull-request attachments, not release attachments.
;; Release attachment has its own config options in [repository.release] section.
;ENABLED = true ;ENABLED = true
;; ;;
;; Comma-separated list of allowed issue/pull-request attachment 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 = .avif,.cpuprofile,.csv,.dmp,.docx,.fodg,.fodp,.fods,.fodt,.gif,.gz,.jpeg,.jpg,.json,.jsonc,.log,.md,.mov,.mp4,.odf,.odg,.odp,.ods,.odt,.patch,.pdf,.png,.pptx,.svg,.tgz,.txt,.webm,.webp,.xls,.xlsx,.zip ;ALLOWED_TYPES = .avif,.cpuprofile,.csv,.dmp,.docx,.fodg,.fodp,.fods,.fodt,.gif,.gz,.jpeg,.jpg,.json,.jsonc,.log,.md,.mov,.mp4,.odf,.odg,.odp,.ods,.odt,.patch,.pdf,.png,.pptx,.svg,.tgz,.txt,.webm,.webp,.xls,.xlsx,.zip
;; ;;
;; Max size of each issue/pull-request attachment file. Defaults to 100MB ;; Max size of each file. Defaults to 2048MB
;MAX_SIZE = 100 ;MAX_SIZE = 2048
;; ;;
;; Max number of issue/pull-request attachment files per upload. Defaults to 5 ;; Max number of files per upload. Defaults to 5
;MAX_FILES = 5 ;MAX_FILES = 5
;; ;;
;; Storage type for attachments, `local` for local disk or `minio` for s3 compatible ;; Storage type for attachments, `local` for local disk or `minio` for s3 compatible
@@ -2284,22 +2271,6 @@ LEVEL = Info
;; Unreferenced blobs created more than OLDER_THAN ago are subject to deletion ;; Unreferenced blobs created more than OLDER_THAN ago are subject to deletion
;OLDER_THAN = 24h ;OLDER_THAN = 24h
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Synchronize repository licenses
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;[cron.sync_repo_licenses]
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Whether to enable the job
;ENABLED = false
;; Whether to always run at least once at start up time (if ENABLED)
;RUN_AT_START = false
;; Whether to emit notice on successful execution too
;NOTICE_ON_SUCCESS = false
;; Time interval for job to run
;SCHEDULE = @annually
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@@ -2363,19 +2334,7 @@ LEVEL = Info
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Update the '.ssh/authorized_principals' file ;; Resynchronize pre-receive, update and post-receive hooks of all repositories.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;[cron.resync_all_sshprincipals]
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;ENABLED = false
;RUN_AT_START = false
;NOTICE_ON_SUCCESS = false
;SCHEDULE = @every 72h
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Resynchronize git hooks of all repositories (pre-receive, update, post-receive, proc-receive, ...)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;[cron.resync_all_hooks] ;[cron.resync_all_hooks]
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@@ -2481,70 +2440,6 @@ LEVEL = Info
;Check at least this proportion of LFSMetaObjects per repo. (This may cause all stale LFSMetaObjects to be checked.) ;Check at least this proportion of LFSMetaObjects per repo. (This may cause all stale LFSMetaObjects to be checked.)
;PROPORTION_TO_CHECK_PER_REPO = 0.6 ;PROPORTION_TO_CHECK_PER_REPO = 0.6
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Rebuild issue index
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;[cron.rebuild_issue_indexer]
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;ENABLED = false
;RUN_AT_START = false
;NO_SUCCESS_NOTICE = false
;SCHEDULE = @annually
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Actions cron tasks
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Stop running tasks which haven't been updated for a long time
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;[cron.stop_zombie_tasks]
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;ENABLED = true
;RUN_AT_START = true
;NO_SUCCESS_NOTICE = false
;SCHEDULE = @every 5m
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Stop running tasks which have running status and continuous updates but don't end for a long time
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;[cron.stop_endless_tasks]
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;ENABLED = true
;RUN_AT_START = true
;NO_SUCCESS_NOTICE = false
;SCHEDULE = @every 30m
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Cancel jobs which haven't been picked up for a long time
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;[cron.cancel_abandoned_jobs]
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;ENABLED = true
;RUN_AT_START = false
;NO_SUCCESS_NOTICE = false
;SCHEDULE = @every 6h
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Start cron based actions
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;[cron.start_schedule_tasks]
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;ENABLED = true
;RUN_AT_START = false
;NO_SUCCESS_NOTICE = false
;SCHEDULE = @every 1m
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;[mirror] ;[mirror]
@@ -2593,9 +2488,8 @@ LEVEL = Info
;[highlight.mapping] ;[highlight.mapping]
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Extension mapping to highlight class, for example: ;; Extension mapping to highlight class
;; .toml = ini ;; e.g. .toml=ini
;; .my-js = JavaScript
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@@ -2798,8 +2692,6 @@ LEVEL = Info
;LIMIT_SIZE_SWIFT = -1 ;LIMIT_SIZE_SWIFT = -1
;; Maximum size of a Vagrant upload (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`) ;; Maximum size of a Vagrant upload (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`)
;LIMIT_SIZE_VAGRANT = -1 ;LIMIT_SIZE_VAGRANT = -1
;; Maximum size of a Terraform state upload (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`)
;LIMIT_SIZE_TERRAFORM_STATE = -1
;; Enable RPM re-signing by default. (It will overwrite the old signature ,using v4 format, not compatible with CentOS 6 or older) ;; Enable RPM re-signing by default. (It will overwrite the old signature ,using v4 format, not compatible with CentOS 6 or older)
;DEFAULT_RPM_SIGN_ENABLED = false ;DEFAULT_RPM_SIGN_ENABLED = false
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@@ -2965,9 +2857,6 @@ LEVEL = Info
;ABANDONED_JOB_TIMEOUT = 24h ;ABANDONED_JOB_TIMEOUT = 24h
;; Strings committers can place inside a commit message or PR title to skip executing the corresponding actions workflow ;; Strings committers can place inside a commit message or PR title to skip executing the corresponding actions workflow
;SKIP_WORKFLOW_STRINGS = [skip ci],[ci skip],[no ci],[skip actions],[actions skip] ;SKIP_WORKFLOW_STRINGS = [skip ci],[ci skip],[no ci],[skip actions],[actions skip]
;; Comma-separated list of workflow directories, the first one to exist
;; in a repo is used to find Actions workflow files
;WORKFLOW_DIRS = .gitea/workflows,.github/workflows
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

View File

@@ -1,8 +1,2 @@
#!/bin/bash #!/bin/bash
# $1 = exit code of the run script, $2 = signal
if [ "$1" -ne 0 ]; then
# avoid immediately restarting the sshd service, which may cause CPU 100% if the error (permission, configuration) is not fixed
echo "openssh failed with exit code $1 - waiting a short delay before attempting a restart"
sleep 3
fi
exit 0 exit 0

View File

@@ -1,2 +0,0 @@
#!/bin/bash
exec /app/gitea/gitea config edit-ini --in-place --apply-env "$@"

View File

@@ -1,2 +0,0 @@
#!/bin/bash
exec /app/gitea/gitea config edit-ini --in-place --apply-env "$@"

View File

@@ -1,198 +0,0 @@
# Community governance and review process
This document describes maintainer expectations, project governance, and the detailed pull request review workflow (labels, merge queue, commit message format for mergers). For what contributors should do when opening and updating a PR, see [CONTRIBUTING.md](../CONTRIBUTING.md).
## Code review
### Milestone
A PR should only be assigned to a milestone if it will likely be merged into the given version. \
PRs without a milestone may not be merged.
### Labels
Almost all labels used inside Gitea can be classified as one of the following:
- `modifies/…`: Determines which parts of the codebase are affected. These labels will be set through the CI.
- `topic/…`: Determines the conceptual component of Gitea that is affected, i.e. issues, projects, or authentication. At best, PRs should only target one component but there might be overlap. Must be set manually.
- `type/…`: Determines the type of an issue or PR (feature, refactoring, docs, bug, …). If GitHub supported scoped labels, these labels would be exclusive, so you should set **exactly** one, not more or less (every PR should fall into one of the provided categories, and only one).
- `issue/…` / `lgtm/…`: Labels that are specific to issues or PRs respectively and that are only necessary in a given context, i.e. `issue/not-a-bug` or `lgtm/need 2`
Every PR should be labeled correctly with every label that applies.
There are also some labels that will be managed automatically.\
In particular, these are
- the amount of pending required approvals
- has all `backport`s or needs a manual backport
### Reviewing PRs
Maintainers are encouraged to review pull requests in areas where they have expertise or particular interest.
#### For reviewers
- **Verification**: Verify that the PR accurately reflects the changes, and verify that the tests and documentation are complete and aligned with the implementation.
- **Actionable feedback**: Say what should change and why, and distinguish required changes from optional suggestions.
- **Feedback**: Focus feedback on the issue itself and avoid comments about the contributor's abilities.
- **Request changes**: If you request changes (i.e., block a PR), give a clear rationale and, whenever possible, a concrete path to resolution.
- **Approval**: Only approve a PR when you are fully satisfied with its current state - "rubber-stamp" approvals need to be highlighted as such.
### Getting PRs merged
Changes to Gitea must be reviewed before they are accepted, including changes from owners and maintainers. The exception is critical bugs that prevent Gitea from compiling or starting.
We require two maintainer approvals for every PR. When that is satisfied, your PR gets the `lgtm/done` label. After that, you mainly fix merge conflicts and respond to or implement maintainer requests; maintainers drive getting the PR merged.
If a PR has `lgtm/done`, no open discussions, and no merge conflicts, any maintainer may add `reviewed/wait-merge`. That puts the PR in the merge queue. PRs are merged from the queue in the order of this list:
<https://github.com/go-gitea/gitea/pulls?q=is%3Apr+label%3Areviewed%2Fwait-merge+sort%3Acreated-asc+is%3Aopen>
Gitea uses its own tool, <https://github.com/GiteaBot/gitea-backporter>, to automate parts of the review process. The backporter:
- Creates a backport PR when needed after the initial PR merges.
- Removes the PR from the merge queue after it merges.
- Keeps the oldest branch in the merge queue up to date with merges.
### Final call
If a PR has been ignored for more than 7 days with no comments or reviews, and the author or any maintainer believes it will not survive a long wait (such as a refactoring PR), they can send "final call" to the TOC by mentioning them in a comment.
After another 7 days, if there is still zero approval, this is considered a polite refusal, and the PR will be closed to avoid wasting further time. Therefore, the "final call" has a cost, and should be used cautiously.
However, if there are no objections from maintainers, the PR can be merged with only one approval from the TOC (not the author).
### Commit messages
Mergers are required to rewrite the PR title and the first comment (the summary) when necessary so the squash commit message is clear.
The final commit message should not hedge: replace phrases like `hopefully, <x> won't happen anymore` with definite wording.
#### PR Co-authors
A person counts as a PR co-author once they (co-)authored a commit that is not simply a `Merge base branch into branch` commit. Mergers must remove such false-positive co-authors when writing the squash message. Every true co-author must remain in the commit message.
#### PRs targeting `main`
The commit message of PRs targeting `main` is always
```bash
$PR_TITLE ($PR_INDEX)
$REWRITTEN_PR_SUMMARY
```
#### Backport PRs
The commit message of backport PRs is always
```bash
$PR_TITLE ($INITIAL_PR_INDEX) ($BACKPORT_PR_INDEX)
$REWRITTEN_PR_SUMMARY
```
## Maintainers
We list [maintainers](../MAINTAINERS) so every PR gets proper review.
#### Review expectations
Every PR **must** be reviewed by at least two maintainers (or owners) before merge. **Exception:** after one week, refactoring PRs and documentation-only PRs need only one maintainer approval.
Maintainers are expected to spend time on code reviews.
#### Becoming a maintainer
A maintainer should already be a Gitea contributor with at least four merged PRs. To apply, use the [Discord](https://discord.gg/Gitea) `#develop` channel. Maintainer teams may also invite contributors.
#### Stepping down, advisors, and inactivity
If you cannot keep reviewing, apply to leave the maintainers team. You can join the [advisors team](https://github.com/orgs/go-gitea/teams/advisors); advisors who want to review again are welcome back as maintainers.
If a maintainer is inactive for more than three months and has not left the team, owners may move them to the advisors team.
#### Account security
For security, maintainers should enable 2FA and sign commits with GPG when possible:
- [Two-factor authentication](https://docs.github.com/en/authentication/securing-your-account-with-two-factor-authentication-2fa/configuring-two-factor-authentication)
- [Signing commits with GPG](https://docs.github.com/en/authentication/managing-commit-signature-verification/signing-commits)
Any account with write access (including bots and TOC members) **must** use [2FA](https://docs.github.com/en/authentication/securing-your-account-with-two-factor-authentication-2fa/configuring-two-factor-authentication).
## Technical Oversight Committee (TOC)
At the start of 2023, the `Owners` team was dissolved. Instead, the governance charter proposed a technical oversight committee (TOC) which expands the ownership team of the Gitea project from three elected positions to six positions. Three positions are elected as it has been over the past years, and the other three consist of appointed members from the Gitea company.
https://blog.gitea.com/quarterly-23q1/
### TOC election process
Any maintainer is eligible to be part of the community TOC if they are not associated with the Gitea company.
A maintainer can either nominate themselves, or can be nominated by other maintainers to be a candidate for the TOC election.
If you are nominated by someone else, you must first accept your nomination before the vote starts to be a candidate.
The TOC is elected for one year, the TOC election happens yearly.
After the announcement of the results of the TOC election, elected members have two weeks time to confirm or refuse the seat.
If an elected member does not answer within this timeframe, they are automatically assumed to refuse the seat.
Refusals result in the person with the next highest vote getting the same choice.
As long as seats are empty in the TOC, members of the previous TOC can fill them until an elected member accepts the seat.
If an elected member that accepts the seat does not have 2FA configured yet, they will be temporarily counted as `answer pending` until they manage to configure 2FA, thus leaving their seat empty for this duration.
### Current TOC members
- 2024-01-01 ~ 2024-12-31
- Company
- [Jason Song](https://gitea.com/wolfogre) <i@wolfogre.com>
- [Lunny Xiao](https://gitea.com/lunny) <xiaolunwen@gmail.com>
- [Matti Ranta](https://gitea.com/techknowlogick) <techknowlogick@gitea.com>
- Community
- [6543](https://gitea.com/6543) <6543@obermui.de>
- [delvh](https://gitea.com/delvh) <dev.lh@web.de>
- [John Olheiser](https://gitea.com/jolheiser) <john.olheiser@gmail.com>
### Previous TOC/owners members
Here's the history of the owners and the time they served:
- [Lunny Xiao](https://gitea.com/lunny) - 2016, 2017, [2018](https://github.com/go-gitea/gitea/issues/3255), [2019](https://github.com/go-gitea/gitea/issues/5572), [2020](https://github.com/go-gitea/gitea/issues/9230), [2021](https://github.com/go-gitea/gitea/issues/13801), [2022](https://github.com/go-gitea/gitea/issues/17872), 2023
- [Kim Carlbäcker](https://github.com/bkcsoft) - 2016, 2017
- [Thomas Boerger](https://gitea.com/tboerger) - 2016, 2017
- [Lauris Bukšis-Haberkorns](https://gitea.com/lafriks) - [2018](https://github.com/go-gitea/gitea/issues/3255), [2019](https://github.com/go-gitea/gitea/issues/5572), [2020](https://github.com/go-gitea/gitea/issues/9230), [2021](https://github.com/go-gitea/gitea/issues/13801)
- [Matti Ranta](https://gitea.com/techknowlogick) - [2019](https://github.com/go-gitea/gitea/issues/5572), [2020](https://github.com/go-gitea/gitea/issues/9230), [2021](https://github.com/go-gitea/gitea/issues/13801), [2022](https://github.com/go-gitea/gitea/issues/17872), 2023
- [Andrew Thornton](https://gitea.com/zeripath) - [2020](https://github.com/go-gitea/gitea/issues/9230), [2021](https://github.com/go-gitea/gitea/issues/13801), [2022](https://github.com/go-gitea/gitea/issues/17872), 2023
- [6543](https://gitea.com/6543) - 2023
- [John Olheiser](https://gitea.com/jolheiser) - 2023
- [Jason Song](https://gitea.com/wolfogre) - 2023
## Governance Compensation
Each member of the community elected TOC will be granted $500 each month as compensation for their work.
Furthermore, any community release manager for a specific release or LTS will be compensated $500 for the delivery of said release.
These funds will come from community sources like the OpenCollective rather than directly from the company.
Only non-company members are eligible for this compensation, and if a member of the community TOC takes the responsibility of release manager, they would only be compensated for their TOC duties.
Gitea Ltd employees are not eligible to receive any funds from the OpenCollective unless it is reimbursement for a purchase made for the Gitea project itself.
## TOC & Working groups
With Gitea covering many projects outside of the main repository, several groups will be created to help focus on specific areas instead of requiring maintainers to be a jack-of-all-trades. Maintainers are of course more than welcome to be part of multiple groups should they wish to contribute in multiple places.
The currently proposed groups are:
- **Core Group**: maintain the primary Gitea repository
- **Integration Group**: maintain the Gitea ecosystem's related tools, including go-sdk/tea/changelog/bots etc.
- **Documentation Group**: maintain related documents and repositories
- **Translation Group**: coordinate with translators and maintain translations
- **Security Group**: managed by TOC directly, members are decided by TOC, maintains security patches/responsible for security items
## Roadmap
Each year a roadmap will be discussed with the entire Gitea maintainers team, and feedback will be solicited from various stakeholders.
TOC members need to review the roadmap every year and work together on the direction of the project.
When a vote is required for a proposal or other change, the vote of community elected TOC members count slightly more than the vote of company elected TOC members. With this approach, we both avoid ties and ensure that changes align with the mission statement and community opinion.
You can visit our roadmap on the wiki.

View File

@@ -1,58 +0,0 @@
# Backend development
This document covers backend-specific contribution expectations. For general contribution workflow, see [CONTRIBUTING.md](../CONTRIBUTING.md).
For coding style and architecture, see also the [backend development guideline](https://docs.gitea.com/contributing/guidelines-backend) on the documentation site.
## Dependencies
Go dependencies are managed using [Go Modules](https://go.dev/cmd/go/#hdr-Module_maintenance). \
You can find more details in the [go mod documentation](https://go.dev/ref/mod) and the [Go Modules Wiki](https://github.com/golang/go/wiki/Modules).
Pull requests should only modify `go.mod` and `go.sum` where it is related to your change, be it a bugfix or a new feature. \
Apart from that, these files should only be modified by Pull Requests whose only purpose is to update dependencies.
The `go.mod`, `go.sum` update needs to be justified as part of the PR description,
and must be verified by the reviewers and/or merger to always reference
an existing upstream commit.
## API v1
The API is documented by [swagger](https://gitea.com/api/swagger) and is based on [the GitHub API](https://docs.github.com/en/rest).
### GitHub API compatibility
Gitea's API should use the same endpoints and fields as the GitHub API as far as possible, unless there are good reasons to deviate. \
If Gitea provides functionality that GitHub does not, a new endpoint can be created. \
If information is provided by Gitea that is not provided by the GitHub API, a new field can be used that doesn't collide with any GitHub fields. \
Updating an existing API should not remove existing fields unless there is a really good reason to do so. \
The same applies to status responses. If you notice a problem, feel free to leave a comment in the code for future refactoring to API v2 (which is currently not planned).
### Adding/Maintaining API routes
All expected results (errors, success, fail messages) must be documented ([example](https://github.com/go-gitea/gitea/blob/c620eb5b2d0d874da68ebd734d3864c5224f71f7/routers/api/v1/repo/issue.go#L319-L327)). \
All JSON input types must be defined as a struct in [modules/structs/](modules/structs/) ([example](https://github.com/go-gitea/gitea/blob/c620eb5b2d0d874da68ebd734d3864c5224f71f7/modules/structs/issue.go#L76-L91)) \
and referenced in [routers/api/v1/swagger/options.go](https://github.com/go-gitea/gitea/blob/c620eb5b2d0d874da68ebd734d3864c5224f71f7/routers/api/v1/swagger/options.go). \
They can then be used like [this example](https://github.com/go-gitea/gitea/blob/c620eb5b2d0d874da68ebd734d3864c5224f71f7/routers/api/v1/repo/issue.go#L318). \
All JSON responses must be defined as a struct in [modules/structs/](modules/structs/) ([example](https://github.com/go-gitea/gitea/blob/c620eb5b2d0d874da68ebd734d3864c5224f71f7/modules/structs/issue.go#L36-L68)) \
and referenced in its category in [routers/api/v1/swagger/](routers/api/v1/swagger/) ([example](https://github.com/go-gitea/gitea/blob/c620eb5b2d0d874da68ebd734d3864c5224f71f7/routers/api/v1/swagger/issue.go#L11-L16)) \
They can be used like [this example](https://github.com/go-gitea/gitea/blob/c620eb5b2d0d874da68ebd734d3864c5224f71f7/routers/api/v1/repo/issue.go#L277-L279).
### When to use what HTTP method
In general, HTTP methods are chosen as follows:
- **GET** endpoints return the requested object(s) and status **OK (200)**
- **DELETE** endpoints return the status **No Content (204)** and no content either
- **POST** endpoints are used to **create** new objects (e.g. a User) and return the status **Created (201)** and the created object
- **PUT** endpoints are used to **add/assign** existing Objects (e.g. a user to a team) and return the status **No Content (204)** and no content either
- **PATCH** endpoints are used to **edit/change** an existing object and return the changed object and the status **OK (200)**
### Requirements for API routes
All parameters of endpoints changing/editing an object must be optional (except the ones to identify the object, which are required).
Endpoints returning lists must
- support pagination (`page` & `limit` options in query)
- set `X-Total-Count` header via **SetTotalCountHeader** ([example](https://github.com/go-gitea/gitea/blob/7aae98cc5d4113f1e9918b7ee7dd09f67c189e3e/routers/api/v1/repo/issue.go#L444))

View File

@@ -1,17 +0,0 @@
# Frontend development
This document covers frontend-specific contribution expectations. For general contribution workflow, see [CONTRIBUTING.md](../CONTRIBUTING.md).
## Dependencies
For the frontend, we use [npm](https://www.npmjs.com/).
The same restrictions apply for frontend dependencies as for [backend dependencies](guideline-backend.md#dependencies), with the exceptions that the files for it are `package.json` and `package-lock.json`, and that new versions must always reference an existing version.
## Design guideline
Depending on your change, please read the
- [backend development guideline](https://docs.gitea.com/contributing/guidelines-backend)
- [frontend development guideline](https://docs.gitea.com/contributing/guidelines-frontend)
- [refactoring guideline](https://docs.gitea.com/contributing/guidelines-refactoring)

View File

@@ -1,115 +0,0 @@
# Release management
This document describes the release cycle, backports, versioning, and the release manager checklist. For everyday contribution workflow, see [CONTRIBUTING.md](../CONTRIBUTING.md).
## Backports and Frontports
### What is backported?
We backport PRs given the following circumstances:
1. Feature freeze is active, but `<version>-rc0` has not been released yet. Here, we backport as much as possible. <!-- TODO: Is that our definition with the new backport bot? -->
2. `rc0` has been released. Here, we only backport bug- and security-fixes, and small enhancements. Large PRs such as refactors are not backported anymore. <!-- TODO: Is that our definition with the new backport bot? -->
3. We never backport new features.
4. We never backport breaking changes except when
1. The breaking change has no effect on the vast majority of users
2. The component triggering the breaking change is marked as experimental
### How to backport?
In the past, it was necessary to manually backport your PRs. \
Now, that's not a requirement anymore as our [backport bot](https://github.com/GiteaBot) tries to create backports automatically once the PR is merged when the PR
- does not have the label `backport/manual`
- has the label `backport/<version>`
The `backport/manual` label signifies either that you want to backport the change yourself, or that there were conflicts when backporting, thus you **must** do it yourself.
### Format of backport PRs
The title of backport PRs should be
```
<original PR title> (#<original pr number>)
```
The first two lines of the summary of the backporting PR should be
```
Backport #<original pr number>
```
with the rest of the summary and labels matching the original PR.
### Frontports
Frontports behave exactly as described above for backports.
## Release Cycle
We use a release schedule so work, stabilization, and releases stay predictable.
### Cadence
- Aim for a major release about every three or four months.
- Roughly two or three months of general development, then about one month of testing and polish called the **release freeze**.
- *Starting with v1.26 the release cycle will be more predictable and follow a more regular schedule.*
### Release schedule
We will try to publish a new major version every three months:
- v1.26.0 in April 2026
- v1.27.0 in June 2026
- v1.28.0 in September 2026
- v1.29.0 in December 2026
#### How is the release handled?
- The release manager will tag the release candidate (e.g. `v1.26.0-rc0`) and publish it for testing in the **first week of the release month**.
- If there are no major issues, the release manager will check with the other maintainers and then tag the final release (e.g. `v1.26.0`) in the **one or two weeks following the release candidate**.
### Feature freeze
- Merge feature PRs before the freeze when you can.
- Feature PRs still open at the freeze move to the next milestone. Watch Discord for the freeze announcement.
- During the freeze, a **release branch** takes fixes backported from `main`. Release candidates ship for testing; the final release for that line is maintained from that branch.
### Patch releases
During a cycle we may ship patch releases for an older line. For example, if the latest release is v1.2, we can still publish v1.1.1 after v1.1.0.
### End of life (EOL)
We support per standard the last major release. For example, if the latest release is v1.26, we support v1.26 and v1.25, but not v1.24 anymore. We will only publish security fixes for the last major release, so if you are using an older release, please upgrade to a supported release as soon as possible.
Also we always try to support the latest on main branch, so if you are using the latest on main, you should be fine.
## Versions
Gitea has the `main` branch as a tip branch and has version branches
such as `release/v1.19`. `release/v1.19` is a release branch and we will
tag `v1.19.0` for binary download. If `v1.19.0` has bugs, we will accept
pull requests on the `release/v1.19` branch and publish a `v1.19.1` tag,
after bringing the bug fix also to the main branch.
Since the `main` branch is a tip version, if you wish to use Gitea
in production, please download the latest release tag version. All the
branches will be protected via GitHub, all the PRs to every branch must
be reviewed by two maintainers and must pass the automatic tests.
## Releasing Gitea
- Let MAJOR, MINOR and PATCH be Major, Minor and Patch version numbers, PATCH should be rc1, rc2, 0, 1, ...... MAJOR.MINOR will be kept the same as milestones on github or gitea in future.
- Before releasing, confirm all the version's milestone issues or PRs has been resolved. Then discuss the release on Discord channel #maintainers and get agreed with almost all the owners and mergers. Or you can declare the version and if nobody is against it in about several hours.
- If this is a big version first you have to create PR for changelog on branch `main` with PRs with label `changelog` and after it has been merged do following steps:
- Create `-dev` tag as `git tag -s -F release.notes vMAJOR.MINOR.0-dev` and push the tag as `git push origin vMAJOR.MINOR.0-dev`.
- When CI has finished building tag then you have to create a new branch named `release/vMAJOR.MINOR`
- If it is bugfix version create PR for changelog on branch `release/vMAJOR.MINOR` and wait till it is reviewed and merged.
- Add a tag as `git tag -s -F release.notes vMAJOR.MINOR.PATCH`, release.notes file could be a temporary file to only include the changelog this version which you added to `CHANGELOG.md`.
- And then push the tag as `git push origin vMAJOR.MINOR.$`. CI will automatically create a release and upload all the compiled binary. (But currently it doesn't add the release notes automatically. Maybe we should fix that.)
- If needed send a frontport PR for the changelog to branch `main` and update the version in `docs/config.yaml` to refer to the new version.
- Send PR to [blog repository](https://gitea.com/gitea/blog) announcing the release.
- Verify all release assets were correctly published through CI on dl.gitea.com and GitHub releases. Once ACKed:
- bump the version of https://dl.gitea.com/gitea/version.json
- merge the blog post PR
- announce the release in discord `#announcements`

View File

@@ -1,9 +1,9 @@
import arrayFunc from 'eslint-plugin-array-func'; import arrayFunc from 'eslint-plugin-array-func';
import comments from '@eslint-community/eslint-plugin-eslint-comments'; import comments from '@eslint-community/eslint-plugin-eslint-comments';
import deMorgan from 'eslint-plugin-de-morgan';
import github from 'eslint-plugin-github'; import github from 'eslint-plugin-github';
import globals from 'globals'; import globals from 'globals';
import importPlugin from 'eslint-plugin-import-x'; import importPlugin from 'eslint-plugin-import-x';
import noUseExtendNative from 'eslint-plugin-no-use-extend-native';
import playwright from 'eslint-plugin-playwright'; import playwright from 'eslint-plugin-playwright';
import regexp from 'eslint-plugin-regexp'; import regexp from 'eslint-plugin-regexp';
import sonarjs from 'eslint-plugin-sonarjs'; import sonarjs from 'eslint-plugin-sonarjs';
@@ -16,22 +16,10 @@ import vue from 'eslint-plugin-vue';
import vueScopedCss from 'eslint-plugin-vue-scoped-css'; import vueScopedCss from 'eslint-plugin-vue-scoped-css';
import wc from 'eslint-plugin-wc'; import wc from 'eslint-plugin-wc';
import {defineConfig, globalIgnores} from 'eslint/config'; import {defineConfig, globalIgnores} from 'eslint/config';
import type {ESLint} from 'eslint';
const jsExts = ['js', 'mjs', 'cjs'] as const; const jsExts = ['js', 'mjs', 'cjs'] as const;
const tsExts = ['ts', 'mts', 'cts'] as const; const tsExts = ['ts', 'mts', 'cts'] as const;
const restrictedSyntax = ['WithStatement', 'ForInStatement', 'LabeledStatement', 'SequenceExpression'];
const restrictedGlobals = [
{name: 'localStorage', message: 'Use `modules/user-settings.ts` instead.'},
{name: 'fetch', message: 'Use `modules/fetch.ts` instead.'},
];
const restrictedProperties = [
{object: 'window', property: 'localStorage', message: 'Use `modules/user-settings.ts` instead.'},
{object: 'globalThis', property: 'localStorage', message: 'Use `modules/user-settings.ts` instead.'},
{object: 'window', property: 'fetch', message: 'Use `modules/fetch.ts` instead.'},
{object: 'globalThis', property: 'fetch', message: 'Use `modules/fetch.ts` instead.'},
];
export default defineConfig([ export default defineConfig([
globalIgnores([ globalIgnores([
@@ -45,6 +33,10 @@ export default defineConfig([
languageOptions: { languageOptions: {
ecmaVersion: 'latest', ecmaVersion: 'latest',
sourceType: 'module', sourceType: 'module',
globals: {
...globals.browser,
...globals.node,
},
parser: typescriptParser, parser: typescriptParser,
parserOptions: { parserOptions: {
sourceType: 'module', sourceType: 'module',
@@ -57,19 +49,24 @@ export default defineConfig([
}, },
linterOptions: { linterOptions: {
reportUnusedDisableDirectives: 2, reportUnusedDisableDirectives: 2,
reportUnusedInlineConfigs: 2,
}, },
plugins: { plugins: {
'@eslint-community/eslint-comments': comments, '@eslint-community/eslint-comments': comments,
// @ts-expect-error
'@stylistic': stylistic, '@stylistic': stylistic,
'@typescript-eslint': typescriptPlugin.plugin, '@typescript-eslint': typescriptPlugin.plugin,
'array-func': arrayFunc, 'array-func': arrayFunc,
'de-morgan': deMorgan, // @ts-expect-error -- https://github.com/un-ts/eslint-plugin-import-x/issues/203
'import-x': importPlugin as unknown as ESLint.Plugin, // https://github.com/un-ts/eslint-plugin-import-x/issues/203 'import-x': importPlugin,
'no-use-extend-native': noUseExtendNative,
// @ts-expect-error
regexp, regexp,
// @ts-expect-error
sonarjs, sonarjs,
// @ts-expect-error
unicorn, unicorn,
github, github,
// @ts-expect-error
wc, wc,
}, },
settings: { settings: {
@@ -78,7 +75,7 @@ export default defineConfig([
'import-x/resolver': {'typescript': true}, 'import-x/resolver': {'typescript': true},
}, },
rules: { rules: {
'@eslint-community/eslint-comments/disable-enable-pair': [0], '@eslint-community/eslint-comments/disable-enable-pair': [2],
'@eslint-community/eslint-comments/no-aggregating-enable': [2], '@eslint-community/eslint-comments/no-aggregating-enable': [2],
'@eslint-community/eslint-comments/no-duplicate-disable': [2], '@eslint-community/eslint-comments/no-duplicate-disable': [2],
'@eslint-community/eslint-comments/no-restricted-disable': [0], '@eslint-community/eslint-comments/no-restricted-disable': [0],
@@ -158,11 +155,11 @@ export default defineConfig([
'@typescript-eslint/adjacent-overload-signatures': [0], '@typescript-eslint/adjacent-overload-signatures': [0],
'@typescript-eslint/array-type': [0], '@typescript-eslint/array-type': [0],
'@typescript-eslint/await-thenable': [2], '@typescript-eslint/await-thenable': [2],
'@typescript-eslint/ban-ts-comment': [2, {'ts-expect-error': true, 'ts-ignore': true, 'ts-nocheck': false, 'ts-check': false}], '@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/ban-tslint-comment': [0],
'@typescript-eslint/class-literal-property-style': [0], '@typescript-eslint/class-literal-property-style': [0],
'@typescript-eslint/class-methods-use-this': [0], '@typescript-eslint/class-methods-use-this': [0],
'@typescript-eslint/consistent-generic-constructors': [2, 'constructor'], '@typescript-eslint/consistent-generic-constructors': [0],
'@typescript-eslint/consistent-indexed-object-style': [0], '@typescript-eslint/consistent-indexed-object-style': [0],
'@typescript-eslint/consistent-return': [0], '@typescript-eslint/consistent-return': [0],
'@typescript-eslint/consistent-type-assertions': [2, {assertionStyle: 'as', objectLiteralTypeAssertions: 'allow'}], '@typescript-eslint/consistent-type-assertions': [2, {assertionStyle: 'as', objectLiteralTypeAssertions: 'allow'}],
@@ -181,7 +178,7 @@ export default defineConfig([
'@typescript-eslint/naming-convention': [0], '@typescript-eslint/naming-convention': [0],
'@typescript-eslint/no-array-constructor': [2], '@typescript-eslint/no-array-constructor': [2],
'@typescript-eslint/no-array-delete': [2], '@typescript-eslint/no-array-delete': [2],
'@typescript-eslint/no-base-to-string': [2], '@typescript-eslint/no-base-to-string': [0],
'@typescript-eslint/no-confusing-non-null-assertion': [2], '@typescript-eslint/no-confusing-non-null-assertion': [2],
'@typescript-eslint/no-confusing-void-expression': [0], '@typescript-eslint/no-confusing-void-expression': [0],
'@typescript-eslint/no-deprecated': [2], '@typescript-eslint/no-deprecated': [2],
@@ -213,7 +210,7 @@ export default defineConfig([
'@typescript-eslint/no-non-null-asserted-nullish-coalescing': [0], '@typescript-eslint/no-non-null-asserted-nullish-coalescing': [0],
'@typescript-eslint/no-non-null-asserted-optional-chain': [2], '@typescript-eslint/no-non-null-asserted-optional-chain': [2],
'@typescript-eslint/no-non-null-assertion': [0], '@typescript-eslint/no-non-null-assertion': [0],
'@typescript-eslint/no-redeclare': [2], '@typescript-eslint/no-redeclare': [0],
'@typescript-eslint/no-redundant-type-constituents': [2], '@typescript-eslint/no-redundant-type-constituents': [2],
'@typescript-eslint/no-require-imports': [2], '@typescript-eslint/no-require-imports': [2],
'@typescript-eslint/no-restricted-imports': [0], '@typescript-eslint/no-restricted-imports': [0],
@@ -224,7 +221,7 @@ export default defineConfig([
'@typescript-eslint/no-unnecessary-condition': [0], '@typescript-eslint/no-unnecessary-condition': [0],
'@typescript-eslint/no-unnecessary-qualifier': [0], '@typescript-eslint/no-unnecessary-qualifier': [0],
'@typescript-eslint/no-unnecessary-template-expression': [0], '@typescript-eslint/no-unnecessary-template-expression': [0],
'@typescript-eslint/no-unnecessary-type-arguments': [2], '@typescript-eslint/no-unnecessary-type-arguments': [0],
'@typescript-eslint/no-unnecessary-type-assertion': [2], '@typescript-eslint/no-unnecessary-type-assertion': [2],
'@typescript-eslint/no-unnecessary-type-constraint': [2], '@typescript-eslint/no-unnecessary-type-constraint': [2],
'@typescript-eslint/no-unnecessary-type-conversion': [2], '@typescript-eslint/no-unnecessary-type-conversion': [2],
@@ -237,12 +234,10 @@ export default defineConfig([
'@typescript-eslint/no-unsafe-member-access': [0], '@typescript-eslint/no-unsafe-member-access': [0],
'@typescript-eslint/no-unsafe-return': [0], '@typescript-eslint/no-unsafe-return': [0],
'@typescript-eslint/no-unsafe-unary-minus': [2], '@typescript-eslint/no-unsafe-unary-minus': [2],
'@typescript-eslint/no-unused-expressions': [2], '@typescript-eslint/no-unused-expressions': [0],
'@typescript-eslint/no-unused-private-class-members': [2],
'@typescript-eslint/no-unused-vars': [2, {vars: 'all', args: 'all', caughtErrors: 'all', ignoreRestSiblings: false, argsIgnorePattern: '^_', varsIgnorePattern: '^_', caughtErrorsIgnorePattern: '^_', destructuredArrayIgnorePattern: '^_'}], '@typescript-eslint/no-unused-vars': [2, {vars: 'all', args: 'all', caughtErrors: 'all', ignoreRestSiblings: false, argsIgnorePattern: '^_', varsIgnorePattern: '^_', caughtErrorsIgnorePattern: '^_', destructuredArrayIgnorePattern: '^_'}],
'@typescript-eslint/no-use-before-define': [2, {functions: false, classes: true, variables: true, allowNamedExports: true, typedefs: false, enums: false, ignoreTypeReferences: true}], '@typescript-eslint/no-use-before-define': [2, {functions: false, classes: true, variables: true, allowNamedExports: true, typedefs: false, enums: false, ignoreTypeReferences: true}],
'@typescript-eslint/no-useless-constructor': [0], '@typescript-eslint/no-useless-constructor': [0],
'@typescript-eslint/no-useless-default-assignment': [2],
'@typescript-eslint/no-useless-empty-export': [0], '@typescript-eslint/no-useless-empty-export': [0],
'@typescript-eslint/no-wrapper-object-types': [2], '@typescript-eslint/no-wrapper-object-types': [2],
'@typescript-eslint/non-nullable-type-assertion-style': [0], '@typescript-eslint/non-nullable-type-assertion-style': [0],
@@ -256,10 +251,10 @@ export default defineConfig([
'@typescript-eslint/prefer-function-type': [2], '@typescript-eslint/prefer-function-type': [2],
'@typescript-eslint/prefer-includes': [2], '@typescript-eslint/prefer-includes': [2],
'@typescript-eslint/prefer-literal-enum-member': [0], '@typescript-eslint/prefer-literal-enum-member': [0],
'@typescript-eslint/prefer-namespace-keyword': [2], '@typescript-eslint/prefer-namespace-keyword': [0],
'@typescript-eslint/prefer-nullish-coalescing': [0], '@typescript-eslint/prefer-nullish-coalescing': [0],
'@typescript-eslint/prefer-optional-chain': [2, {requireNullish: true}], '@typescript-eslint/prefer-optional-chain': [2, {requireNullish: true}],
'@typescript-eslint/prefer-promise-reject-errors': [2], '@typescript-eslint/prefer-promise-reject-errors': [0],
'@typescript-eslint/prefer-readonly': [0], '@typescript-eslint/prefer-readonly': [0],
'@typescript-eslint/prefer-readonly-parameter-types': [0], '@typescript-eslint/prefer-readonly-parameter-types': [0],
'@typescript-eslint/prefer-reduce-type-parameter': [0], '@typescript-eslint/prefer-reduce-type-parameter': [0],
@@ -270,10 +265,9 @@ export default defineConfig([
'@typescript-eslint/require-array-sort-compare': [0], '@typescript-eslint/require-array-sort-compare': [0],
'@typescript-eslint/require-await': [0], '@typescript-eslint/require-await': [0],
'@typescript-eslint/restrict-plus-operands': [2], '@typescript-eslint/restrict-plus-operands': [2],
'@typescript-eslint/restrict-template-expressions': [2], '@typescript-eslint/restrict-template-expressions': [0],
'@typescript-eslint/return-await': [0], '@typescript-eslint/return-await': [0],
'@typescript-eslint/strict-boolean-expressions': [0], '@typescript-eslint/strict-boolean-expressions': [0],
'@typescript-eslint/strict-void-return': [0],
'@typescript-eslint/switch-exhaustiveness-check': [0], '@typescript-eslint/switch-exhaustiveness-check': [0],
'@typescript-eslint/triple-slash-reference': [2], '@typescript-eslint/triple-slash-reference': [2],
'@typescript-eslint/typedef': [0], '@typescript-eslint/typedef': [0],
@@ -297,8 +291,6 @@ export default defineConfig([
'consistent-this': [0], 'consistent-this': [0],
'constructor-super': [2], 'constructor-super': [2],
'curly': [0], 'curly': [0],
'de-morgan/no-negated-conjunction': [2],
'de-morgan/no-negated-disjunction': [2],
'default-case-last': [2], 'default-case-last': [2],
'default-case': [0], 'default-case': [0],
'default-param-last': [0], 'default-param-last': [0],
@@ -329,7 +321,7 @@ export default defineConfig([
'github/no-innerText': [2], 'github/no-innerText': [2],
'github/no-then': [2], 'github/no-then': [2],
'github/no-useless-passive': [2], 'github/no-useless-passive': [2],
'github/prefer-observers': [0], 'github/prefer-observers': [2],
'github/require-passive-events': [2], 'github/require-passive-events': [2],
'github/unescaped-html-literal': [2], 'github/unescaped-html-literal': [2],
'grouped-accessor-pairs': [2], 'grouped-accessor-pairs': [2],
@@ -346,7 +338,7 @@ export default defineConfig([
'import-x/first': [2], 'import-x/first': [2],
'import-x/group-exports': [0], 'import-x/group-exports': [0],
'import-x/max-dependencies': [0], 'import-x/max-dependencies': [0],
'import-x/named': [0], 'import-x/named': [2],
'import-x/namespace': [0], 'import-x/namespace': [0],
'import-x/newline-after-import': [0], 'import-x/newline-after-import': [0],
'import-x/no-absolute-path': [0], 'import-x/no-absolute-path': [0],
@@ -374,7 +366,7 @@ export default defineConfig([
'import-x/no-self-import': [2], 'import-x/no-self-import': [2],
'import-x/no-unassigned-import': [0], 'import-x/no-unassigned-import': [0],
'import-x/no-unresolved': [2, {commonjs: true, ignore: ['\\?.+$']}], 'import-x/no-unresolved': [2, {commonjs: true, ignore: ['\\?.+$']}],
'import-x/no-unused-modules': [0], // incompatible with eslint 9 // 'import-x/no-unused-modules': [2, {unusedExports: true}], // not compatible with eslint 9
'import-x/no-useless-path-segments': [2, {commonjs: true}], 'import-x/no-useless-path-segments': [2, {commonjs: true}],
'import-x/no-webpack-loader-syntax': [2], 'import-x/no-webpack-loader-syntax': [2],
'import-x/order': [0], 'import-x/order': [0],
@@ -441,7 +433,7 @@ export default defineConfig([
'no-import-assign': [2], 'no-import-assign': [2],
'no-inline-comments': [0], 'no-inline-comments': [0],
'no-inner-declarations': [2], 'no-inner-declarations': [2],
'no-invalid-regexp': [0], // handled by regexp/no-invalid-regexp 'no-invalid-regexp': [2],
'no-invalid-this': [0], 'no-invalid-this': [0],
'no-irregular-whitespace': [2], 'no-irregular-whitespace': [2],
'no-iterator': [2], 'no-iterator': [2],
@@ -555,7 +547,7 @@ export default defineConfig([
'no-new-func': [0], // handled by @typescript-eslint/no-implied-eval 'no-new-func': [0], // handled by @typescript-eslint/no-implied-eval
'no-new-native-nonconstructor': [2], 'no-new-native-nonconstructor': [2],
'no-new-object': [2], 'no-new-object': [2],
'no-new-symbol': [0], // handled by no-new-native-nonconstructor 'no-new-symbol': [2],
'no-new-wrappers': [2], 'no-new-wrappers': [2],
'no-new': [0], 'no-new': [0],
'no-nonoctal-decimal-escape': [2], 'no-nonoctal-decimal-escape': [2],
@@ -570,12 +562,9 @@ export default defineConfig([
'no-redeclare': [0], // must be disabled for typescript overloads 'no-redeclare': [0], // must be disabled for typescript overloads
'no-regex-spaces': [2], 'no-regex-spaces': [2],
'no-restricted-exports': [0], 'no-restricted-exports': [0],
'no-restricted-globals': [2, ...restrictedGlobals], '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'],
'no-restricted-properties': [2, ...restrictedProperties], 'no-restricted-imports': [0],
'no-restricted-imports': [2, {paths: [ 'no-restricted-syntax': [2, ...restrictedSyntax, {selector: 'CallExpression[callee.name="fetch"]', message: 'use modules/fetch.ts instead'}],
{name: 'jquery', message: 'Use the global $ instead', allowTypeImports: true},
]}],
'no-restricted-syntax': [2, 'WithStatement', 'ForInStatement', 'LabeledStatement', 'SequenceExpression'],
'no-return-assign': [0], 'no-return-assign': [0],
'no-script-url': [2], 'no-script-url': [2],
'no-self-assign': [2, {props: true}], 'no-self-assign': [2, {props: true}],
@@ -588,11 +577,10 @@ export default defineConfig([
'no-template-curly-in-string': [2], 'no-template-curly-in-string': [2],
'no-ternary': [0], 'no-ternary': [0],
'no-this-before-super': [2], 'no-this-before-super': [2],
'no-throw-literal': [0], // handled by @typescript-eslint/only-throw-error 'no-throw-literal': [2],
'no-undef-init': [2], 'no-undef-init': [2],
'no-undef': [2], // it is still needed by eslint & IDE to prompt undefined names in real time 'no-undef': [2], // it is still needed by eslint & IDE to prompt undefined names in real time
'no-undefined': [0], 'no-undefined': [0],
'no-unassigned-vars': [2],
'no-underscore-dangle': [0], 'no-underscore-dangle': [0],
'no-unexpected-multiline': [2], 'no-unexpected-multiline': [2],
'no-unmodified-loop-condition': [2], 'no-unmodified-loop-condition': [2],
@@ -601,13 +589,13 @@ export default defineConfig([
'no-unreachable': [2], 'no-unreachable': [2],
'no-unsafe-finally': [2], 'no-unsafe-finally': [2],
'no-unsafe-negation': [2], 'no-unsafe-negation': [2],
'no-unused-expressions': [0], // handled by @typescript-eslint/no-unused-expressions 'no-unused-expressions': [2],
'no-unused-labels': [2], 'no-unused-labels': [2],
'no-unused-private-class-members': [0], // handled by @typescript-eslint/no-unused-private-class-members 'no-unused-private-class-members': [2],
'no-unused-vars': [0], // handled by @typescript-eslint/no-unused-vars 'no-unused-vars': [0], // handled by @typescript-eslint/no-unused-vars
'no-use-before-define': [0], // handled by @typescript-eslint/no-use-before-define 'no-use-before-define': [0], // handled by @typescript-eslint/no-use-before-define
'no-useless-assignment': [2], 'no-use-extend-native/no-use-extend-native': [2],
'no-useless-backreference': [0], // handled by regexp/no-useless-backreference 'no-useless-backreference': [2],
'no-useless-call': [2], 'no-useless-call': [2],
'no-useless-catch': [2], 'no-useless-catch': [2],
'no-useless-computed-key': [2], 'no-useless-computed-key': [2],
@@ -615,7 +603,7 @@ export default defineConfig([
'no-useless-constructor': [2], 'no-useless-constructor': [2],
'no-useless-escape': [2], 'no-useless-escape': [2],
'no-useless-rename': [2], 'no-useless-rename': [2],
'no-useless-return': [0], // handled by sonarjs/no-redundant-jump 'no-useless-return': [2],
'no-var': [2], 'no-var': [2],
'no-void': [2], 'no-void': [2],
'no-warning-comments': [0], 'no-warning-comments': [0],
@@ -624,7 +612,7 @@ export default defineConfig([
'one-var-declaration-per-line': [0], 'one-var-declaration-per-line': [0],
'one-var': [0], 'one-var': [0],
'operator-assignment': [2, 'always'], 'operator-assignment': [2, 'always'],
'operator-linebreak': [0], // handled by @stylistic/operator-linebreak 'operator-linebreak': [2, 'after'],
'prefer-arrow-callback': [2, {allowNamedFunctions: true, allowUnboundThis: true}], 'prefer-arrow-callback': [2, {allowNamedFunctions: true, allowUnboundThis: true}],
'prefer-const': [2, {destructuring: 'all', ignoreReadBeforeAssign: true}], 'prefer-const': [2, {destructuring: 'all', ignoreReadBeforeAssign: true}],
'prefer-destructuring': [0], 'prefer-destructuring': [0],
@@ -633,20 +621,19 @@ export default defineConfig([
'prefer-numeric-literals': [2], 'prefer-numeric-literals': [2],
'prefer-object-has-own': [2], 'prefer-object-has-own': [2],
'prefer-object-spread': [2], 'prefer-object-spread': [2],
'prefer-promise-reject-errors': [0], // handled by @typescript-eslint/prefer-promise-reject-errors 'prefer-promise-reject-errors': [2, {allowEmptyReject: false}],
'prefer-regex-literals': [2], 'prefer-regex-literals': [2],
'prefer-rest-params': [2], 'prefer-rest-params': [2],
'prefer-spread': [2], 'prefer-spread': [2],
'prefer-template': [2], 'prefer-template': [2],
'preserve-caught-error': [0], 'radix': [2, 'as-needed'],
'radix': [0],
'regexp/confusing-quantifier': [2], 'regexp/confusing-quantifier': [2],
'regexp/control-character-escape': [2], 'regexp/control-character-escape': [2],
'regexp/hexadecimal-escape': [0], 'regexp/hexadecimal-escape': [0],
'regexp/letter-case': [0], 'regexp/letter-case': [0],
'regexp/match-any': [2], 'regexp/match-any': [2],
'regexp/negation': [2], 'regexp/negation': [2],
'regexp/no-contradiction-with-assertion': [2], 'regexp/no-contradiction-with-assertion': [0],
'regexp/no-control-character': [0], 'regexp/no-control-character': [0],
'regexp/no-dupe-characters-character-class': [2], 'regexp/no-dupe-characters-character-class': [2],
'regexp/no-dupe-disjunctions': [2], 'regexp/no-dupe-disjunctions': [2],
@@ -662,8 +649,8 @@ export default defineConfig([
'regexp/no-invisible-character': [2], 'regexp/no-invisible-character': [2],
'regexp/no-lazy-ends': [2], 'regexp/no-lazy-ends': [2],
'regexp/no-legacy-features': [2], 'regexp/no-legacy-features': [2],
'regexp/no-misleading-capturing-group': [2], 'regexp/no-misleading-capturing-group': [0],
'regexp/no-misleading-unicode-character': [2], 'regexp/no-misleading-unicode-character': [0],
'regexp/no-missing-g-flag': [2], 'regexp/no-missing-g-flag': [2],
'regexp/no-non-standard-flag': [2], 'regexp/no-non-standard-flag': [2],
'regexp/no-obscure-range': [2], 'regexp/no-obscure-range': [2],
@@ -705,7 +692,7 @@ export default defineConfig([
'regexp/prefer-question-quantifier': [2], 'regexp/prefer-question-quantifier': [2],
'regexp/prefer-range': [2], 'regexp/prefer-range': [2],
'regexp/prefer-regexp-exec': [2], 'regexp/prefer-regexp-exec': [2],
'regexp/prefer-regexp-test': [0], // handled by unicorn/prefer-regexp-test 'regexp/prefer-regexp-test': [2],
'regexp/prefer-result-array-groups': [0], 'regexp/prefer-result-array-groups': [0],
'regexp/prefer-set-operation': [2], 'regexp/prefer-set-operation': [2],
'regexp/prefer-star-quantifier': [2], 'regexp/prefer-star-quantifier': [2],
@@ -735,7 +722,7 @@ export default defineConfig([
'sonarjs/no-empty-collection': [2], 'sonarjs/no-empty-collection': [2],
'sonarjs/no-extra-arguments': [2], 'sonarjs/no-extra-arguments': [2],
'sonarjs/no-gratuitous-expressions': [2], 'sonarjs/no-gratuitous-expressions': [2],
'sonarjs/no-identical-conditions': [0], // handled by no-dupe-else-if 'sonarjs/no-identical-conditions': [2],
'sonarjs/no-identical-expressions': [2], 'sonarjs/no-identical-expressions': [2],
'sonarjs/no-identical-functions': [2, 5], 'sonarjs/no-identical-functions': [2, 5],
'sonarjs/no-ignored-return': [2], 'sonarjs/no-ignored-return': [2],
@@ -748,7 +735,7 @@ export default defineConfig([
'sonarjs/no-small-switch': [0], 'sonarjs/no-small-switch': [0],
'sonarjs/no-unused-collection': [2], 'sonarjs/no-unused-collection': [2],
'sonarjs/no-use-of-empty-return-value': [2], 'sonarjs/no-use-of-empty-return-value': [2],
'sonarjs/no-useless-catch': [0], // handled by no-useless-catch 'sonarjs/no-useless-catch': [2],
'sonarjs/non-existent-operator': [2], 'sonarjs/non-existent-operator': [2],
'sonarjs/prefer-immediate-return': [0], 'sonarjs/prefer-immediate-return': [0],
'sonarjs/prefer-object-literal': [0], 'sonarjs/prefer-object-literal': [0],
@@ -764,7 +751,6 @@ export default defineConfig([
'unicorn/catch-error-name': [0], 'unicorn/catch-error-name': [0],
'unicorn/consistent-destructuring': [2], 'unicorn/consistent-destructuring': [2],
'unicorn/consistent-empty-array-spread': [2], 'unicorn/consistent-empty-array-spread': [2],
'unicorn/consistent-template-literal-escape': [2],
'unicorn/consistent-existence-index-check': [0], 'unicorn/consistent-existence-index-check': [0],
'unicorn/consistent-function-scoping': [0], 'unicorn/consistent-function-scoping': [0],
'unicorn/custom-error-definition': [0], 'unicorn/custom-error-definition': [0],
@@ -776,7 +762,6 @@ export default defineConfig([
'unicorn/filename-case': [0], 'unicorn/filename-case': [0],
'unicorn/import-index': [0], 'unicorn/import-index': [0],
'unicorn/import-style': [0], 'unicorn/import-style': [0],
'unicorn/isolated-functions': [2, {functions: []}],
'unicorn/new-for-builtins': [2], 'unicorn/new-for-builtins': [2],
'unicorn/no-abusive-eslint-disable': [0], 'unicorn/no-abusive-eslint-disable': [0],
'unicorn/no-anonymous-default-export': [0], 'unicorn/no-anonymous-default-export': [0],
@@ -792,7 +777,6 @@ export default defineConfig([
'unicorn/no-empty-file': [2], 'unicorn/no-empty-file': [2],
'unicorn/no-for-loop': [0], 'unicorn/no-for-loop': [0],
'unicorn/no-hex-escape': [0], 'unicorn/no-hex-escape': [0],
'unicorn/no-immediate-mutation': [0],
'unicorn/no-instanceof-array': [0], 'unicorn/no-instanceof-array': [0],
'unicorn/no-invalid-fetch-options': [2], 'unicorn/no-invalid-fetch-options': [2],
'unicorn/no-invalid-remove-event-listener': [2], 'unicorn/no-invalid-remove-event-listener': [2],
@@ -816,11 +800,9 @@ export default defineConfig([
'unicorn/no-unnecessary-await': [2], 'unicorn/no-unnecessary-await': [2],
'unicorn/no-unnecessary-polyfills': [2], 'unicorn/no-unnecessary-polyfills': [2],
'unicorn/no-unreadable-array-destructuring': [0], 'unicorn/no-unreadable-array-destructuring': [0],
'unicorn/no-unreadable-iife': [0], 'unicorn/no-unreadable-iife': [2],
'unicorn/no-unused-properties': [2], 'unicorn/no-unused-properties': [2],
'unicorn/no-useless-collection-argument': [2],
'unicorn/no-useless-fallback-in-spread': [2], 'unicorn/no-useless-fallback-in-spread': [2],
'unicorn/no-useless-iterator-to-array': [2],
'unicorn/no-useless-length-check': [2], 'unicorn/no-useless-length-check': [2],
'unicorn/no-useless-promise-resolve-reject': [2], 'unicorn/no-useless-promise-resolve-reject': [2],
'unicorn/no-useless-spread': [2], 'unicorn/no-useless-spread': [2],
@@ -830,9 +812,9 @@ export default defineConfig([
'unicorn/number-literal-case': [0], 'unicorn/number-literal-case': [0],
'unicorn/numeric-separators-style': [0], 'unicorn/numeric-separators-style': [0],
'unicorn/prefer-add-event-listener': [2], 'unicorn/prefer-add-event-listener': [2],
'unicorn/prefer-array-find': [0], // handled by @typescript-eslint/prefer-find 'unicorn/prefer-array-find': [2],
'unicorn/prefer-array-flat': [2],
'unicorn/prefer-array-flat-map': [2], 'unicorn/prefer-array-flat-map': [2],
'unicorn/prefer-array-flat': [2],
'unicorn/prefer-array-index-of': [2], 'unicorn/prefer-array-index-of': [2],
'unicorn/prefer-array-some': [2], 'unicorn/prefer-array-some': [2],
'unicorn/prefer-at': [0], 'unicorn/prefer-at': [0],
@@ -847,7 +829,7 @@ export default defineConfig([
'unicorn/prefer-event-target': [2], 'unicorn/prefer-event-target': [2],
'unicorn/prefer-export-from': [0], 'unicorn/prefer-export-from': [0],
'unicorn/prefer-global-this': [0], 'unicorn/prefer-global-this': [0],
'unicorn/prefer-includes': [0], // handled by @typescript-eslint/prefer-includes 'unicorn/prefer-includes': [2],
'unicorn/prefer-json-parse-buffer': [0], 'unicorn/prefer-json-parse-buffer': [0],
'unicorn/prefer-keyboard-event-key': [2], 'unicorn/prefer-keyboard-event-key': [2],
'unicorn/prefer-logical-operator-over-ternary': [2], 'unicorn/prefer-logical-operator-over-ternary': [2],
@@ -867,15 +849,13 @@ export default defineConfig([
'unicorn/prefer-query-selector': [2], 'unicorn/prefer-query-selector': [2],
'unicorn/prefer-reflect-apply': [0], 'unicorn/prefer-reflect-apply': [0],
'unicorn/prefer-regexp-test': [2], 'unicorn/prefer-regexp-test': [2],
'unicorn/prefer-response-static-json': [2],
'unicorn/prefer-set-has': [0], 'unicorn/prefer-set-has': [0],
'unicorn/prefer-set-size': [2], 'unicorn/prefer-set-size': [2],
'unicorn/prefer-simple-condition-first': [0],
'unicorn/prefer-spread': [0], 'unicorn/prefer-spread': [0],
'unicorn/prefer-string-raw': [0], 'unicorn/prefer-string-raw': [0],
'unicorn/prefer-string-replace-all': [0], 'unicorn/prefer-string-replace-all': [0],
'unicorn/prefer-string-slice': [0], 'unicorn/prefer-string-slice': [0],
'unicorn/prefer-string-starts-ends-with': [0], // handled by @typescript-eslint/prefer-string-starts-ends-with 'unicorn/prefer-string-starts-ends-with': [2],
'unicorn/prefer-string-trim-start-end': [2], 'unicorn/prefer-string-trim-start-end': [2],
'unicorn/prefer-structured-clone': [2], 'unicorn/prefer-structured-clone': [2],
'unicorn/prefer-switch': [0], 'unicorn/prefer-switch': [0],
@@ -889,7 +869,6 @@ export default defineConfig([
'unicorn/require-post-message-target-origin': [0], 'unicorn/require-post-message-target-origin': [0],
'unicorn/string-content': [0], 'unicorn/string-content': [0],
'unicorn/switch-case-braces': [0], 'unicorn/switch-case-braces': [0],
'unicorn/switch-case-break-position': [2],
'unicorn/template-indent': [2], 'unicorn/template-indent': [2],
'unicorn/text-encoding-identifier-case': [0], 'unicorn/text-encoding-identifier-case': [0],
'unicorn/throw-new-error': [2], 'unicorn/throw-new-error': [2],
@@ -921,13 +900,12 @@ export default defineConfig([
'yoda': [2, 'never'], 'yoda': [2, 'never'],
}, },
}, },
// @ts-expect-error
{ {
...playwright.configs['flat/recommended'], ...playwright.configs['flat/recommended'],
files: ['tests/e2e/**/*.test.ts'], files: ['tests/e2e/**'],
languageOptions: {globals: {...globals.nodeBuiltin, ...globals.browser}},
rules: { rules: {
...playwright.configs['flat/recommended'].rules, ...playwright.configs['flat/recommended'].rules,
'playwright/expect-expect': [0],
}, },
}, },
{ {
@@ -938,19 +916,27 @@ export default defineConfig([
}, },
}, },
extends: [ extends: [
// @ts-expect-error
vue.configs['flat/recommended'], vue.configs['flat/recommended'],
vueScopedCss.configs.recommended as any, // @ts-expect-error
vueScopedCss.configs['flat/recommended'],
], ],
rules: { rules: {
'vue/attributes-order': [0], 'vue/attributes-order': [0],
'vue/html-closing-bracket-spacing': [2, {startTag: 'never', endTag: 'never', selfClosingTag: 'never'}], 'vue/html-closing-bracket-spacing': [2, {startTag: 'never', endTag: 'never', selfClosingTag: 'never'}],
'vue/max-attributes-per-line': [0], 'vue/max-attributes-per-line': [0],
'vue/singleline-html-element-content-newline': [0], 'vue/singleline-html-element-content-newline': [0],
'vue/require-typed-ref': [2], },
},
{
files: ['web_src/js/modules/fetch.ts', 'web_src/js/standalone/**/*'],
rules: {
'no-restricted-syntax': [2, ...restrictedSyntax],
}, },
}, },
{ {
files: ['**/*.test.ts', 'web_src/js/test/setup.ts'], files: ['**/*.test.ts', 'web_src/js/test/setup.ts'],
// @ts-expect-error - https://github.com/vitest-dev/eslint-plugin-vitest/issues/737
plugins: {vitest}, plugins: {vitest},
languageOptions: {globals: globals.vitest}, languageOptions: {globals: globals.vitest},
rules: { rules: {
@@ -974,7 +960,6 @@ export default defineConfig([
'vitest/no-interpolation-in-snapshots': [0], 'vitest/no-interpolation-in-snapshots': [0],
'vitest/no-large-snapshots': [0], 'vitest/no-large-snapshots': [0],
'vitest/no-mocks-import': [0], 'vitest/no-mocks-import': [0],
'vitest/no-importing-vitest-globals': [2],
'vitest/no-restricted-matchers': [0], 'vitest/no-restricted-matchers': [0],
'vitest/no-restricted-vi-methods': [0], 'vitest/no-restricted-vi-methods': [0],
'vitest/no-standalone-expect': [0], 'vitest/no-standalone-expect': [0],
@@ -1003,24 +988,42 @@ export default defineConfig([
'vitest/require-to-throw-message': [0], 'vitest/require-to-throw-message': [0],
'vitest/require-top-level-describe': [0], 'vitest/require-top-level-describe': [0],
'vitest/valid-describe-callback': [2], 'vitest/valid-describe-callback': [2],
'vitest/valid-expect': [2, {maxArgs: 2}], 'vitest/valid-expect': [2],
'vitest/valid-expect-in-promise': [2],
'vitest/valid-title': [2], 'vitest/valid-title': [2],
}, },
}, },
{
files: ['web_src/js/types.ts'],
rules: {
'import-x/no-unused-modules': [0],
},
},
{ {
files: ['**/*.d.ts'], files: ['**/*.d.ts'],
rules: { rules: {
'import-x/no-unused-modules': [0],
'@typescript-eslint/consistent-type-definitions': [0], '@typescript-eslint/consistent-type-definitions': [0],
'@typescript-eslint/consistent-type-imports': [0], '@typescript-eslint/consistent-type-imports': [0],
}, },
}, },
{ {
files: ['*', 'tools/**/*', 'tests/**/*'], files: ['*.config.*'],
languageOptions: {globals: globals.nodeBuiltin}, rules: {
'import-x/no-unused-modules': [0],
},
},
{
files: ['web_src/**/*', 'docs/**/*'],
languageOptions: {globals: globals.browser},
}, },
{ {
files: ['web_src/**/*'], files: ['web_src/**/*'],
languageOptions: {globals: {...globals.browser, ...globals.jquery}}, languageOptions: {
globals: {
...globals.browser,
__webpack_public_path__: true,
process: false, // https://github.com/webpack/webpack/issues/15833
},
},
}, },
]); ]);

View File

@@ -1,30 +0,0 @@
import {defineConfig, globalIgnores} from 'eslint/config';
import json from '@eslint/json';
export default defineConfig([
globalIgnores([
'**/.venv',
'**/node_modules',
'**/public',
]),
{
files: ['**/*.json'],
plugins: {json},
language: 'json/json',
extends: ['json/recommended'],
},
{
files: [
'tsconfig.json',
'.devcontainer/*.json',
'.vscode/*.json',
'contrib/ide/vscode/*.json',
],
plugins: {json},
language: 'json/jsonc',
languageOptions: {
allowTrailingCommas: true,
},
extends: ['json/recommended'],
},
]);

40
flake.lock generated
View File

@@ -1,12 +1,30 @@
{ {
"nodes": { "nodes": {
"flake-utils": {
"inputs": {
"systems": "systems"
},
"locked": {
"lastModified": 1731533236,
"narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "11707dc2f618dd54ca8739b309ec4fc024de578b",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "flake-utils",
"type": "github"
}
},
"nixpkgs": { "nixpkgs": {
"locked": { "locked": {
"lastModified": 1775710090, "lastModified": 1755186698,
"narHash": "sha256-ar3rofg+awPB8QXDaFJhJ2jJhu+KqN/PRCXeyuXR76E=", "narHash": "sha256-wNO3+Ks2jZJ4nTHMuks+cxAiVBGNuEBXsT29Bz6HASo=",
"owner": "nixos", "owner": "nixos",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "4c1018dae018162ec878d42fec712642d214fdfa", "rev": "fbcf476f790d8a217c3eab4e12033dc4a0f6d23c",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -18,8 +36,24 @@
}, },
"root": { "root": {
"inputs": { "inputs": {
"flake-utils": "flake-utils",
"nixpkgs": "nixpkgs" "nixpkgs": "nixpkgs"
} }
},
"systems": {
"locked": {
"lastModified": 1681028828,
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
"owner": "nix-systems",
"repo": "default",
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
"type": "github"
},
"original": {
"owner": "nix-systems",
"repo": "default",
"type": "github"
}
} }
}, },
"root": "root", "root": "root",

139
flake.nix
View File

@@ -1,94 +1,73 @@
{ {
inputs = { inputs = {
nixpkgs.url = "github:nixos/nixpkgs?ref=nixos-unstable"; nixpkgs.url = "github:nixos/nixpkgs?ref=nixos-unstable";
flake-utils.url = "github:numtide/flake-utils";
}; };
outputs = outputs =
{ nixpkgs, ... }: { nixpkgs, flake-utils, ... }:
let flake-utils.lib.eachDefaultSystem (
supportedSystems = [ system:
"aarch64-darwin" let
"aarch64-linux" pkgs = nixpkgs.legacyPackages.${system};
"x86_64-darwin" in
"x86_64-linux" {
]; devShells.default =
with pkgs;
forEachSupportedSystem =
f:
nixpkgs.lib.genAttrs supportedSystems (
system:
let let
pkgs = import nixpkgs { # only bump toolchain versions here
inherit system; go = go_1_25;
nodejs = nodejs_24;
python3 = python312;
pnpm = pnpm_10;
# Platform-specific dependencies
linuxOnlyInputs = lib.optionals pkgs.stdenv.isLinux [
glibc.static
];
linuxOnlyEnv = lib.optionalAttrs pkgs.stdenv.isLinux {
CFLAGS = "-I${glibc.static.dev}/include";
LDFLAGS = "-L ${glibc.static}/lib";
}; };
in in
f { inherit pkgs; } pkgs.mkShell (
); {
in buildInputs = [
{ # generic
devShells = forEachSupportedSystem ( git
{ pkgs, ... }: git-lfs
{ gnumake
default = gnused
let gnutar
inherit (pkgs) lib; gzip
zip
# only bump toolchain versions here # frontend
go = pkgs.go_1_26; nodejs
nodejs = pkgs.nodejs_24; pnpm
python3 = pkgs.python314; cairo
pnpm = pkgs.pnpm_10; pixman
pkg-config
# Platform-specific dependencies # linting
linuxOnlyInputs = lib.optionals pkgs.stdenv.isLinux [ python3
pkgs.glibc.static uv
];
linuxOnlyEnv = lib.optionalAttrs pkgs.stdenv.isLinux { # backend
CFLAGS = "-I${pkgs.glibc.static.dev}/include"; go
LDFLAGS = "-L ${pkgs.glibc.static}/lib"; gofumpt
}; sqlite
in ]
pkgs.mkShell { ++ linuxOnlyInputs;
packages =
with pkgs;
[
# generic
git
git-lfs
gnumake
gnused
gnutar
gzip
zip
# frontend GO = "${go}/bin/go";
nodejs GOROOT = "${go}/share/go";
pnpm
cairo
pixman
pkg-config
# linting TAGS = "sqlite sqlite_unlock_notify";
python3 STATIC = "true";
uv }
// linuxOnlyEnv
# backend );
go }
gofumpt );
sqlite
]
++ linuxOnlyInputs;
env = {
GO = "${go}/bin/go";
GOROOT = "${go}/share/go";
TAGS = "sqlite sqlite_unlock_notify";
STATIC = "true";
}
// linuxOnlyEnv;
};
}
);
};
} }

280
go.mod
View File

@@ -1,6 +1,6 @@
module code.gitea.io/gitea module code.gitea.io/gitea
go 1.26.2 go 1.25.4
// 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:
@@ -9,200 +9,208 @@ godebug x509negativeserial=1
require ( require (
code.gitea.io/actions-proto-go v0.4.1 code.gitea.io/actions-proto-go v0.4.1
code.gitea.io/sdk/gitea v0.24.1 code.gitea.io/gitea-vet v0.2.3
code.gitea.io/sdk/gitea v0.22.0
codeberg.org/gusted/mcaptcha v0.0.0-20220723083913-4f3072e1d570 codeberg.org/gusted/mcaptcha v0.0.0-20220723083913-4f3072e1d570
connectrpc.com/connect v1.19.1 connectrpc.com/connect v1.18.1
gitea.com/go-chi/binding v0.0.0-20260414111559-654cea7ac60a 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
gitea.com/go-chi/session v0.0.0-20251124165456-68e0254e989e gitea.com/go-chi/session v0.0.0-20240316035857-16768d98ec96
gitea.com/lunny/dingtalk_webhook v0.0.0-20171025031554-e3534c89ef96 gitea.com/lunny/dingtalk_webhook v0.0.0-20171025031554-e3534c89ef96
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.4 github.com/42wim/httpsig v1.2.3
github.com/42wim/sshsig v0.0.0-20260317195500-b9f38cf0d432 github.com/42wim/sshsig v0.0.0-20250502153856-5100632e8920
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.19.0 github.com/Azure/azure-sdk-for-go/sdk/azcore v1.19.0
github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.6.2 github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.6.2
github.com/Azure/go-ntlmssp v0.1.0 github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358
github.com/ProtonMail/go-crypto v1.4.1 github.com/ProtonMail/go-crypto v1.3.0
github.com/PuerkitoBio/goquery v1.12.0 github.com/PuerkitoBio/goquery v1.10.3
github.com/SaveTheRbtz/zstd-seekable-format-go/pkg v0.8.0 github.com/SaveTheRbtz/zstd-seekable-format-go/pkg v0.8.0
github.com/alecthomas/chroma/v2 v2.23.1 github.com/alecthomas/chroma/v2 v2.20.0
github.com/aws/aws-sdk-go-v2/credentials v1.19.14 github.com/aws/aws-sdk-go-v2/credentials v1.18.10
github.com/aws/aws-sdk-go-v2/service/codecommit v1.33.12 github.com/aws/aws-sdk-go-v2/service/codecommit v1.32.2
github.com/blakesmith/ar v0.0.0-20190502131153-809d4375e1fb github.com/blakesmith/ar v0.0.0-20190502131153-809d4375e1fb
github.com/blevesearch/bleve/v2 v2.5.7 github.com/blevesearch/bleve/v2 v2.5.3
github.com/bohde/codel v0.2.0 github.com/bohde/codel v0.2.0
github.com/buildkite/terminal-to-html/v3 v3.16.8 github.com/buildkite/terminal-to-html/v3 v3.16.8
github.com/caddyserver/certmagic v0.25.2 github.com/caddyserver/certmagic v0.24.0
github.com/charmbracelet/git-lfs-transfer v0.1.1-0.20251013092601-6327009efd21 github.com/charmbracelet/git-lfs-transfer v0.1.1-0.20251013092601-6327009efd21
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
github.com/dlclark/regexp2 v1.11.5 github.com/djherbis/buffer v1.2.0
github.com/djherbis/nio/v3 v3.0.1
github.com/dsnet/compress v0.0.2-0.20230904184137-39efe44ab707 github.com/dsnet/compress v0.0.2-0.20230904184137-39efe44ab707
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.4 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.9.0 github.com/fsnotify/fsnotify v1.9.0
github.com/gliderlabs/ssh v0.3.8 github.com/gliderlabs/ssh v0.3.8
github.com/go-chi/chi/v5 v5.2.5 github.com/go-ap/activitypub v0.0.0-20250810115208-cb73b20a1742
github.com/go-ap/jsonld v0.0.0-20221030091449-f2a191312c73
github.com/go-chi/chi/v5 v5.2.3
github.com/go-chi/cors v1.2.2 github.com/go-chi/cors v1.2.2
github.com/go-co-op/gocron/v2 v2.20.0 github.com/go-co-op/gocron v1.37.0
github.com/go-enry/go-enry/v2 v2.9.6 github.com/go-enry/go-enry/v2 v2.9.2
github.com/go-git/go-billy/v5 v5.8.0 github.com/go-git/go-billy/v5 v5.6.2
github.com/go-git/go-git/v5 v5.18.0 github.com/go-git/go-git/v5 v5.16.3
github.com/go-ldap/ldap/v3 v3.4.13 github.com/go-ldap/ldap/v3 v3.4.11
github.com/go-redsync/redsync/v4 v4.16.0 github.com/go-redsync/redsync/v4 v4.13.0
github.com/go-sql-driver/mysql v1.9.3 github.com/go-sql-driver/mysql v1.9.3
github.com/go-webauthn/webauthn v0.16.4 github.com/go-webauthn/webauthn v0.13.4
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.3.1 github.com/golang-jwt/jwt/v5 v5.3.0
github.com/google/go-github/v84 v84.0.0 github.com/google/go-github/v74 v74.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-20260402051712-545e8a4df936 github.com/google/pprof v0.0.0-20250820193118-f64d9cf942d6
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/hashicorp/go-version v1.9.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
github.com/jaytaylor/html2text v0.0.0-20230321000545-74c2419ad056 github.com/jaytaylor/html2text v0.0.0-20230321000545-74c2419ad056
github.com/jhillyerd/enmime/v2 v2.3.0 github.com/jhillyerd/enmime v1.3.0
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/klauspost/compress v1.18.5 github.com/klauspost/compress v1.18.0
github.com/klauspost/cpuid/v2 v2.3.0 github.com/klauspost/cpuid/v2 v2.3.0
github.com/lib/pq v1.12.3 github.com/lib/pq v1.10.9
github.com/markbates/goth v1.82.0 github.com/markbates/goth v1.82.0
github.com/mattn/go-isatty v0.0.21 github.com/mattn/go-isatty v0.0.20
github.com/mattn/go-sqlite3 v1.14.42 github.com/mattn/go-sqlite3 v1.14.32
github.com/meilisearch/meilisearch-go v0.36.2 github.com/meilisearch/meilisearch-go v0.33.2
github.com/mholt/archives v0.1.5 github.com/mholt/archives v0.1.5-0.20251009205813-e30ac6010726
github.com/microcosm-cc/bluemonday v1.0.27 github.com/microcosm-cc/bluemonday v1.0.27
github.com/microsoft/go-mssqldb v1.9.6 github.com/microsoft/go-mssqldb v1.9.3
github.com/minio/minio-go/v7 v7.0.100 github.com/minio/minio-go/v7 v7.0.95
github.com/msteinert/pam/v2 v2.1.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.9.1 github.com/niklasfasching/go-org v1.9.1
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.1 github.com/opencontainers/image-spec v1.1.1
github.com/pkg/errors v0.9.1
github.com/pquerna/otp v1.5.0 github.com/pquerna/otp v1.5.0
github.com/prometheus/client_golang v1.23.2 github.com/prometheus/client_golang v1.23.0
github.com/quasoft/websspi v1.1.2 github.com/quasoft/websspi v1.1.2
github.com/redis/go-redis/v9 v9.18.0 github.com/redis/go-redis/v9 v9.12.1
github.com/robfig/cron/v3 v3.0.1 github.com/robfig/cron/v3 v3.0.1
github.com/santhosh-tekuri/jsonschema/v6 v6.0.2 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.4.0 github.com/sergi/go-diff v1.4.0
github.com/stretchr/testify v1.11.1 github.com/stretchr/testify v1.11.1
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.15 github.com/ulikunitz/xz v0.5.15
github.com/urfave/cli-docs/v3 v3.1.0 github.com/urfave/cli-docs/v3 v3.0.0-alpha6
github.com/urfave/cli/v3 v3.4.1 github.com/urfave/cli/v3 v3.4.1
github.com/wneessen/go-mail v0.7.2 github.com/wneessen/go-mail v0.7.2
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.8.2 github.com/yuin/goldmark v1.7.13
github.com/yuin/goldmark-highlighting/v2 v2.0.0-20230729083705-37449abec8cc github.com/yuin/goldmark-highlighting/v2 v2.0.0-20230729083705-37449abec8cc
gitlab.com/gitlab-org/api/client-go v1.46.0 github.com/yuin/goldmark-meta v1.1.0
go.yaml.in/yaml/v4 v4.0.0-rc.3 gitlab.com/gitlab-org/api/client-go v0.142.4
golang.org/x/crypto v0.50.0 golang.org/x/crypto v0.45.0
golang.org/x/image v0.39.0 golang.org/x/image v0.30.0
golang.org/x/net v0.53.0 golang.org/x/net v0.47.0
golang.org/x/oauth2 v0.36.0 golang.org/x/oauth2 v0.30.0
golang.org/x/sync v0.20.0 golang.org/x/sync v0.18.0
golang.org/x/sys v0.43.0 golang.org/x/sys v0.38.0
golang.org/x/text v0.36.0 golang.org/x/text v0.31.0
google.golang.org/grpc v1.80.0 google.golang.org/grpc v1.75.0
google.golang.org/protobuf v1.36.11 google.golang.org/protobuf v1.36.8
gopkg.in/ini.v1 v1.67.1 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.6.0 mvdan.cc/xurls/v2 v2.6.0
strk.kbt.io/projects/go/libravatar v0.0.0-20260301104140-add494e31dab 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.11 xorm.io/xorm v1.3.10
) )
require ( require (
cloud.google.com/go/compute/metadata v0.9.0 // indirect cloud.google.com/go/compute/metadata v0.8.0 // indirect
dario.cat/mergo v1.0.2 // indirect dario.cat/mergo v1.0.2 // indirect
filippo.io/edwards25519 v1.2.0 // indirect filippo.io/edwards25519 v1.1.0 // indirect
git.sr.ht/~mariusor/go-xsd-duration v0.0.0-20220703122237-02e73435a078 // indirect
github.com/Azure/azure-sdk-for-go/sdk/internal v1.11.2 // indirect github.com/Azure/azure-sdk-for-go/sdk/internal v1.11.2 // indirect
github.com/DataDog/zstd v1.5.7 // indirect github.com/DataDog/zstd v1.5.7 // indirect
github.com/Microsoft/go-winio v0.6.2 // indirect github.com/Microsoft/go-winio v0.6.2 // indirect
github.com/RoaringBitmap/roaring/v2 v2.16.0 // indirect github.com/RoaringBitmap/roaring/v2 v2.10.0 // indirect
github.com/STARRY-S/zip v0.2.3 // indirect github.com/STARRY-S/zip v0.2.3 // indirect
github.com/andybalholm/brotli v1.2.1 // indirect github.com/andybalholm/brotli v1.2.0 // indirect
github.com/andybalholm/cascadia v1.3.3 // 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/aws/aws-sdk-go-v2 v1.41.5 // indirect github.com/aws/aws-sdk-go-v2 v1.38.3 // indirect
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.21 // indirect github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.6 // indirect
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.21 // indirect github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.6 // indirect
github.com/aws/smithy-go v1.24.2 // indirect github.com/aws/smithy-go v1.23.0 // 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.24.4 // indirect github.com/bits-and-blooms/bitset v1.24.0 // indirect
github.com/blevesearch/bleve_index_api v1.3.7 // indirect github.com/blevesearch/bleve_index_api v1.2.9 // indirect
github.com/blevesearch/geo v0.2.5 // indirect github.com/blevesearch/geo v0.2.4 // indirect
github.com/blevesearch/go-faiss v1.0.30 // indirect github.com/blevesearch/go-faiss v1.0.25 // 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.2.0 // indirect github.com/blevesearch/mmap-go v1.0.4 // indirect
github.com/blevesearch/scorch_segment_api/v2 v2.4.5 // indirect github.com/blevesearch/scorch_segment_api/v2 v2.3.11 // 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
github.com/blevesearch/vellum v1.2.0 // indirect github.com/blevesearch/vellum v1.1.0 // indirect
github.com/blevesearch/zapx/v11 v11.4.3 // indirect github.com/blevesearch/zapx/v11 v11.4.2 // indirect
github.com/blevesearch/zapx/v12 v12.4.3 // indirect github.com/blevesearch/zapx/v12 v12.4.2 // indirect
github.com/blevesearch/zapx/v13 v13.4.3 // indirect github.com/blevesearch/zapx/v13 v13.4.2 // indirect
github.com/blevesearch/zapx/v14 v14.4.3 // indirect github.com/blevesearch/zapx/v14 v14.4.2 // indirect
github.com/blevesearch/zapx/v15 v15.4.3 // indirect github.com/blevesearch/zapx/v15 v15.4.2 // indirect
github.com/blevesearch/zapx/v16 v16.3.2 // indirect github.com/blevesearch/zapx/v16 v16.2.4 // indirect
github.com/bmatcuk/doublestar/v4 v4.10.0 // indirect github.com/bmatcuk/doublestar/v4 v4.9.1 // indirect
github.com/bodgit/plumbing v1.3.0 // indirect github.com/bodgit/plumbing v1.3.0 // indirect
github.com/bodgit/sevenzip v1.6.1 // indirect github.com/bodgit/sevenzip v1.6.1 // indirect
github.com/bodgit/windows v1.0.1 // indirect github.com/bodgit/windows v1.0.1 // indirect
github.com/boombuler/barcode v1.1.0 // indirect github.com/boombuler/barcode v1.1.0 // indirect
github.com/bradfitz/gomemcache v0.0.0-20250403215159-8d39553ac7cf // indirect github.com/bradfitz/gomemcache v0.0.0-20250403215159-8d39553ac7cf // indirect
github.com/caddyserver/zerossl v0.1.5 // 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/clipperhouse/displaywidth v0.11.0 // indirect github.com/cloudflare/circl v1.6.1 // indirect
github.com/clipperhouse/uax29/v2 v2.7.0 // indirect
github.com/cloudflare/circl v1.6.3 // 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.4 // indirect github.com/couchbase/gomemcached v0.3.3 // indirect
github.com/couchbase/goutils v0.3.0 // indirect github.com/couchbase/goutils v0.1.2 // indirect
github.com/cpuguy83/go-md2man/v2 v2.0.7 // indirect github.com/cpuguy83/go-md2man/v2 v2.0.7 // indirect
github.com/cyphar/filepath-securejoin v0.6.1 // 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.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.19.0 // indirect github.com/fatih/color v1.18.0 // indirect
github.com/fxamacker/cbor/v2 v2.9.1 // indirect github.com/fxamacker/cbor/v2 v2.9.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-20250527110557-c8db454e53fd // indirect
github.com/go-asn1-ber/asn1-ber v1.5.8-0.20250403174932-29230038a667 // indirect github.com/go-asn1-ber/asn1-ber v1.5.8-0.20250403174932-29230038a667 // indirect
github.com/go-enry/go-oniguruma v1.2.1 // indirect github.com/go-enry/go-oniguruma v1.2.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-viper/mapstructure/v2 v2.5.0 // indirect github.com/go-webauthn/x v0.1.24 // indirect
github.com/go-webauthn/x v0.2.3 // indirect github.com/goccy/go-json v0.10.5 // indirect
github.com/goccy/go-json v0.10.6 // 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/groupcache v0.0.0-20241129210726-2c02b8208cf8 // indirect github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 // indirect
github.com/golang/protobuf v1.5.4 // indirect
github.com/golang/snappy v1.0.0 // 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.12.19+incompatible // indirect github.com/google/flatbuffers v25.2.10+incompatible // indirect
github.com/google/go-querystring v1.2.0 // indirect github.com/google/go-querystring v1.1.0 // indirect
github.com/google/go-tpm v0.9.8 // indirect github.com/google/go-tpm v0.9.5 // indirect
github.com/gorilla/css v1.0.1 // indirect github.com/gorilla/css v1.0.1 // 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
@@ -210,56 +218,53 @@ require (
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.8 // indirect github.com/hashicorp/go-retryablehttp v0.7.8 // indirect
github.com/inbucket/html2text 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/jonboulle/clockwork v0.5.0 // indirect
github.com/josharian/intern v1.0.0 // indirect github.com/josharian/intern v1.0.0 // indirect
github.com/json-iterator/go v1.1.12 // indirect github.com/kevinburke/ssh_config v1.4.0 // indirect
github.com/kevinburke/ssh_config v1.6.0 // indirect
github.com/klauspost/crc32 v1.3.0 // indirect
github.com/klauspost/pgzip v1.2.6 // indirect github.com/klauspost/pgzip v1.2.6 // indirect
github.com/libdns/libdns v1.1.1 // indirect github.com/libdns/libdns v1.1.1 // indirect
github.com/mailru/easyjson v0.9.2 // indirect github.com/mailru/easyjson v0.9.0 // indirect
github.com/markbates/going v1.0.3 // indirect github.com/markbates/going v1.0.3 // indirect
github.com/mattn/go-colorable v0.1.14 // indirect github.com/mattn/go-colorable v0.1.14 // indirect
github.com/mattn/go-runewidth v0.0.21 // indirect github.com/mattn/go-runewidth v0.0.16 // indirect
github.com/mattn/go-shellwords v1.0.12 // indirect github.com/mattn/go-shellwords v1.0.12 // indirect
github.com/mholt/acmez/v3 v3.1.6 // indirect github.com/mholt/acmez/v3 v3.1.2 // indirect
github.com/miekg/dns v1.1.72 // indirect github.com/miekg/dns v1.1.68 // indirect
github.com/mikelolasagasti/xz v1.0.1 // indirect github.com/mikelolasagasti/xz v1.0.1 // indirect
github.com/minio/crc64nvme v1.1.1 // indirect github.com/minio/crc64nvme v1.1.1 // indirect
github.com/minio/md5-simd v1.1.2 // indirect github.com/minio/md5-simd v1.1.2 // indirect
github.com/minio/minlz v1.1.0 // indirect github.com/minio/minlz v1.0.1 // indirect
github.com/mitchellh/mapstructure v1.5.0 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/mrjones/oauth v0.0.0-20190623134757-126b35219450 // indirect github.com/mrjones/oauth v0.0.0-20190623134757-126b35219450 // indirect
github.com/mschoch/smat v0.2.0 // indirect github.com/mschoch/smat v0.2.0 // indirect
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
github.com/nwaples/rardecode/v2 v2.2.2 // indirect github.com/nwaples/rardecode/v2 v2.2.0 // indirect
github.com/olekukonko/cat v0.0.0-20250911104152-50322a0618f6 // indirect github.com/olekukonko/cat v0.0.0-20250817074551-3280053e4e00 // indirect
github.com/olekukonko/errors v1.2.0 // indirect github.com/olekukonko/errors v1.1.0 // indirect
github.com/olekukonko/ll v0.1.8 // indirect github.com/olekukonko/ll v0.1.0 // indirect
github.com/olekukonko/tablewriter v1.1.4 // indirect github.com/olekukonko/tablewriter v1.0.9 // indirect
github.com/onsi/ginkgo v1.16.5 // indirect github.com/onsi/ginkgo v1.16.5 // indirect
github.com/philhofer/fwd v1.2.0 // indirect github.com/philhofer/fwd v1.2.0 // indirect
github.com/pierrec/lz4/v4 v4.1.26 // indirect github.com/pierrec/lz4/v4 v4.1.22 // indirect
github.com/pjbgf/sha1cd v0.5.0 // indirect github.com/pjbgf/sha1cd v0.4.0 // indirect
github.com/pkg/errors v0.9.1 // 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.2 // indirect github.com/prometheus/client_model v0.6.2 // indirect
github.com/prometheus/common v0.67.5 // indirect github.com/prometheus/common v0.65.0 // indirect
github.com/prometheus/procfs v0.20.1 // indirect github.com/prometheus/procfs v0.17.0 // indirect
github.com/rhysd/actionlint v1.7.12 // indirect github.com/rhysd/actionlint v1.7.7 // indirect
github.com/rivo/uniseg v0.4.7 // 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/shopspring/decimal v1.4.0 // indirect github.com/sirupsen/logrus v1.9.3 // indirect
github.com/sirupsen/logrus v1.9.4 // indirect github.com/skeema/knownhosts v1.3.1 // indirect
github.com/skeema/knownhosts v1.3.2 // indirect
github.com/sorairolake/lzip-go v0.3.8 // indirect github.com/sorairolake/lzip-go v0.3.8 // indirect
github.com/spf13/afero v1.15.0 // indirect github.com/spf13/afero v1.15.0 // indirect
github.com/ssor/bom v0.0.0-20170718123548-6386211fdfcf // indirect github.com/ssor/bom v0.0.0-20170718123548-6386211fdfcf // indirect
github.com/tinylib/msgp v1.6.3 // indirect github.com/tinylib/msgp v1.4.0 // indirect
github.com/unknwon/com v1.0.1 // indirect github.com/unknwon/com v1.0.1 // indirect
github.com/valyala/fastjson v1.6.4 // indirect
github.com/x448/float16 v0.8.4 // indirect github.com/x448/float16 v0.8.4 // indirect
github.com/xanzy/ssh-agent v0.3.3 // indirect github.com/xanzy/ssh-agent v0.3.3 // indirect
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect
@@ -270,17 +275,16 @@ require (
go.etcd.io/bbolt v1.4.3 // indirect go.etcd.io/bbolt v1.4.3 // 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.1 // indirect go.uber.org/zap v1.27.0 // indirect
go.uber.org/zap/exp v0.3.0 // indirect go.uber.org/zap/exp v0.3.0 // indirect
go.yaml.in/yaml/v2 v2.4.4 // indirect go4.org v0.0.0-20230225012048-214862532bf5 // indirect
go.yaml.in/yaml/v3 v3.0.4 // indirect golang.org/x/exp v0.0.0-20250305212735-054e65f0b394 // indirect
go4.org v0.0.0-20260112195520-a5071408f32f // indirect golang.org/x/mod v0.29.0 // indirect
golang.org/x/exp v0.0.0-20250819193227-8b4c13bb791b // indirect golang.org/x/time v0.12.0 // indirect
golang.org/x/mod v0.34.0 // indirect golang.org/x/tools v0.38.0 // indirect
golang.org/x/time v0.15.0 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20250826171959-ef028d996bc1 // indirect
golang.org/x/tools v0.43.0 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20260401020348-3a24fdc17823 // 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
) )
ignore ( ignore (
@@ -288,20 +292,18 @@ ignore (
./node_modules ./node_modules
) )
// When doing "go get -u ./...", Golang will try to update all dependencies replace github.com/jaytaylor/html2text => github.com/Necoro/html2text v0.0.0-20250804200300-7bf1ce1c7347
// But not all latest versions of dependencies are compatible with other packages or our codebase, so we need to pin some dependencies to specific versions
// Need to regularly maintain this list to try to update them to latest versions, especially the TODO ones
replace github.com/jaytaylor/html2text => github.com/Necoro/html2text v0.0.0-20250804200300-7bf1ce1c7347 // jaytaylor/html2text is unmaintained replace github.com/hashicorp/go-version => github.com/6543/go-version v1.3.1
replace github.com/nektos/act => gitea.com/gitea/act v0.261.10 // gitea maintains its own package replace github.com/nektos/act => gitea.com/gitea/act v0.261.7-0.20251003180512-ac6e4b751763
replace github.com/urfave/cli/v3 => github.com/urfave/cli/v3 v3.4.1 // v3.6.2 breaks -c flag parsing in help commands replace git.sr.ht/~mariusor/go-xsd-duration => gitea.com/gitea/go-xsd-duration v0.0.0-20220703122237-02e73435a078
replace go.yaml.in/yaml/v4 => go.yaml.in/yaml/v4 v4.0.0-rc.3 // rc.4 changes block scalar serialization, wait for stable release exclude github.com/gofrs/uuid v3.2.0+incompatible
replace github.com/Azure/azure-sdk-for-go/sdk/azcore => github.com/Azure/azure-sdk-for-go/sdk/azcore v1.19.0 // v1.21.0+ uses API version unsupported by Azurite in CI exclude github.com/gofrs/uuid v4.0.0+incompatible
replace github.com/Azure/azure-sdk-for-go/sdk/storage/azblob => github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.6.2 // v1.6.4+ uses API version unsupported by Azurite in CI exclude github.com/goccy/go-json v0.4.11
replace github.com/microsoft/go-mssqldb => github.com/microsoft/go-mssqldb v1.9.7 // downgraded with Azure SDK exclude github.com/satori/go.uuid v1.2.0

777
go.sum

File diff suppressed because it is too large Load Diff

View File

@@ -26,8 +26,9 @@ import (
// these flags will be set by the build flags // these flags will be set by the build flags
var ( var (
Version = "development" // program version for this build Version = "development" // program version for this build
Tags = "" // the Golang build tags Tags = "" // the Golang build tags
MakeVersion = "" // "make" program version if built with make
) )
func init() { func init() {
@@ -43,12 +44,14 @@ func main() {
} }
app := cmd.NewMainApp(cmd.AppVersion{Version: Version, Extra: formatBuiltWith()}) app := cmd.NewMainApp(cmd.AppVersion{Version: Version, Extra: formatBuiltWith()})
_ = cmd.RunMainApp(app, os.Args...) // all errors should have been handled by the RunMainApp _ = cmd.RunMainApp(app, os.Args...) // all errors should have been handled by the RunMainApp
// flush the queued logs before exiting, it is a MUST, otherwise there will be log loss
log.GetManager().Close() log.GetManager().Close()
} }
func formatBuiltWith() string { func formatBuiltWith() string {
version := runtime.Version() version := runtime.Version()
if len(MakeVersion) > 0 {
version = MakeVersion + ", " + runtime.Version()
}
if len(Tags) == 0 { if len(Tags) == 0 {
return " built with " + version return " built with " + version
} }

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