Compare commits

...

74 Commits

Author SHA1 Message Date
Lunny Xiao
acdcfcc6eb Fix cache bug (#30510)
Cache cannot be disabled from v1.22. So it still maybe `nil` in v1.21,
we have to check whether cache is `nil`.
2024-04-16 10:59:15 +08:00
Lunny Xiao
727b1914b4 Update 1.21.11 changelog (#30403)
Add #30394 into changelog

---------

Co-authored-by: Jason Song <i@wolfogre.com>
Co-authored-by: yp05327 <576951401@qq.com>
2024-04-16 10:10:47 +08:00
Lunny Xiao
60181eb599 Fix code owners will not be mentioned when a pull request comes from a forked repository (#30476) (#30497)
Backport #30476 
Fix #30277
Caused by #29783
2024-04-16 08:27:01 +08:00
Lunny Xiao
a0ca311165 Fix commit status cache which missed target_url (#30426) (#30445)
Fix #30421
Backport #30426

Co-authored-by: Jason Song <i@wolfogre.com>
2024-04-15 07:43:20 +00:00
Lunny Xiao
430fe6c0c1 Avoid losing token when updating mirror settings (#30429) (#30466)
Fix #30416.
Backport #30429 

Before (it shows as "Unset" while there's a token):

<img width="980" alt="image"

src="https://github.com/go-gitea/gitea/assets/9418365/d7148e3e-62c9-4d2e-942d-3d795b79515a">

After:

<img width="977" alt="image"

src="https://github.com/go-gitea/gitea/assets/9418365/24aaa1db-5baa-4204-9081-470b15ea72b5">

The username shows as "oauth2" because of

f9fdac9809/services/migrations/dump.go (L99)

I have checked that all usage of `MirrorRemoteAddress` has been updated.

<img width="1806" alt="image"

src="https://github.com/go-gitea/gitea/assets/9418365/2f042501-2824-4511-9203-c84a6731a02d">

However, it needs to be checked again when backporting.

Co-authored-by: Jason Song <i@wolfogre.com>
2024-04-15 11:29:42 +08:00
Lunny Xiao
b6379d2f16 Change the default maxPerPage for gitbucket (#30392) (#30471)
Backport #30392 

This patch improves the migration from gitbucket to gitea.

The gitbucket uses it's own internal perPage value (= 25) for paging and
ignore per_page arguments in the requested URL. This cause gitea to
migrate only 25 issues and 25 PRs from gitbucket repository. This may
not happens on old gitbucket. But recent gitbucket 4.40 or 4.38.4 has
this problem.

This patch change to use this internally hardcoded perPage of gitbucket
as gitea's maxPerPage numer when migrating from gitbucket. There are
several perPage values in gitbucket like 25 for Isseus/PRs and 10 for
Releases. Some of those API doesn't support paging yet. It sounds
difficult to implement, but using the minimum number among them worked
out very well. So, I use 10 in this patch.

Brief descriptions of problems and this patch are also available in
https://github.com/go-gitea/gitea/issues/30316.

In addition, I'm not sure what kind of test cases are possible to write
here. It's a test for migration, so it requires testing gitbucket server
and gitea server, I guess. Please let me know if it is possible to write
such test cases here. Thanks!

Co-authored-by: Kazushi (Jam) Marukawa <jam@pobox.com>
2024-04-14 12:42:50 +00:00
yp05327
928c0d4f46 Fix mirror error when mirror repo is empty (#30432) (#30467)
Backport #30432
Fix https://github.com/go-gitea/gitea/issues/30424

ps: convert `gitrepo.OpenRepository` to `git.OpenRepository`
remove `ctx` from `checkAndUpdateEmptyRepository`

Co-authored-by: Giteabot <teabot@gitea.io>
2024-04-14 14:18:06 +02:00
Giteabot
222d16e6ea fix: Fix to delete cookie when AppSubURL is non-empty (#30375) (#30468)
Backport #30375 by @jtran

Cookies may exist on "/subpath" and "/subpath/" for some legacy reasons
(eg: changed CookiePath behavior in code). The legacy cookie should be
removed correctly.

Co-authored-by: Jonathan Tran <jonnytran@gmail.com>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
Co-authored-by: Kyle D <kdumontnu@gmail.com>
2024-04-14 13:45:51 +02:00
Lunny Xiao
09df5c9c7d Use db.ListOptions directly instead of Paginator interface to make iteasier to use and fix performance of /pulls and /issues (#29990) (#30447)
backport #29990

This PR uses `db.ListOptions` instead of `Paginor` to make the code
simpler.
And it also fixed the performance problem when viewing /pulls or
/issues. Before the counting in fact will also do the search.

Co-authored-by: Jason Song <i@wolfogre.com>
Co-authored-by: silverwind <me@silverwind.io>
2024-04-13 17:44:57 +00:00
Lunny Xiao
fc4e08f804 Upgrade go-sqlite to v1.14.22 (#30462) 2024-04-13 08:33:50 -05:00
Giteabot
68bd1dd89d Fix rename branch 500 when the target branch is deleted but exist in database (#30430) (#30437)
Backport #30430 by @lunny

Fix #30428

---------

Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
2024-04-12 23:09:16 +08:00
Zettat123
55990ebf92 Check the token's owner and repository when registering a runner (#30406) (#30412)
Backport #30406

Fix #30378
2024-04-11 11:29:53 +00:00
Giteabot
245e8d10c2 Avoid user does not exist error when detecting schedule actions when the commit author is an external user (#30357) (#30408)
Backport #30357 by @yp05327


![image](https://github.com/go-gitea/gitea/assets/18380374/ddf6ee84-2242-49b9-b066-bd8429ba4d76)

When repo is a mirror, and commit author is an external user, then
`GetUserByEmail` will return error.

reproduce/test:
- mirror Gitea to your instance
- disable action and enable it again, this will trigger
`DetectAndHandleSchedules`

ps: also follow #24706, it only fixed normal runs, not scheduled runs.

Co-authored-by: yp05327 <576951401@qq.com>
2024-04-11 15:39:27 +08:00
Giteabot
529604a044 Update actions variables documents (#30394) (#30404)
Backport #30394 by @lunny

Fix #30393

Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
Co-authored-by: silverwind <me@silverwind.io>
Co-authored-by: Zettat123 <zettat123@gmail.com>
2024-04-11 12:04:21 +08:00
Jason Song
6cfe67cfc3 No global variables (#30402)
Fix #30361, regression of #29782 which is a backport, not the original
#29468.

#29468 did a small refactor which introduced a new function
`GetVariablesOfRun`. However, it's designed for v1.22 which supports
global variables.

After backporting it to v1.21, it will still try to get global
variables, which causes it to retrieve all variables.
2024-04-11 03:25:05 +00:00
Lunny Xiao
9149221845 Add changelog for 1.21.11 (#30314)
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2024-04-11 10:52:02 +08:00
Lunny Xiao
6e3aaa9975 Performance optimization for git push (#30104) (#30354)
Agit returned result should be from `ProcReceive` hook but not
`PostReceive` hook. Then for all non-agit pull requests, it will not
check the pull requests for every pushing `refs/pull/%d/head`.

Backport #30104
2024-04-10 14:12:19 +08:00
Lunny Xiao
3f6ddd9bee Fix create commit status (#30225) (#30340)
Partially backport #30223

This PR uses the service layer `CreateCommitstatus` method instead of
the git model method.
2024-04-08 23:30:55 +00:00
Lunny Xiao
65d96725bb Fix possible renderer security problem(#30136) (#30315)
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2024-04-09 00:24:35 +02:00
Giteabot
4588c7b705 Close file in the Upload func (#30262) (#30269)
Co-authored-by: guangwu <guoguangwu@magic-shield.com>
2024-04-03 15:20:18 +00:00
Giteabot
47de6e3b54 Add -u git to docs when using docker exec with root installation (#29314) (#30264)
Backport #29314 by @scribblemaniac

This fixes a minor issue in the documentation for SSH Container
Passthrough for non-rootless installs. The non-rootless Dockerfile and
docker-compose do not set `USER`/`user` instructions so `docker exec`
will run as root by default. While running as root, gitea commands will
refuse to execute, breaking these approaches. For containers built with
the rootless instructions, `docker exec` will run as git by default so
this is not necessary in that case.

This issue was already discussed in #19065, but it does not appear this
part of the issue was ever added to the documentation.

Co-authored-by: scribblemaniac <scribblemaniac@users.noreply.github.com>
2024-04-03 13:44:11 +00:00
Giteabot
5123ed3191 Fixes #27605: inline math blocks can't be preceeded/followed by alphanumerical characters (#30175) (#30250)
Backport #30175 by @jmlt2002

- Inline math blocks couldn't be preceeded or succeeded by
alphanumerical characters due to changes introduced in PR #21171.
Removed the condition that caused this (precedingCharacter condition)
and added a new exit condition of the for-loop that checks if a specific
'$' was escaped using '\' so that the math expression can be rendered as
intended.
- Additionally this PR fixes another bug where math blocks of the type
'$xyz$abc$' where the dollar sign was not escaped by the user, generated
an error (shown in the screenshots below)
- Altered the tests to accomodate for the changes

Former behaviour (from try.gitea.io):

![image](https://github.com/go-gitea/gitea/assets/114936010/8f0cbb21-321d-451c-b871-c67a8e1e9235)

Fixed behaviour (from my local build):

![image](https://github.com/go-gitea/gitea/assets/114936010/5c22687c-6f11-4407-b5e7-c14b838bc20d)

(Edit) Source code for the README.md file:
```
$x$ -$x$ $x$-

a$xa$ $xa$a 1$xb$ $xb$1

$a a$b b$

a$b $a a$b b$

$a a\$b b$
```

Signed-off-by: João Tiago <joao.leal.tintas@tecnico.ulisboa.pt>
Co-authored-by: João Tiago <114936010+jmlt2002@users.noreply.github.com>
2024-04-03 06:06:39 +00:00
Giteabot
9f2a1a55e6 Add -u git to docs when using docker exec with root installation (#29314) (#30258)
Backport #29314 by @scribblemaniac

This fixes a minor issue in the documentation for SSH Container
Passthrough for non-rootless installs. The non-rootless Dockerfile and
docker-compose do not set `USER`/`user` instructions so `docker exec`
will run as root by default. While running as root, gitea commands will
refuse to execute, breaking these approaches. For containers built with
the rootless instructions, `docker exec` will run as git by default so
this is not necessary in that case.

This issue was already discussed in #19065, but it does not appear this
part of the issue was ever added to the documentation.

Co-authored-by: scribblemaniac <scribblemaniac@users.noreply.github.com>
2024-04-03 01:44:13 -04:00
Giteabot
935bfe6445 Fix missing 0 prefix of GPG key id (#30245) (#30247)
Backport #30245 by @KN4CK3R

Fixes #30235

If the key id "front" byte has a single digit, `%X` is missing the 0
prefix.
` 38D1A3EADDBEA9C` instead of
`038D1A3EADDBEA9C`
When using the `IssuerFingerprint` slice `%X` is enough but I changed it
to `%016X` too to be consistent.

Co-authored-by: KN4CK3R <admin@oldschoolhack.me>
2024-04-02 16:13:07 +00:00
Giteabot
2ac78c75d0 Include encoding in signature payload (#30174) (#30181)
Backport #30174 by @KN4CK3R

Fixes #30119

Include the encoding in the signature payload.

before

![grafik](https://github.com/go-gitea/gitea/assets/1666336/01ab94a3-8af5-4d6f-be73-a10b65a15421)

after

![grafik](https://github.com/go-gitea/gitea/assets/1666336/3a37d438-c70d-4d69-b178-d170e74aa683)

---------

Co-authored-by: KN4CK3R <admin@oldschoolhack.me>
2024-04-01 09:47:11 +08:00
YR Chen
b1dae9f2c8 Move from max( id ) to max( index ) for latest commit statuses (#30076) (#30155)
Backport https://github.com/go-gitea/gitea/pull/30076.

This PR replaces the use of `max( id )`, and instead using ``max(
`index` )`` for determining the latest commit status. Building business
logic over an `auto_increment` primary key like `id` is risky and
there’re already plenty of discussions on the Internet.

There‘s no guarantee for `auto_increment` values to be monotonic,
especially upon failures or with a cluster. In the specific case, we met
the problem of commit statuses being outdated when using TiDB as the
database. As [being
documented](https://docs.pingcap.com/tidb/stable/auto-increment),
`auto_increment` values assigned to an `insert` statement will only be
monotonic on a per server (node) basis.

Closes #30074.
2024-03-28 16:29:38 +00:00
yp05327
7bffb923ce Load attachments for code comments (#30124) (#30126)
backport #30124
2024-03-27 16:06:23 +08:00
yp05327
0c10c3a282 Fix gitea doctor will remove repo-avatar files when execute command storage-archives (#30094) (#30120)
backport #30094
2024-03-27 10:09:17 +08:00
Lunny Xiao
09a5067c0c Fix possible data race on tests (#30093) (#30108)
backport #30093
2024-03-26 16:49:48 +01:00
yp05327
a0f89ba8c7 Fix duplicate migrated milestones (#30102) (#30105)
backport #30102
2024-03-26 20:58:56 +08:00
yp05327
6d47b63be2 Fix panic for fixBrokenRepoUnits16961 (#30068) (#30100)
backport #30068
2024-03-26 18:20:03 +08:00
silverwind
8dccea02f2 Update katex to 0.16.10 (#30089)
https://github.com/KaTeX/KaTeX/releases/tag/v0.16.10

---------

Co-authored-by: Giteabot <teabot@gitea.io>
2024-03-26 02:42:37 +01:00
silverwind
03f29db46d Fix incorrect SVGs (#30087)
Just the SVG fixes from https://github.com/go-gitea/gitea/pull/30086 for
v1.21 branch.
2024-03-26 00:10:24 +00:00
Lunny Xiao
d6b0d0e9c0 Release of 1.21.10 (#30073)
The main reason for this release is to fix a bug #29997
2024-03-26 00:46:08 +01:00
Lunny Xiao
087aed7096 Fix Add/Remove WIP on pull request title failure (#29999) (#30066)
Fix #29997
Backport #29999
2024-03-25 10:26:05 +01:00
Giteabot
78795dd566 Fix misuse of TxContext (#30061) (#30062)
Backport #30061 by @wolfogre

Help #29999, or its tests cannot pass.

Also, add some comments to clarify the usage of `TxContext`.

I don't check all usages of `TxContext` because there are too many
(almost 140+). It's a better idea to replace them with `WithTx` instead
of checking them one by one. However, that may be another refactoring
PR.

Co-authored-by: Jason Song <i@wolfogre.com>
2024-03-25 07:22:09 +00:00
Giteabot
e321b8a849 Respect DEFAULT_ORG_MEMBER_VISIBLE setting when adding creator to org (#30013) (#30035)
Backport #30013 by @DrMaxNix

This PR adds `setting.Service.DefaultOrgMemberVisible` value to dataset
of user when the initial org creator is being added to the created org.

Fixes #30012.

Co-authored-by: DrMaxNix <mail@drmaxnix.de>
2024-03-24 06:38:31 +01:00
wxiaoguang
2172b38d50 Escape paths for find file correctly (#30026) (#30031)
Backport #30026
2024-03-23 17:21:57 +01:00
wxiaoguang
01f736f68c Remove duplicate option in admin screen and now-unused translation keys (#28492) (#30024)
Backport #28492
Fix #30019

Co-authored-by: The Magician <142242365+TheMagician23@users.noreply.github.com>
2024-03-23 15:56:19 +01:00
Giteabot
688107651c Small refactors in anchors.js (#29947) (#30003)
Backport #29947 by @silverwind

Some minor refactors, remove unnecessary `:is` selector and move the
`:target` check out of the function. Might as well backport for the rare
browser that does not support `:is`.

Co-authored-by: silverwind <me@silverwind.io>
2024-03-22 15:02:05 +01:00
wxiaoguang
24c66c5096 Fix manual merge form and 404 page templates (#30000)
Partially backport #29985, fix some template errors.

* fix the manual-merge form
* fix the 404 page
2024-03-22 19:42:41 +08:00
Lunny Xiao
e1e88f9ad1 Add changelog for 1.21.9 (#29971)
Co-authored-by: Jason Song <i@wolfogre.com>
2024-03-22 12:32:44 +08:00
Giteabot
f91b4dd959 Fix bugs in rerunning jobs (#29955) (#29983)
Backport #29955 by @Zettat123

Fix #28761
Fix #27884
Fix #28093

## Changes

### Rerun all jobs
When rerun all jobs, status of the jobs with `needs` will be set to
`blocked` instead of `waiting`. Therefore, these jobs will not run until
the required jobs are completed.

### Rerun a single job
When a single job is rerun, its dependents should also be rerun, just
like GitHub does
(https://github.com/go-gitea/gitea/issues/28761#issuecomment-2008620820).
In this case, only the specified job will be set to `waiting`, its
dependents will be set to `blocked` to wait the job.

### Show warning if every job has `needs`
If every job in a workflow has `needs`, all jobs will be blocked and no
job can be run. So I add a warning message.

<img
src="https://github.com/go-gitea/gitea/assets/15528715/88f43511-2360-465d-be96-ee92b57ff67b"
width="480px" />

---------

Co-authored-by: Zettat123 <zettat123@gmail.com>
Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
2024-03-22 03:57:10 +00:00
Lunny Xiao
6ef986d474 Performance improvements for pull request list page (#29900) (#29972)
This PR will avoid load pullrequest.Issue twice in pull request list
page. It will reduce x times database queries for those WIP pull
requests.

Partially fix #29585
Backport #29900
2024-03-22 09:58:04 +08:00
Lunny Xiao
c03b1e2854 Fix the bug that user may logout if GetUserByID return unknow error (#29964)
backport #29962

This PR fixed a bug when the user switching pages too fast, he will
logout automatically.

The reason is that when the error is context cancelled, the previous
code think user hasn't login then the session will be deleted. Now it
will return the errors but not think it's not login.

Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2024-03-21 14:30:55 +00:00
HEREYUA
3ff3c5ba78 Solving the issue of UI disruption when the review is deleted without refreshing (#29951) (#29968)
backport #29951
2024-03-21 15:03:01 +01:00
Giteabot
58a0ba711d Fix and rewrite markup anchor processing (#29931) (#29946)
Backport #29931 by @lunny

Fix #29877

Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
Co-authored-by: silverwind <me@silverwind.io>
2024-03-21 01:09:08 +02:00
wxiaoguang
b4a6c6fd7a Fix loadOneBranch panic (#29938) (#29939)
Backport #29938

Try to fix #29936

Far from ideal, but still better than panic.
2024-03-20 22:31:32 +08:00
Lunny Xiao
3fd15aeff2 Add cache for dashbaord commit status (#29932)
backport #29444
2024-03-20 10:34:40 +00:00
Giteabot
0873088223 Show Actions post step when it's running (#29926) (#29928)
Backport #29926 by @wolfogre

The post step was always waiting, even if all steps were done. Then,
once the task was done, the post step became success immediately.

Before:

<img width="915" alt="xnip_240320_120228"
src="https://github.com/go-gitea/gitea/assets/9418365/00347430-f998-4c43-917a-bf6dd6d0e333">

After:

<img width="905" alt="xnip_240320_120443"
src="https://github.com/go-gitea/gitea/assets/9418365/a419b111-17c2-4029-a022-c761cc419091">

Co-authored-by: Jason Song <i@wolfogre.com>
2024-03-20 06:25:11 +00:00
Lunny Xiao
ff27ca32ca Notify reviewers added via CODEOWNERS (#29842) (#29902)
backport #29842

Co-authored-by: Jimmy Praet <jimmy.praet@telenet.be>
2024-03-20 06:02:24 +00:00
Giteabot
eb302deb18 Fix the wrong default value of ENABLE_OPENID_SIGNIN on docs (#29925) (#29927)
Backport #29925 by @lunny

Fix #29923

Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
2024-03-20 05:08:24 +00:00
yp05327
aae96cc62b Fix invalid link of the commit status when ref is tag (#29752) (#29908)
Backport #29752

---------

Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
2024-03-20 04:36:32 +00:00
Lunny Xiao
5f7b6b55a5 Only do counting when count_only=true for repo dashboard (#29884) (#29905)
Ref: #29878
Backport #29884

Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2024-03-20 11:02:35 +08:00
Giteabot
408c92938b Fix PR creation via api between branches of same repo with head field namespaced (#26986) (#29857)
Backport #26986 by @norohind

Fix #20175

Current implementation of API does not allow creating pull requests
between branches of the same
repo when you specify *namespace* (owner of the repo) in `head` field in
http request body.

---------

Co-authored-by: norohind <60548839+norohind@users.noreply.github.com>
Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
2024-03-20 09:38:30 +08:00
wxiaoguang
b9dd5dd471 Fix template error when comment review doesn't exist (#29888) (#29889)
Backport #29888
2024-03-19 15:00:01 +08:00
Lunny Xiao
440be51a45 Fix bug on template (#29887)
Caused by #29807
Fix #29886
2024-03-18 15:24:07 +00:00
Giteabot
00ea9af8e1 Editor error message misleading due to re-used key. (#29859) (#29876)
Backport #29859 by @buckybytes

The error message:

`editor.file_changed_while_editing = The file contents have changed
since you started editing. <a target="_blank" rel="noopener noreferrer"
href="%s">Click here</a> to see them or <strong>Commit Changes
again</strong> to overwrite them.`

Is re-used in inappropriate contexts. The link in the key goes to a 404
when the key is used in a situation where the file contents have not
changed.

Added two new keys to differentiate commit id mismatch and push out of
date conditions.

Co-authored-by: buckybytes <158571971+buckybytes@users.noreply.github.com>
2024-03-18 14:45:43 +08:00
Giteabot
c044510ca8 Fix user id column case (#29863) (#29867)
Backport #29863 by @lng2020

Sometimes the column name is case-sensitive and it may cause 500.

Co-authored-by: Nanguan Lin <nanguanlin6@gmail.com>
2024-03-17 13:51:15 +00:00
Lunny Xiao
85f31eb643 Fix codeowner detected diff base branch to mergebase (#29783) (#29807)
Fix #29763
Backport #29783 

This PR fixes 2 problems with CodeOwner in the pull request.
- Don't use the pull request base branch but merge-base as a diff base
to detect the code owner.
- CodeOwner detection in fork repositories will be disabled because
almost all the fork repositories will not change CODEOWNERS files but it
should not be used on fork repositories' pull requests.

---------

Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2024-03-17 02:40:06 +01:00
Giteabot
8242c3c88c fix double border and border-radius on empty action steps (#29845) (#29850)
Backport #29845 by @silverwind

Before, double border-bottom and incorrect border-radius:

<img width="914" alt="Screenshot 2024-03-16 at 14 46 31"
src="https://github.com/go-gitea/gitea/assets/115237/6ea63c42-754c-420c-a0f5-c889a8507d9f">

After, both fixed:

<img width="917" alt="Screenshot 2024-03-16 at 14 45 59"
src="https://github.com/go-gitea/gitea/assets/115237/9d3f2dba-6b22-441d-8e99-5809d5f1f1c0">

Co-authored-by: silverwind <me@silverwind.io>
2024-03-16 18:16:45 +01:00
6543
0cbbcf20e3 Make meilisearch do exact search for issues (#29740 & #29671) (#29846)
Backport https://github.com/go-gitea/gitea/pull/29740 (based on #29671
...)
2024-03-16 17:01:40 +01:00
Giteabot
47dc4598a3 Fix for attribute not pointing to the ID of the color picker (#29813) (#29815)
Backport #29813 by @yardenshoham

It didn't include the word picker.

Signed-off-by: Yarden Shoham <git@yardenshoham.com>
2024-03-15 13:33:46 +00:00
silverwind
817d5e4d30 Use Temporal.PlainDate for absolute dates (#29804) (#29808)
Backport https://github.com/go-gitea/gitea/pull/29804.

Use the upcoming
[Temporal.PlainDate](https://tc39.es/proposal-temporal/docs/plaindate.html)
via polyfill. If there is any remaining bugs in `<absolute-date>` this
will iron them out. I opted for the lightweight polyfill because both
seem to achieve our goal of localizeable absolute dates.

- With
[`@js-temporal/polyfill`](https://www.npmjs.com/package/@js-temporal/polyfill)
chunk size goes from 81.4 KiB to 274 KiB
- With
[`temporal-polyfill`](https://www.npmjs.com/package/temporal-polyfill)
chunk size goes from 81.4 KiB to 142 KiB

Also see [this
table](https://github.com/fullcalendar/temporal-polyfill?tab=readme-ov-file#comparison-with-js-temporalpolyfill)
for more comparisons of these polyfills. Soon there will be
[treeshakable
API](https://github.com/fullcalendar/temporal-polyfill?tab=readme-ov-file#tree-shakable-api)
as well which will further reduce size.
2024-03-15 11:20:42 +01:00
Lunny Xiao
31ab839a65 Update Chroma to v2.13.0 (#29732) (#29805)
Backport #29732 

This adds new lexers and includes some fixes. See
https://github.com/alecthomas/chroma/releases/tag/v2.13.0 for the full
changelog.

Co-authored-by: JakobDev <jakobdev@gmx.de>
2024-03-15 16:45:10 +08:00
Giteabot
df23ec0f8b Fix Safari spinner rendering (#29801) (#29802)
Backport #29801 by @silverwind

Fixes: https://github.com/go-gitea/gitea/issues/29041
Fixes: https://github.com/go-gitea/gitea/pull/29713

Any of the `width: *-content` properties seem to workaround this Webkit
bug, this one seemed most suitable.

Before:
<img width="184" alt="Screenshot 2024-03-14 at 22 29 58"
src="https://github.com/go-gitea/gitea/assets/115237/6effc5f0-bc64-4752-be74-9c43b3974407">

After:
<img width="177" alt="Screenshot 2024-03-14 at 22 30 30"
src="https://github.com/go-gitea/gitea/assets/115237/5de244d7-6b46-428e-957c-4b10f53e2441">

Co-authored-by: silverwind <me@silverwind.io>
2024-03-14 22:08:59 +00:00
Giteabot
e0a9a921af Support GITEA_I_AM_BEING_UNSAFE_RUNNING_AS_ROOT env (#29788) (#29791)
Backport #29788 by @wolfogre

I was trying to run unit tests for Gitea on act runner, by using `make
test`.

It failed with log:

```
2024/03/14 03:09:26 ...s/setting/setting.go:180:loadRunModeFrom() [F] Gitea is not supposed to be run as root. Sorry. If you need to use privileged TCP ports please instead use setcap and the `cap_net_bind_service` permission
```

So it will be convenient to skip by setting environment, since it's OK
to use root user in job containers.

It's not a bug, but I want to backport it to v1.21 since it doesn't
break anything.

---------

Co-authored-by: Jason Song <i@wolfogre.com>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2024-03-14 10:02:37 +00:00
Giteabot
e03cf66e8b Fix missing translation on milestons (#29785) (#29789)
Backport #29785 by @lunny

Caused by #26569
Fix #29778

Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
2024-03-14 09:21:04 +01:00
Lunny Xiao
61db562a5f Fix user router possbile panic (#29751) (#29786)
regression from #28023
backport #29751
2024-03-14 12:44:14 +08:00
sillyguodong
538efb9df7 Make runs-on support variable expression (#29468) (#29782)
backport #29468 

Close issue: https://gitea.com/gitea/act_runner/issues/445
Follow: https://gitea.com/gitea/act/pulls/91

Move `getSecretsOfTask` and `getVariablesOfTask` under models because of
circular dependency issues.
2024-03-14 10:19:01 +08:00
Giteabot
5e3581f073 Fix possible NPE in ToPullReviewList (#29759) (#29775)
Backport #29759 by @lunny

Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2024-03-13 21:42:17 +01:00
Denys Konovalov
bb9860307f Update to labeler v5 (#29721) (#29765)
Backport #29721

Updated to actions/labeler@v5

Updated labeler config accordingly, also improved the config and added
more labels.

Co-authored-by: Giteabot <teabot@gitea.io>
2024-03-13 13:42:55 +00:00
wxiaoguang
bb2640c485 Fix incorrect package link method calls in templates (#29580) (#29764)
Backport #29580
Fix #29562
Fix #29762
Follow  #29531
2024-03-13 19:43:31 +08:00
Giteabot
462ae88fc2 Suppress error from monaco-editor (#29684) (#29758)
Backport #29684 by @silverwind

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

I see no way for us to catch this error, so downgrade it until
https://github.com/microsoft/monaco-editor/issues/4325 is fixed, which
will likely take a few weeks to propagate up from vscode.

The entries in `updates.config.js` will make
[`updates`](https://github.com/silverwind/updates) not upgrade these
anymore and I think it's good documentation as well to have the reasons
why we don't upgrade these dependencies.

Co-authored-by: silverwind <me@silverwind.io>
2024-03-13 09:02:00 +01:00
147 changed files with 2552 additions and 982 deletions
+69 -21
View File
@@ -1,36 +1,84 @@
modifies/docs:
- "**/*.md"
- "docs/**"
- changed-files:
- any-glob-to-any-file:
- "**/*.md"
- "docs/**"
modifies/frontend:
- "web_src/**/*"
- changed-files:
- any-glob-to-any-file:
- "web_src/**"
- "tailwind.config.js"
- "webpack.config.js"
modifies/templates:
- all: ["templates/**", "!templates/swagger/v1_json.tmpl"]
- changed-files:
- all-globs-to-any-file:
- "templates/**"
- "!templates/swagger/v1_json.tmpl"
modifies/api:
- "routers/api/**"
- "templates/swagger/v1_json.tmpl"
- changed-files:
- any-glob-to-any-file:
- "routers/api/**"
- "templates/swagger/v1_json.tmpl"
modifies/cli:
- "cmd/**"
- changed-files:
- any-glob-to-any-file:
- "cmd/**"
modifies/translation:
- "options/locale/*.ini"
- changed-files:
- any-glob-to-any-file:
- "options/locale/*.ini"
modifies/migrations:
- "models/migrations/**/*"
- changed-files:
- any-glob-to-any-file:
- "models/migrations/**"
modifies/internal:
- "Makefile"
- "Dockerfile"
- "Dockerfile.rootless"
- "docker/**"
- "webpack.config.js"
- ".eslintrc.yaml"
- ".golangci.yml"
- ".markdownlint.yaml"
- ".spectral.yaml"
- ".stylelintrc.yaml"
- ".yamllint.yaml"
- ".github/**"
- changed-files:
- any-glob-to-any-file:
- ".air.toml"
- "Makefile"
- "Dockerfile"
- "Dockerfile.rootless"
- ".dockerignore"
- "docker/**"
- ".editorconfig"
- ".eslintrc.yaml"
- ".golangci.yml"
- ".gitpod.yml"
- ".markdownlint.yaml"
- ".spectral.yaml"
- ".stylelintrc.yaml"
- ".yamllint.yaml"
- ".github/**"
- ".gitea/"
- ".devcontainer/**"
- "build.go"
- "build/**"
- "contrib/**"
modifies/dependencies:
- changed-files:
- any-glob-to-any-file:
- "package.json"
- "package-lock.json"
- "poetry.toml"
- "poetry.lock"
- "go.mod"
- "go.sum"
- "pyproject.toml"
modifies/go:
- changed-files:
- any-glob-to-any-file:
- "**/*.go"
modifies/js:
- changed-files:
- any-glob-to-any-file:
- "**/*.js"
+2 -3
View File
@@ -9,13 +9,12 @@ concurrency:
cancel-in-progress: true
jobs:
label:
labeler:
runs-on: ubuntu-latest
permissions:
contents: read
pull-requests: write
steps:
- uses: actions/labeler@v4
- uses: actions/labeler@v5
with:
dot: true
sync-labels: true
+82 -2
View File
@@ -4,7 +4,87 @@ This changelog goes through all the changes that have been made in each release
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).
## [1.21.8](https://github.com/go-gitea/gitea/releases/tag/1.21.8) - 2024-03-12
## [1.21.11](https://github.com/go-gitea/gitea/releases/tag/v1.21.11) - 2024-04-07
* SECURITY
* Use go1.21.9 to include Golang security fix
* Fix possible renderer security problem (#30136) (#30315)
* BUGFIXES
* Fix close file in the Upload func (#30262) (#30269)
* Fix inline math blocks can't be preceeded/followed by alphanumerical characters (#30175) (#30250)
* Fix missing 0 prefix of GPG key id (#30245) (#30247)
* Include encoding in signature payload (#30174) (#30181)
* Move from `max( id )` to `max( index )` for latest commit statuses (#30076) (#30155)
* Load attachments for code comments (#30124) (#30126)
* Fix gitea doctor will remove repo-avatar files when executing command storage-archives (#30094) (#30120)
* Fix possible data race on tests (#30093) (#30108)
* Performance optimization for git push (#30104)
* Fix duplicate migrated milestones (#30102) (#30105)
* Fix panic for fixBrokenRepoUnits16961 (#30068) (#30100)
* Fix incorrect SVGs (#30087)
* Fix create commit status (#30225) (#30340)
* Performance optimization for git push (#30104) (#30354)
* Fix misuse of unsupported global variables (#30402)
* Fix to delete the cookie when AppSubURL is non-empty (#30375) (#30468)
* Avoid user does not exist error when detecting schedule actions when the commit author is an external user (#30357) (#30408)
* Change the default maxPerPage for gitbucket (#30392) (#30471)
* Check the token's owner and repository when registering a runner (#30406) (#30412)
* Avoid losing token when updating mirror settings (#30429) (#30466)
* Fix commit status cache which missed target_url (#30426) (#30445)
* Fix rename branch 500 when the target branch is deleted but exist in database (#30430) (#30437)
* Fix mirror error when mirror repo is empty (#30432) (#30467)
* Use db.ListOptions directly instead of Paginator interface to make it easier to use and fix performance of /pulls and /issues (#29990) (#30447)
* Fix code owners will not be mentioned when a pull request comes from a forked repository (#30476) (#30497)
* DOCS
* Update actions variables documents (#30394) (#30405)
* MISC
* Update katex to 0.16.10 (#30089)
* Upgrade go-sqlite to v1.14.22 (#30462)
## [1.21.10](https://github.com/go-gitea/gitea/releases/tag/v1.21.10) - 2024-03-25
* BUGFIXES
* Fix Add/Remove WIP on pull request title failure (#29999) (#30066)
* Fix misuse of `TxContext` (#30061) (#30062)
* Respect DEFAULT_ORG_MEMBER_VISIBLE setting when adding creator to org (#30013) (#30035)
* Escape paths for find file correctly (#30026) (#30031)
* Remove duplicate option in admin screen and now-unused translation keys (#28492) (#30024)
* Fix manual merge form and 404 page templates (#30000)
## [1.21.9](https://github.com/go-gitea/gitea/releases/tag/v1.21.9) - 2024-03-21
* PERFORMANCE
* Only do counting when count_only=true for repo dashboard (#29884) (#29905)
* Add cache for dashboard commit status (#29932)
* ENHANCEMENT
* Make runs-on support variable expression (#29468) (#29782)
* Show Actions post step when it's running (#29926) (#29928)
* BUGFIXES
* Fix PR creation via API between branches of the same repo with head field namespaced (#26986) (#29857)
* Fix and rewrite markup anchor processing (#29931) (#29946)
* Notify reviewers added via CODEOWNERS (#29842) (#29902)
* Fix template error when comment review doesn't exist (#29888) (#29889)
* Fix user id column case (#29863) (#29867)
* Make meilisearch do exact search for issues (#29740 & #29671) (#29846)
* Fix the `for` attribute not pointing to the ID of the color picker (#29813) (#29815)
* Fix codeowner detected diff base branch to mergebase (#29783) (#29807)
* Fix Safari spinner rendering (#29801) (#29802)
* Fix missing translation on milestones (#29785) (#29789)
* Fix user router possible panic (#29751) (#29786)
* Fix possible NPE in ToPullReviewList (#29759) (#29775)
* Fix the wrong default value of ENABLE_OPENID_SIGNIN on docs (#29925) (#29927)
* Solving the issue of UI disruption when the review is deleted without refreshing (#29951) (#29968)
* Fix loadOneBranch panic (#29938) (#29939)
* Fix invalid link of the commit status when ref is tagged (#29752) (#29908)
* Editor error message misleading due to re-used key. (#29859) (#29876)
* Fix double border and border-radius on empty action steps (#29845) (#29850)
* Use `Temporal.PlainDate` for absolute dates (#29804) (#29808)
* Fix incorrect package link method calls in templates (#29580) (#29764)
* Fix the bug that the user may log out if GetUserByID returns unknown error (#29962) (#29964)
* Performance improvements for pull request list page (#29900) (#29972)
* Fix bugs in rerunning jobs (#29983) (#29955)
## [1.21.8](https://github.com/go-gitea/gitea/releases/tag/v1.21.8) - 2024-03-12
* SECURITY
* Only use supported sort orders for "/explore/users" page (#29430) (#29443)
@@ -49,7 +129,7 @@ been added to each release, please refer to the [blog](https://blog.gitea.com).
* Fixing the issue when status checks per rule matches multiple actions (#29631) (#29655)
* Improve contrast on blame timestamp, fix double border (#29482) (#29485)
## [1.21.7](https://github.com/go-gitea/gitea/releases/tag/1.21.7) - 2024-02-26
## [1.21.7](https://github.com/go-gitea/gitea/releases/tag/v1.21.7) - 2024-02-26
* ENHANCEMENTS
* Users with `read` permission of pull requests can be assigned too (#27263) (#29372)
+23 -14
View File
@@ -446,23 +446,26 @@ Gitea or set your environment appropriately.`, "")
func hookPrintResults(results []private.HookPostReceiveBranchResult) {
for _, res := range results {
if !res.Message {
continue
}
fmt.Fprintln(os.Stderr, "")
if res.Create {
fmt.Fprintf(os.Stderr, "Create a new pull request for '%s':\n", res.Branch)
fmt.Fprintf(os.Stderr, " %s\n", res.URL)
} else {
fmt.Fprint(os.Stderr, "Visit the existing pull request:\n")
fmt.Fprintf(os.Stderr, " %s\n", res.URL)
}
fmt.Fprintln(os.Stderr, "")
os.Stderr.Sync()
hookPrintResult(res.Message, res.Create, res.Branch, res.URL)
}
}
func hookPrintResult(output, isCreate bool, branch, url string) {
if !output {
return
}
fmt.Fprintln(os.Stderr, "")
if isCreate {
fmt.Fprintf(os.Stderr, "Create a new pull request for '%s':\n", branch)
fmt.Fprintf(os.Stderr, " %s\n", url)
} else {
fmt.Fprint(os.Stderr, "Visit the existing pull request:\n")
fmt.Fprintf(os.Stderr, " %s\n", url)
}
fmt.Fprintln(os.Stderr, "")
os.Stderr.Sync()
}
func pushOptions() map[string]string {
opts := make(map[string]string)
if pushCount, err := strconv.Atoi(os.Getenv(private.GitPushOptionCount)); err == nil {
@@ -688,6 +691,12 @@ Gitea or set your environment appropriately.`, "")
}
err = writeFlushPktLine(ctx, os.Stdout)
if err == nil {
for _, res := range resp.Results {
hookPrintResult(res.ShouldShowMessage, res.IsCreatePR, res.HeadBranch, res.URL)
}
}
return err
}
@@ -581,7 +581,7 @@ And the following unique queues:
## OpenID (`openid`)
- `ENABLE_OPENID_SIGNIN`: **false**: Allow authentication in via OpenID.
- `ENABLE_OPENID_SIGNIN`: **true**: Allow authentication in via OpenID.
- `ENABLE_OPENID_SIGNUP`: **! DISABLE\_REGISTRATION**: Allow registering via OpenID.
- `WHITELISTED_URIS`: **_empty_**: If non-empty, list of POSIX regex patterns matching
OpenID URI's to permit.
@@ -559,7 +559,7 @@ Gitea 创建以下非唯一队列:
## OpenID (`openid`)
- `ENABLE_OPENID_SIGNIN`: **false**允许通过OpenID进行身份验证。
- `ENABLE_OPENID_SIGNIN`: **true**允许通过OpenID进行身份验证。
- `ENABLE_OPENID_SIGNUP`: **! DISABLE\_REGISTRATION**允许通过OpenID进行注册。
- `WHITELISTED_URIS`: **_empty_**如果非空是一组匹配OpenID URI的POSIX正则表达式模式用于允许访问。
- `BLACKLISTED_URIS`: **_empty_**如果非空是一组匹配OpenID URI的POSIX正则表达式模式用于阻止访问。
@@ -545,7 +545,7 @@ In this option, the idea is that the host SSH uses an `AuthorizedKeysCommand` in
```bash
cat <<"EOF" | sudo tee /home/git/docker-shell
#!/bin/sh
/usr/bin/docker exec -i --env SSH_ORIGINAL_COMMAND="$SSH_ORIGINAL_COMMAND" gitea sh "$@"
/usr/bin/docker exec -i -u git --env SSH_ORIGINAL_COMMAND="$SSH_ORIGINAL_COMMAND" gitea sh "$@"
EOF
sudo chmod +x /home/git/docker-shell
sudo usermod -s /home/git/docker-shell git
@@ -560,7 +560,7 @@ Add the following block to `/etc/ssh/sshd_config`, on the host:
```bash
Match User git
AuthorizedKeysCommandUser git
AuthorizedKeysCommand /usr/bin/docker exec -i gitea /usr/local/bin/gitea keys -c /data/gitea/conf/app.ini -e git -u %u -t %t -k %k
AuthorizedKeysCommand /usr/bin/docker exec -i -u git gitea /usr/local/bin/gitea keys -c /data/gitea/conf/app.ini -e git -u %u -t %t -k %k
```
(From 1.16.0 you will not need to set the `-c /data/gitea/conf/app.ini` option.)
@@ -301,34 +301,3 @@ sudo systemctl enable act_runner --now
```
If using Docker, the `act_runner` user should also be added to the `docker` group before starting the service. Keep in mind that this effectively gives `act_runner` root access to the system [[1]](https://docs.docker.com/engine/security/#docker-daemon-attack-surface).
## Configuration variable
You can create configuration variables on the user, organization and repository level.
The level of the variable depends on where you created it.
### Naming conventions
The following rules apply to variable names:
- Variable names can only contain alphanumeric characters (`[a-z]`, `[A-Z]`, `[0-9]`) or underscores (`_`). Spaces are not allowed.
- Variable names must not start with the `GITHUB_` and `GITEA_` prefix.
- Variable names must not start with a number.
- Variable names are case-insensitive.
- Variable names must be unique at the level they are created at.
- Variable names must not be `CI`.
### Using variable
After creating configuration variables, they will be automatically filled in the `vars` context.
They can be accessed through expressions like `{{ vars.VARIABLE_NAME }}` in the workflow.
### Precedence
If a variable with the same name exists at multiple levels, the variable at the lowest level takes precedence:
A repository variable will always be chosen over an organization/user variable.
@@ -258,32 +258,3 @@ Runner的标签用于确定Runner可以运行哪些Job以及如何运行它们
Runner将从Gitea实例获取Job并自动运行它们。
由于Act Runner仍处于开发中建议定期检查最新版本并进行升级。
## 变量
您可以创建用户、组织和仓库级别的变量。变量的级别取决于创建它的位置。
### 命名规则
以下规则适用于变量名:
- 变量名称只能包含字母数字字符 (`[a-z]`, `[A-Z]`, `[0-9]`) 或下划线 (`_`)。不允许使用空格。
- 变量名称不能以 `GITHUB_``GITEA_` 前缀开头。
- 变量名称不能以数字开头。
- 变量名称不区分大小写。
- 变量名称在创建它们的级别上必须是唯一的。
- 变量名称不能为 “CI”。
### 使用
创建配置变量后,它们将自动填充到 `vars` 上下文中。您可以在工作流中使用类似 `{{ vars.VARIABLE_NAME }}` 这样的表达式来使用它们。
### 优先级
如果同名变量存在于多个级别,则级别最低的变量优先。
仓库级别的变量总是比组织或者用户级别的变量优先被选中。
@@ -0,0 +1,41 @@
---
date: "2024-04-10T22:21:00+08:00"
title: "Variables"
slug: "actions-variables"
sidebar_position: 25
draft: false
toc: false
menu:
sidebar:
parent: "actions"
name: "Variables"
sidebar_position: 25
identifier: "actions-variables"
---
## Variables
You can create configuration variables on the user, organization and repository level.
The level of the variable depends on where you created it. When creating a variable, the
key will be converted to uppercase. You need use uppercase on the yaml file.
### Naming conventions
The following rules apply to variable names:
- Variable names can only contain alphanumeric characters (`[a-z]`, `[A-Z]`, `[0-9]`) or underscores (`_`). Spaces are not allowed.
- Variable names must not start with the `GITHUB_` and `GITEA_` prefix.
- Variable names must not start with a number.
- Variable names are case-insensitive.
- Variable names must be unique at the level they are created at.
- Variable names must not be `CI`.
### Using variable
After creating configuration variables, they will be automatically filled in the `vars` context.
They can be accessed through expressions like `${{ vars.VARIABLE_NAME }}` in the workflow.
### Precedence
If a variable with the same name exists at multiple levels, the variable at the lowest level takes precedence:
A repository variable will always be chosen over an organization/user variable.
@@ -0,0 +1,39 @@
---
date: "2024-04-10T22:21:00+08:00"
title: "变量"
slug: "actions-variables"
sidebar_position: 25
draft: false
toc: false
menu:
sidebar:
parent: "actions"
name: "变量"
sidebar_position: 25
identifier: "actions-variables"
---
## 变量
您可以创建用户、组织和仓库级别的变量。变量的级别取决于创建它的位置。当创建变量时,变量的名称会被
转换为大写在yaml文件中引用时需要使用大写。
### 命名规则
以下规则适用于变量名:
- 变量名称只能包含字母数字字符 (`[a-z]`, `[A-Z]`, `[0-9]`) 或下划线 (`_`)。不允许使用空格。
- 变量名称不能以 `GITHUB_``GITEA_` 前缀开头。
- 变量名称不能以数字开头。
- 变量名称不区分大小写。
- 变量名称在创建它们的级别上必须是唯一的。
- 变量名称不能为 `CI`
### 使用
创建配置变量后,它们将自动填充到 `vars` 上下文中。您可以在工作流中使用类似 `${{ vars.VARIABLE_NAME }}` 这样的表达式来使用它们。
### 优先级
如果同名变量存在于多个级别,则级别最低的变量优先。
仓库级别的变量总是比组织或者用户级别的变量优先被选中。
+10 -10
View File
@@ -17,7 +17,7 @@ require (
github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358
github.com/NYTimes/gziphandler v1.1.1
github.com/PuerkitoBio/goquery v1.8.1
github.com/alecthomas/chroma/v2 v2.10.0
github.com/alecthomas/chroma/v2 v2.13.0
github.com/blakesmith/ar v0.0.0-20190502131153-809d4375e1fb
github.com/blevesearch/bleve/v2 v2.3.10
github.com/bufbuild/connect-go v1.10.0
@@ -68,12 +68,12 @@ require (
github.com/json-iterator/go v1.1.12
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51
github.com/keybase/go-crypto v0.0.0-20200123153347-de78d2cb44f4
github.com/klauspost/compress v1.17.0
github.com/klauspost/compress v1.17.2
github.com/klauspost/cpuid/v2 v2.2.5
github.com/lib/pq v1.10.9
github.com/markbates/goth v1.78.0
github.com/mattn/go-isatty v0.0.19
github.com/mattn/go-sqlite3 v1.14.17
github.com/mattn/go-isatty v0.0.20
github.com/mattn/go-sqlite3 v1.14.22
github.com/meilisearch/meilisearch-go v0.25.1
github.com/mholt/archiver/v3 v3.5.1
github.com/microcosm-cc/bluemonday v1.0.26
@@ -173,10 +173,10 @@ require (
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
github.com/davidmz/go-pageant v1.0.2 // indirect
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
github.com/dlclark/regexp2 v1.10.0 // indirect
github.com/emersion/go-sasl v0.0.0-20220912192320-0145f2c60ead // indirect
github.com/fatih/color v1.15.0 // indirect
github.com/felixge/httpsnoop v1.0.3 // indirect
github.com/dlclark/regexp2 v1.11.0 // indirect
github.com/emersion/go-sasl v0.0.0-20231106173351-e73c9f7bad43 // indirect
github.com/fatih/color v1.16.0 // indirect
github.com/felixge/httpsnoop v1.0.4 // indirect
github.com/fxamacker/cbor/v2 v2.5.0 // indirect
github.com/go-ap/errors v0.0.0-20231003111023-183eef4b31b7 // indirect
github.com/go-asn1-ber/asn1-ber v1.5.5 // indirect
@@ -281,7 +281,7 @@ require (
github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 // indirect
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect
github.com/zeebo/blake3 v0.2.3 // indirect
go.etcd.io/bbolt v1.3.7 // indirect
go.etcd.io/bbolt v1.3.8 // indirect
go.mongodb.org/mongo-driver v1.12.1 // indirect
go.opentelemetry.io/otel v1.19.0 // indirect
go.opentelemetry.io/otel/trace v1.19.0 // indirect
@@ -303,7 +303,7 @@ replace github.com/hashicorp/go-version => github.com/6543/go-version v1.3.1
replace github.com/shurcooL/vfsgen => github.com/lunny/vfsgen v0.0.0-20220105142115-2c99e1ffdfa0
replace github.com/nektos/act => gitea.com/gitea/act v0.2.51
replace github.com/nektos/act => gitea.com/gitea/act v0.259.1
exclude github.com/gofrs/uuid v3.2.0+incompatible
+24 -24
View File
@@ -53,8 +53,8 @@ dario.cat/mergo v1.0.0/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk=
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
git.sr.ht/~mariusor/go-xsd-duration v0.0.0-20220703122237-02e73435a078 h1:cliQ4HHsCo6xi2oWZYKWW4bly/Ory9FuTpFPRxj/mAg=
git.sr.ht/~mariusor/go-xsd-duration v0.0.0-20220703122237-02e73435a078/go.mod h1:g/V2Hjas6Z1UHUp4yIx6bATpNzJ7DYtD0FG3+xARWxs=
gitea.com/gitea/act v0.2.51 h1:gXc/B4OlTciTTzAx9cmNyw04n2SDO7exPjAsR5Idu+c=
gitea.com/gitea/act v0.2.51/go.mod h1:CoaX2053jqBlD6JMgu4d4UgFL/rp2I14Kt5mMqcs0Z0=
gitea.com/gitea/act v0.259.1 h1:8GG1o/xtUHl3qjn5f0h/2FXrT5ubBn05TJOM5ry+FBw=
gitea.com/gitea/act v0.259.1/go.mod h1:UxZWRYqQG2Yj4+4OqfGWW5a3HELwejyWFQyU7F1jUD8=
gitea.com/go-chi/binding v0.0.0-20230415142243-04b515c6d669 h1:RUBX+MK/TsDxpHmymaOaydfigEbbzqUnG1OTZU/HAeo=
gitea.com/go-chi/binding v0.0.0-20230415142243-04b515c6d669/go.mod h1:77TZu701zMXWJFvB8gvTbQ92zQ3DQq/H7l5wAEjQRKc=
gitea.com/go-chi/cache v0.0.0-20210110083709-82c4c9ce2d5e/go.mod h1:k2V/gPDEtXGjjMGuBJiapffAXTv76H4snSmlJRLUhH0=
@@ -111,14 +111,14 @@ github.com/RoaringBitmap/roaring v0.4.23/go.mod h1:D0gp8kJQgE1A4LQ5wFLggQEyvDi06
github.com/RoaringBitmap/roaring v0.7.1/go.mod h1:jdT9ykXwHFNdJbEtxePexlFYH9LXucApeS0/+/g+p1I=
github.com/RoaringBitmap/roaring v1.6.0 h1:dc7kRiroETgJcHhWX6BerXkZz2b3JgLGg9nTURJL/og=
github.com/RoaringBitmap/roaring v1.6.0/go.mod h1:plvDsJQpxOC5bw8LRteu/MLWHsHez/3y6cubLI4/1yE=
github.com/alecthomas/assert/v2 v2.2.1 h1:XivOgYcduV98QCahG8T5XTezV5bylXe+lBxLG2K2ink=
github.com/alecthomas/assert/v2 v2.2.1/go.mod h1:pXcQ2Asjp247dahGEmsZ6ru0UVwnkhktn7S0bBDLxvQ=
github.com/alecthomas/assert/v2 v2.6.0 h1:o3WJwILtexrEUk3cUVal3oiQY2tfgr/FHWiz/v2n4FU=
github.com/alecthomas/assert/v2 v2.6.0/go.mod h1:Bze95FyfUr7x34QZrjL+XP+0qgp/zg8yS+TtBj1WA3k=
github.com/alecthomas/chroma/v2 v2.2.0/go.mod h1:vf4zrexSH54oEjJ7EdB65tGNHmH3pGZmVkgTP5RHvAs=
github.com/alecthomas/chroma/v2 v2.10.0 h1:T2iQOCCt4pRmRMfL55gTodMtc7cU0y7lc1Jb8/mK/64=
github.com/alecthomas/chroma/v2 v2.10.0/go.mod h1:4TQu7gdfuPjSh76j78ietmqh9LiurGF0EpseFXdKMBw=
github.com/alecthomas/chroma/v2 v2.13.0 h1:VP72+99Fb2zEcYM0MeaWJmV+xQvz5v5cxRHd+ooU1lI=
github.com/alecthomas/chroma/v2 v2.13.0/go.mod h1:BUGjjsD+ndS6eX37YgTchSEG+Jg9Jv1GiZs9sqPqztk=
github.com/alecthomas/repr v0.0.0-20220113201626-b1b626ac65ae/go.mod h1:2kn6fqh/zIyPLmm3ugklbEi5hg5wS435eygvNfaDQL8=
github.com/alecthomas/repr v0.2.0 h1:HAzS41CIzNW5syS8Mf9UwXhNH1J9aix/BvDRf1Ml2Yk=
github.com/alecthomas/repr v0.2.0/go.mod h1:Fr0507jx4eOXV7AlPV6AVZLYrLIuIeSOWtW57eE/O/4=
github.com/alecthomas/repr v0.4.0 h1:GhI2A8MACjfegCPVq9f1FLvIBS+DrQ2KQBFZP1iFzXc=
github.com/alecthomas/repr v0.4.0/go.mod h1:Fr0507jx4eOXV7AlPV6AVZLYrLIuIeSOWtW57eE/O/4=
github.com/alexbrainman/sspi v0.0.0-20210105120005-909beea2cc74 h1:Kk6a4nehpJ3UuJRqlA3JxYxBZEqCeOmATOvrbT4p9RA=
github.com/alexbrainman/sspi v0.0.0-20210105120005-909beea2cc74/go.mod h1:cEWa1LVoE5KvSD9ONXsZrj0z6KqySlCCNKHlLzbqAt4=
github.com/andybalholm/brotli v1.0.1/go.mod h1:loMXtMfwqflxFJPmdbJO0a3KNoPuLBgiu3qAvBg8x/Y=
@@ -269,8 +269,8 @@ github.com/djherbis/nio/v3 v3.0.1/go.mod h1:Ng4h80pbZFMla1yKzm61cF0tqqilXZYrogmW
github.com/dlclark/regexp2 v1.2.0/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc=
github.com/dlclark/regexp2 v1.4.0/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc=
github.com/dlclark/regexp2 v1.7.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=
github.com/dlclark/regexp2 v1.10.0 h1:+/GIL799phkJqYW+3YbOd8LCcbHzT0Pbo8zl70MHsq0=
github.com/dlclark/regexp2 v1.10.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=
github.com/dlclark/regexp2 v1.11.0 h1:G/nrcoOa7ZXlpoa/91N3X7mM3r8eIlMBBJZvsz/mxKI=
github.com/dlclark/regexp2 v1.11.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=
github.com/dnaeon/go-vcr v1.2.0/go.mod h1:R4UdLID7HZT3taECzJs4YgbbH6PIGXB6W/sc5OLb6RQ=
github.com/dsnet/compress v0.0.2-0.20210315054119-f66993602bf5 h1:iFaUwBSo5Svw6L7HYpRu/0lE3e0BaElwnNO1qkNQxBY=
github.com/dsnet/compress v0.0.2-0.20210315054119-f66993602bf5/go.mod h1:qssHWj60/X5sZFNxpG4HBPDHVqxNm4DfnCKgrbZOT+s=
@@ -288,8 +288,8 @@ github.com/emersion/go-imap v1.2.1 h1:+s9ZjMEjOB8NzZMVTM3cCenz2JrQIGGo5j1df19WjT
github.com/emersion/go-imap v1.2.1/go.mod h1:Qlx1FSx2FTxjnjWpIlVNEuX+ylerZQNFE5NsmKFSejY=
github.com/emersion/go-message v0.15.0/go.mod h1:wQUEfE+38+7EW8p8aZ96ptg6bAb1iwdgej19uXASlE4=
github.com/emersion/go-sasl v0.0.0-20200509203442-7bfe0ed36a21/go.mod h1:iL2twTeMvZnrg54ZoPDNfJaJaqy0xIQFuBdrLsmspwQ=
github.com/emersion/go-sasl v0.0.0-20220912192320-0145f2c60ead h1:fI1Jck0vUrXT8bnphprS1EoVRe2Q5CKCX8iDlpqjQ/Y=
github.com/emersion/go-sasl v0.0.0-20220912192320-0145f2c60ead/go.mod h1:iL2twTeMvZnrg54ZoPDNfJaJaqy0xIQFuBdrLsmspwQ=
github.com/emersion/go-sasl v0.0.0-20231106173351-e73c9f7bad43 h1:hH4PQfOndHDlpzYfLAAfl63E8Le6F2+EL/cdhlkyRJY=
github.com/emersion/go-sasl v0.0.0-20231106173351-e73c9f7bad43/go.mod h1:iL2twTeMvZnrg54ZoPDNfJaJaqy0xIQFuBdrLsmspwQ=
github.com/emersion/go-textwrapper v0.0.0-20200911093747-65d896831594/go.mod h1:aqO8z8wPrjkscevZJFVE1wXJrLpC5LtJG7fqLOsPb2U=
github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc=
github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ=
@@ -301,13 +301,13 @@ github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.m
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/ethantkoenig/rupture v1.0.1 h1:6aAXghmvtnngMgQzy7SMGdicMvkV86V4n9fT0meE5E4=
github.com/ethantkoenig/rupture v1.0.1/go.mod h1:Sjqo/nbffZp1pVVXNGhpugIjsWmuS9KiIB4GtpEBur4=
github.com/fatih/color v1.15.0 h1:kOqh6YHBtK8aywxGerMG2Eq3H6Qgoqeo13Bk2Mv/nBs=
github.com/fatih/color v1.15.0/go.mod h1:0h5ZqXfHYED7Bhv2ZJamyIOUej9KtShiJESRwBDUSsw=
github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM=
github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE=
github.com/felixge/fgprof v0.9.3 h1:VvyZxILNuCiUCSXtPtYmmtGvb65nqXh2QFWc0Wpf2/g=
github.com/felixge/fgprof v0.9.3/go.mod h1:RdbpDgzqYVh/T9fPELJyV7EYJuHB55UTEULNun8eiPw=
github.com/felixge/httpsnoop v1.0.1/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
github.com/felixge/httpsnoop v1.0.3 h1:s/nj+GCswXYzN5v2DpNMuMQYe+0DDwt5WVCU6CWBdXk=
github.com/felixge/httpsnoop v1.0.3/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=
github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
github.com/fortytw2/leaktest v1.3.0 h1:u8491cBMTQ8ft8aeV+adlcytMZylmA5nnwwkRZjI8vw=
github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g=
github.com/frankban/quicktest v1.14.4 h1:g2rn0vABPOOXmZUj+vbmUp0lPoXEMuhTpIluN0XL9UY=
@@ -654,8 +654,8 @@ github.com/klauspost/compress v1.11.7/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYs
github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
github.com/klauspost/compress v1.15.0/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
github.com/klauspost/compress v1.15.6/go.mod h1:PhcZ0MbTNciWF3rruxRgKxI5NkcHHrHUDtV4Yw2GlzU=
github.com/klauspost/compress v1.17.0 h1:Rnbp4K9EjcDuVuHtd0dgA4qNuv9yKDYKK1ulpJwgrqM=
github.com/klauspost/compress v1.17.0/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE=
github.com/klauspost/compress v1.17.2 h1:RlWWUY/Dr4fL8qk9YG7DTZ7PDgME2V4csBXA8L/ixi4=
github.com/klauspost/compress v1.17.2/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE=
github.com/klauspost/cpuid v1.2.0/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
github.com/klauspost/cpuid/v2 v2.0.1/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
github.com/klauspost/cpuid/v2 v2.0.12/go.mod h1:g2LTdtYhdyuGPqyWyv7qRAmj1WBqxuObKfj5c0PQa7c=
@@ -710,14 +710,14 @@ github.com/markbates/safe v1.0.1/go.mod h1:nAqgmRi7cY2nqMc92/bSEeQA+R4OheNU2T1kN
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA=
github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U=
github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
github.com/mattn/go-sqlite3 v1.11.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
github.com/mattn/go-sqlite3 v1.14.17 h1:mCRHCLDUBXgpKAqIKsaAaAsrAlbkeomtRFKXh2L6YIM=
github.com/mattn/go-sqlite3 v1.14.17/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg=
github.com/mattn/go-sqlite3 v1.14.22 h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o4kU=
github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo=
github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4=
github.com/meilisearch/meilisearch-go v0.25.1 h1:D5wY22sn5kkpRH3uYMGlwltdUEq5regIFmO7awHz3Vo=
@@ -1010,8 +1010,8 @@ github.com/zeebo/blake3 v0.2.3/go.mod h1:mjJjZpnsyIVtVgTOSpJ9vmRE4wgDeyt2HU3qXvv
github.com/zeebo/pcg v1.0.1 h1:lyqfGeWiv4ahac6ttHs+I5hwtH/+1mrhlCtVNQM2kHo=
github.com/zeebo/pcg v1.0.1/go.mod h1:09F0S9iiKrwn9rlI5yjLkmrug154/YRW6KnnXVDM/l4=
go.etcd.io/bbolt v1.3.5/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ=
go.etcd.io/bbolt v1.3.7 h1:j+zJOnnEjF/kyHlDDgGnVL/AIqIJPq8UoB2GSNfkUfQ=
go.etcd.io/bbolt v1.3.7/go.mod h1:N9Mkw9X8x5fupy0IKsmuqVtoGDyxsaDlbk4Rd05IAQw=
go.etcd.io/bbolt v1.3.8 h1:xs88BrvEv273UsB79e0hcVrlUWmS0a8upikMFhSyAtA=
go.etcd.io/bbolt v1.3.8/go.mod h1:N9Mkw9X8x5fupy0IKsmuqVtoGDyxsaDlbk4Rd05IAQw=
go.mongodb.org/mongo-driver v1.7.3/go.mod h1:NqaYOwnXWr5Pm7AOpO5QFxKJ503nbMse/R79oO62zWg=
go.mongodb.org/mongo-driver v1.7.5/go.mod h1:VXEWRZ6URJIkUq2SCAyapmhH0ZLRBP+FT4xhp5Zvxng=
go.mongodb.org/mongo-driver v1.10.0/go.mod h1:wsihk0Kdgv8Kqu1Anit4sfK+22vSFbUrAVEYRhCXrA8=
+3
View File
@@ -44,6 +44,9 @@ func (schedules ScheduleList) LoadTriggerUser(ctx context.Context) error {
schedule.TriggerUser = user_model.NewActionsUser()
} else {
schedule.TriggerUser = users[schedule.TriggerUserID]
if schedule.TriggerUser == nil {
schedule.TriggerUser = user_model.NewGhostUser()
}
}
}
return nil
+26
View File
@@ -10,6 +10,7 @@ import (
"strings"
"code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/timeutil"
"code.gitea.io/gitea/modules/util"
@@ -95,3 +96,28 @@ func UpdateVariable(ctx context.Context, variable *ActionVariable) (bool, error)
})
return count != 0, err
}
func GetVariablesOfRun(ctx context.Context, run *ActionRun) (map[string]string, error) {
variables := map[string]string{}
// Org / User level
ownerVariables, err := FindVariables(ctx, FindVariablesOpts{OwnerID: run.Repo.OwnerID})
if err != nil {
log.Error("find variables of org: %d, error: %v", run.Repo.OwnerID, err)
return nil, err
}
// Repo level
repoVariables, err := FindVariables(ctx, FindVariablesOpts{RepoID: run.RepoID})
if err != nil {
log.Error("find variables of repo: %d, error: %v", run.RepoID, err)
return nil, err
}
// Level precedence: Repo > Org / User
for _, v := range append(ownerVariables, repoVariables...) {
variables[v.Name] = v.Data
}
return variables, nil
}
+29
View File
@@ -20,6 +20,7 @@ import (
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/timeutil"
"code.gitea.io/gitea/modules/util"
"xorm.io/builder"
"xorm.io/xorm"
@@ -821,3 +822,31 @@ func UpdateNotificationStatuses(ctx context.Context, user *user_model.User, curr
Update(n)
return err
}
// LoadIssuePullRequests loads all issues' pull requests if possible
func (nl NotificationList) LoadIssuePullRequests(ctx context.Context) error {
issues := make(map[int64]*issues_model.Issue, len(nl))
for _, notification := range nl {
if notification.Issue != nil && notification.Issue.IsPull && notification.Issue.PullRequest == nil {
issues[notification.Issue.ID] = notification.Issue
}
}
if len(issues) == 0 {
return nil
}
pulls, err := issues_model.GetPullRequestByIssueIDs(ctx, util.KeysOfMap(issues))
if err != nil {
return err
}
for _, pull := range pulls {
if issue := issues[pull.IssueID]; issue != nil {
issue.PullRequest = pull
issue.PullRequest.Issue = issue
}
}
return nil
}
@@ -139,13 +139,7 @@ func ParseCommitWithSignature(ctx context.Context, c *git.Commit) *CommitVerific
}
}
keyID := ""
if sig.IssuerKeyId != nil && (*sig.IssuerKeyId) != 0 {
keyID = fmt.Sprintf("%X", *sig.IssuerKeyId)
}
if keyID == "" && sig.IssuerFingerprint != nil && len(sig.IssuerFingerprint) > 0 {
keyID = fmt.Sprintf("%X", sig.IssuerFingerprint[12:20])
}
keyID := tryGetKeyIDFromSignature(sig)
defaultReason := NoKeyFound
// First check if the sig has a keyID and if so just look at that
+10
View File
@@ -134,3 +134,13 @@ func extractSignature(s string) (*packet.Signature, error) {
}
return sig, nil
}
func tryGetKeyIDFromSignature(sig *packet.Signature) string {
if sig.IssuerKeyId != nil && (*sig.IssuerKeyId) != 0 {
return fmt.Sprintf("%016X", *sig.IssuerKeyId)
}
if sig.IssuerFingerprint != nil && len(sig.IssuerFingerprint) > 0 {
return fmt.Sprintf("%016X", sig.IssuerFingerprint[12:20])
}
return ""
}
+12
View File
@@ -11,7 +11,9 @@ import (
"code.gitea.io/gitea/models/unittest"
user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/timeutil"
"code.gitea.io/gitea/modules/util"
"github.com/keybase/go-crypto/openpgp/packet"
"github.com/stretchr/testify/assert"
)
@@ -391,3 +393,13 @@ epiDVQ==
assert.Equal(t, time.Unix(1586105389, 0), expire)
}
}
func TestTryGetKeyIDFromSignature(t *testing.T) {
assert.Empty(t, tryGetKeyIDFromSignature(&packet.Signature{}))
assert.Equal(t, "038D1A3EADDBEA9C", tryGetKeyIDFromSignature(&packet.Signature{
IssuerKeyId: util.ToPointer(uint64(0x38D1A3EADDBEA9C)),
}))
assert.Equal(t, "038D1A3EADDBEA9C", tryGetKeyIDFromSignature(&packet.Signature{
IssuerFingerprint: []uint8{0xb, 0x23, 0x24, 0xc7, 0xe6, 0xfe, 0x4f, 0x3a, 0x6, 0x26, 0xc1, 0x21, 0x3, 0x8d, 0x1a, 0x3e, 0xad, 0xdb, 0xea, 0x9c},
}))
}
+10
View File
@@ -120,6 +120,16 @@ func (c *halfCommitter) Close() error {
// TxContext represents a transaction Context,
// it will reuse the existing transaction in the parent context or create a new one.
// Some tips to use:
//
// 1 It's always recommended to use `WithTx` in new code instead of `TxContext`, since `WithTx` will handle the transaction automatically.
// 2. To maintain the old code which uses `TxContext`:
// a. Always call `Close()` before returning regardless of whether `Commit()` has been called.
// b. Always call `Commit()` before returning if there are no errors, even if the code did not change any data.
// c. Remember the `Committer` will be a halfCommitter when a transaction is being reused.
// So calling `Commit()` will do nothing, but calling `Close()` without calling `Commit()` will rollback the transaction.
// And all operations submitted by the caller stack will be rollbacked as well, not only the operations in the current function.
// d. It doesn't mean rollback is forbidden, but always do it only when there is an error, and you do want to rollback.
func TxContext(parentCtx context.Context) (*Context, Committer, error) {
if sess, ok := inTransaction(parentCtx); ok {
return newContext(parentCtx, sess, true), &halfCommitter{committer: sess}, nil
+8
View File
@@ -75,3 +75,11 @@
content: "comment in private pository"
created_unix: 946684811
updated_unix: 946684811
-
id: 9
type: 22 # review
poster_id: 2
issue_id: 2 # in repo_id 1
review_id: 20
created_unix: 946684810
+9
View File
@@ -170,3 +170,12 @@
content: "review request for user15"
updated_unix: 946684835
created_unix: 946684835
-
id: 20
type: 22
reviewer_id: 1
issue_id: 2
content: "Review Comment"
updated_unix: 946684810
created_unix: 946684810
+25 -6
View File
@@ -292,6 +292,7 @@ func RenameBranch(ctx context.Context, repo *repo_model.Repository, from, to str
sess := db.GetEngine(ctx)
// check whether from branch exist
var branch Branch
exist, err := db.GetEngine(ctx).Where("repo_id=? AND name=?", repo.ID, from).Get(&branch)
if err != nil {
@@ -303,6 +304,24 @@ func RenameBranch(ctx context.Context, repo *repo_model.Repository, from, to str
}
}
// check whether to branch exist or is_deleted
var dstBranch Branch
exist, err = db.GetEngine(ctx).Where("repo_id=? AND name=?", repo.ID, to).Get(&dstBranch)
if err != nil {
return err
}
if exist {
if !dstBranch.IsDeleted {
return ErrBranchAlreadyExists{
BranchName: to,
}
}
if _, err := db.GetEngine(ctx).ID(dstBranch.ID).NoAutoCondition().Delete(&dstBranch); err != nil {
return err
}
}
// 1. update branch in database
if n, err := sess.Where("repo_id=? AND name=?", repo.ID, from).Update(&Branch{
Name: to,
@@ -357,12 +376,7 @@ func RenameBranch(ctx context.Context, repo *repo_model.Repository, from, to str
return err
}
// 5. do git action
if err = gitAction(ctx, isDefault); err != nil {
return err
}
// 6. insert renamed branch record
// 5. insert renamed branch record
renamedBranch := &RenamedBranch{
RepoID: repo.ID,
From: from,
@@ -373,6 +387,11 @@ func RenameBranch(ctx context.Context, repo *repo_model.Repository, from, to str
return err
}
// 6. do git action
if err = gitAction(ctx, isDefault); err != nil {
return err
}
return committer.Commit()
}
+73 -47
View File
@@ -25,6 +25,7 @@ import (
"code.gitea.io/gitea/modules/translation"
"xorm.io/builder"
"xorm.io/xorm"
)
// CommitStatus holds a single Status of a single Commit
@@ -281,44 +282,48 @@ type CommitStatusIndex struct {
// GetLatestCommitStatus returns all statuses with a unique context for a given commit.
func GetLatestCommitStatus(ctx context.Context, repoID int64, sha string, listOptions db.ListOptions) ([]*CommitStatus, int64, error) {
ids := make([]int64, 0, 10)
sess := db.GetEngine(ctx).Table(&CommitStatus{}).
Where("repo_id = ?", repoID).And("sha = ?", sha).
Select("max( id ) as id").
GroupBy("context_hash").OrderBy("max( id ) desc")
getBase := func() *xorm.Session {
return db.GetEngine(ctx).Table(&CommitStatus{}).
Where("repo_id = ?", repoID).And("sha = ?", sha)
}
indices := make([]int64, 0, 10)
sess := getBase().Select("max( `index` ) as `index`").
GroupBy("context_hash").OrderBy("max( `index` ) desc")
if !listOptions.IsListAll() {
sess = db.SetSessionPagination(sess, &listOptions)
}
count, err := sess.FindAndCount(&ids)
count, err := sess.FindAndCount(&indices)
if err != nil {
return nil, count, err
}
statuses := make([]*CommitStatus, 0, len(ids))
if len(ids) == 0 {
statuses := make([]*CommitStatus, 0, len(indices))
if len(indices) == 0 {
return statuses, count, nil
}
return statuses, count, db.GetEngine(ctx).In("id", ids).Find(&statuses)
return statuses, count, getBase().And(builder.In("`index`", indices)).Find(&statuses)
}
// GetLatestCommitStatusForPairs returns all statuses with a unique context for a given list of repo-sha pairs
func GetLatestCommitStatusForPairs(ctx context.Context, repoIDsToLatestCommitSHAs map[int64]string, listOptions db.ListOptions) (map[int64][]*CommitStatus, error) {
type result struct {
ID int64
Index int64
RepoID int64
}
results := make([]result, 0, len(repoIDsToLatestCommitSHAs))
sess := db.GetEngine(ctx).Table(&CommitStatus{})
getBase := func() *xorm.Session {
return db.GetEngine(ctx).Table(&CommitStatus{})
}
// Create a disjunction of conditions for each repoID and SHA pair
conds := make([]builder.Cond, 0, len(repoIDsToLatestCommitSHAs))
for repoID, sha := range repoIDsToLatestCommitSHAs {
conds = append(conds, builder.Eq{"repo_id": repoID, "sha": sha})
}
sess = sess.Where(builder.Or(conds...)).
Select("max( id ) as id, repo_id").
GroupBy("context_hash, repo_id").OrderBy("max( id ) desc")
sess := getBase().Where(builder.Or(conds...)).
Select("max( `index` ) as `index`, repo_id").
GroupBy("context_hash, repo_id").OrderBy("max( `index` ) desc")
sess = db.SetSessionPagination(sess, &listOptions)
@@ -327,15 +332,21 @@ func GetLatestCommitStatusForPairs(ctx context.Context, repoIDsToLatestCommitSHA
return nil, err
}
ids := make([]int64, 0, len(results))
repoStatuses := make(map[int64][]*CommitStatus)
for _, result := range results {
ids = append(ids, result.ID)
}
statuses := make([]*CommitStatus, 0, len(ids))
if len(ids) > 0 {
err = db.GetEngine(ctx).In("id", ids).Find(&statuses)
if len(results) > 0 {
statuses := make([]*CommitStatus, 0, len(results))
conds = make([]builder.Cond, 0, len(results))
for _, result := range results {
cond := builder.Eq{
"`index`": result.Index,
"repo_id": result.RepoID,
"sha": repoIDsToLatestCommitSHAs[result.RepoID],
}
conds = append(conds, cond)
}
err = getBase().Where(builder.Or(conds...)).Find(&statuses)
if err != nil {
return nil, err
}
@@ -352,42 +363,43 @@ func GetLatestCommitStatusForPairs(ctx context.Context, repoIDsToLatestCommitSHA
// GetLatestCommitStatusForRepoCommitIDs returns all statuses with a unique context for a given list of repo-sha pairs
func GetLatestCommitStatusForRepoCommitIDs(ctx context.Context, repoID int64, commitIDs []string) (map[string][]*CommitStatus, error) {
type result struct {
ID int64
Sha string
Index int64
SHA string
}
getBase := func() *xorm.Session {
return db.GetEngine(ctx).Table(&CommitStatus{}).Where("repo_id = ?", repoID)
}
results := make([]result, 0, len(commitIDs))
sess := db.GetEngine(ctx).Table(&CommitStatus{})
// Create a disjunction of conditions for each repoID and SHA pair
conds := make([]builder.Cond, 0, len(commitIDs))
for _, sha := range commitIDs {
conds = append(conds, builder.Eq{"sha": sha})
}
sess = sess.Where(builder.Eq{"repo_id": repoID}.And(builder.Or(conds...))).
Select("max( id ) as id, sha").
GroupBy("context_hash, sha").OrderBy("max( id ) desc")
sess := getBase().And(builder.Or(conds...)).
Select("max( `index` ) as `index`, sha").
GroupBy("context_hash, sha").OrderBy("max( `index` ) desc")
err := sess.Find(&results)
if err != nil {
return nil, err
}
ids := make([]int64, 0, len(results))
repoStatuses := make(map[string][]*CommitStatus)
for _, result := range results {
ids = append(ids, result.ID)
}
statuses := make([]*CommitStatus, 0, len(ids))
if len(ids) > 0 {
err = db.GetEngine(ctx).In("id", ids).Find(&statuses)
if len(results) > 0 {
statuses := make([]*CommitStatus, 0, len(results))
conds = make([]builder.Cond, 0, len(results))
for _, result := range results {
conds = append(conds, builder.Eq{"`index`": result.Index, "sha": result.SHA})
}
err = getBase().And(builder.Or(conds...)).Find(&statuses)
if err != nil {
return nil, err
}
// Group the statuses by repo ID
// Group the statuses by commit
for _, status := range statuses {
repoStatuses[status.SHA] = append(repoStatuses[status.SHA], status)
}
@@ -398,22 +410,36 @@ func GetLatestCommitStatusForRepoCommitIDs(ctx context.Context, repoID int64, co
// FindRepoRecentCommitStatusContexts returns repository's recent commit status contexts
func FindRepoRecentCommitStatusContexts(ctx context.Context, repoID int64, before time.Duration) ([]string, error) {
type result struct {
Index int64
SHA string
}
getBase := func() *xorm.Session {
return db.GetEngine(ctx).Table(&CommitStatus{}).Where("repo_id = ?", repoID)
}
start := timeutil.TimeStampNow().AddDuration(-before)
ids := make([]int64, 0, 10)
if err := db.GetEngine(ctx).Table("commit_status").
Where("repo_id = ?", repoID).
And("updated_unix >= ?", start).
Select("max( id ) as id").
GroupBy("context_hash").OrderBy("max( id ) desc").
Find(&ids); err != nil {
results := make([]result, 0, 10)
sess := getBase().And("updated_unix >= ?", start).
Select("max( `index` ) as `index`, sha").
GroupBy("context_hash, sha").OrderBy("max( `index` ) desc")
err := sess.Find(&results)
if err != nil {
return nil, err
}
contexts := make([]string, 0, len(ids))
if len(ids) == 0 {
contexts := make([]string, 0, len(results))
if len(results) == 0 {
return contexts, nil
}
return contexts, db.GetEngine(ctx).Select("context").Table("commit_status").In("id", ids).Find(&contexts)
conds := make([]builder.Cond, 0, len(results))
for _, result := range results {
conds = append(conds, builder.Eq{"`index`": result.Index, "sha": result.SHA})
}
return contexts, getBase().And(builder.Or(conds...)).Select("context").Find(&contexts)
}
// NewCommitStatusOptions holds options for creating a CommitStatus
+4
View File
@@ -74,6 +74,10 @@ func findCodeComments(ctx context.Context, opts FindCommentsOptions, issue *Issu
return nil, err
}
if err := comments.LoadAttachments(ctx); err != nil {
return nil, err
}
// Find all reviews by ReviewID
reviews := make(map[int64]*Review)
ids := make([]int64, 0, len(comments))
-14
View File
@@ -200,20 +200,6 @@ func (issue *Issue) IsTimetrackerEnabled(ctx context.Context) bool {
return issue.Repo.IsTimetrackerEnabled(ctx)
}
// GetPullRequest returns the issue pull request
func (issue *Issue) GetPullRequest() (pr *PullRequest, err error) {
if !issue.IsPull {
return nil, fmt.Errorf("Issue is not a pull request")
}
pr, err = GetPullRequestByIssueID(db.DefaultContext, issue.ID)
if err != nil {
return nil, err
}
pr.Issue = issue
return pr, err
}
// LoadPoster loads poster
func (issue *Issue) LoadPoster(ctx context.Context) (err error) {
if issue.Poster == nil && issue.PosterID != 0 {
+3
View File
@@ -370,6 +370,9 @@ func (issues IssueList) LoadPullRequests(ctx context.Context) error {
for _, issue := range issues {
issue.PullRequest = pullRequestMaps[issue.ID]
if issue.PullRequest != nil {
issue.PullRequest.Issue = issue
}
}
return nil
}
+5 -17
View File
@@ -21,7 +21,7 @@ import (
// IssuesOptions represents options of an issue.
type IssuesOptions struct { //nolint
db.Paginator
Paginator *db.ListOptions
RepoIDs []int64 // overwrites RepoCond if the length is not 0
RepoCond builder.Cond
AssigneeID int64
@@ -103,23 +103,11 @@ func applyLimit(sess *xorm.Session, opts *IssuesOptions) *xorm.Session {
return sess
}
// Warning: Do not use GetSkipTake() for *db.ListOptions
// Its implementation could reset the page size with setting.API.MaxResponseItems
if listOptions, ok := opts.Paginator.(*db.ListOptions); ok {
if listOptions.Page >= 0 && listOptions.PageSize > 0 {
var start int
if listOptions.Page == 0 {
start = 0
} else {
start = (listOptions.Page - 1) * listOptions.PageSize
}
sess.Limit(listOptions.PageSize, start)
}
return sess
start := 0
if opts.Paginator.Page > 1 {
start = (opts.Paginator.Page - 1) * opts.Paginator.PageSize
}
start, limit := opts.Paginator.GetSkipTake()
sess.Limit(limit, start)
sess.Limit(opts.Paginator.PageSize, start)
return sess
}
+5 -1
View File
@@ -69,13 +69,17 @@ func CountIssuesByRepo(ctx context.Context, opts *IssuesOptions) (map[int64]int6
}
// CountIssues number return of issues by given conditions.
func CountIssues(ctx context.Context, opts *IssuesOptions) (int64, error) {
func CountIssues(ctx context.Context, opts *IssuesOptions, otherConds ...builder.Cond) (int64, error) {
sess := db.GetEngine(ctx).
Select("COUNT(issue.id) AS count").
Table("issue").
Join("INNER", "repository", "`issue`.repo_id = `repository`.id")
applyConditions(sess, opts)
for _, cond := range otherConds {
sess.And(cond)
}
return sess.Count()
}
+4 -80
View File
@@ -706,8 +706,8 @@ func (pr *PullRequest) UpdateColsIfNotMerged(ctx context.Context, cols ...string
// IsWorkInProgress determine if the Pull Request is a Work In Progress by its title
// Issue must be set before this method can be called.
func (pr *PullRequest) IsWorkInProgress() bool {
if err := pr.LoadIssue(db.DefaultContext); err != nil {
func (pr *PullRequest) IsWorkInProgress(ctx context.Context) bool {
if err := pr.LoadIssue(ctx); err != nil {
log.Error("LoadIssue: %v", err)
return false
}
@@ -810,14 +810,14 @@ func UpdateAllowEdits(ctx context.Context, pr *PullRequest) error {
}
// Mergeable returns if the pullrequest is mergeable.
func (pr *PullRequest) Mergeable() bool {
func (pr *PullRequest) Mergeable(ctx context.Context) bool {
// If a pull request isn't mergable if it's:
// - Being conflict checked.
// - Has a conflict.
// - Received a error while being conflict checked.
// - Is a work-in-progress pull request.
return pr.Status != PullRequestStatusChecking && pr.Status != PullRequestStatusConflict &&
pr.Status != PullRequestStatusError && !pr.IsWorkInProgress()
pr.Status != PullRequestStatusError && !pr.IsWorkInProgress(ctx)
}
// HasEnoughApprovals returns true if pr has enough granted approvals.
@@ -887,82 +887,6 @@ func MergeBlockedByOutdatedBranch(protectBranch *git_model.ProtectedBranch, pr *
return protectBranch.BlockOnOutdatedBranch && pr.CommitsBehind > 0
}
func PullRequestCodeOwnersReview(ctx context.Context, pull *Issue, pr *PullRequest) error {
files := []string{"CODEOWNERS", "docs/CODEOWNERS", ".gitea/CODEOWNERS"}
if pr.IsWorkInProgress() {
return nil
}
if err := pr.LoadBaseRepo(ctx); err != nil {
return err
}
repo, err := git.OpenRepository(ctx, pr.BaseRepo.RepoPath())
if err != nil {
return err
}
defer repo.Close()
branch, err := repo.GetDefaultBranch()
if err != nil {
return err
}
commit, err := repo.GetBranchCommit(branch)
if err != nil {
return err
}
var data string
for _, file := range files {
if blob, err := commit.GetBlobByPath(file); err == nil {
data, err = blob.GetBlobContent(setting.UI.MaxDisplayFileSize)
if err == nil {
break
}
}
}
rules, _ := GetCodeOwnersFromContent(ctx, data)
changedFiles, err := repo.GetFilesChangedBetween(git.BranchPrefix+pr.BaseBranch, pr.GetGitRefName())
if err != nil {
return err
}
uniqUsers := make(map[int64]*user_model.User)
uniqTeams := make(map[string]*org_model.Team)
for _, rule := range rules {
for _, f := range changedFiles {
if (rule.Rule.MatchString(f) && !rule.Negative) || (!rule.Rule.MatchString(f) && rule.Negative) {
for _, u := range rule.Users {
uniqUsers[u.ID] = u
}
for _, t := range rule.Teams {
uniqTeams[fmt.Sprintf("%d/%d", t.OrgID, t.ID)] = t
}
}
}
}
for _, u := range uniqUsers {
if u.ID != pull.Poster.ID {
if _, err := AddReviewRequest(ctx, pull, u, pull.Poster); err != nil {
log.Warn("Failed add assignee user: %s to PR review: %s#%d, error: %s", u.Name, pr.BaseRepo.Name, pr.ID, err)
return err
}
}
}
for _, t := range uniqTeams {
if _, err := AddTeamReviewRequest(ctx, pull, t, pull.Poster); err != nil {
log.Warn("Failed add assignee team: %s to PR review: %s#%d, error: %s", t.Name, pr.BaseRepo.Name, pr.ID, err)
return err
}
}
return nil
}
// GetCodeOwnersFromContent returns the code owners configuration
// Return empty slice if files missing
// Return warning messages on parsing errors
+9
View File
@@ -212,3 +212,12 @@ func HasMergedPullRequestInRepo(ctx context.Context, repoID, posterID int64) (bo
Limit(1).
Get(new(Issue))
}
// GetPullRequestByIssueIDs returns all pull requests by issue ids
func GetPullRequestByIssueIDs(ctx context.Context, issueIDs []int64) (PullRequestList, error) {
prs := make([]*PullRequest, 0, len(issueIDs))
return prs, db.GetEngine(ctx).
Where("issue_id > 0").
In("issue_id", issueIDs).
Find(&prs)
}
+3 -3
View File
@@ -260,13 +260,13 @@ func TestPullRequest_IsWorkInProgress(t *testing.T) {
pr := unittest.AssertExistsAndLoadBean(t, &issues_model.PullRequest{ID: 2})
pr.LoadIssue(db.DefaultContext)
assert.False(t, pr.IsWorkInProgress())
assert.False(t, pr.IsWorkInProgress(db.DefaultContext))
pr.Issue.Title = "WIP: " + pr.Issue.Title
assert.True(t, pr.IsWorkInProgress())
assert.True(t, pr.IsWorkInProgress(db.DefaultContext))
pr.Issue.Title = "[wip]: " + pr.Issue.Title
assert.True(t, pr.IsWorkInProgress())
assert.True(t, pr.IsWorkInProgress(db.DefaultContext))
}
func TestPullRequest_GetWorkInProgressPrefixWorkInProgress(t *testing.T) {
+5 -6
View File
@@ -240,11 +240,11 @@ type CreateReviewOptions struct {
// IsOfficialReviewer check if at least one of the provided reviewers can make official reviews in issue (counts towards required approvals)
func IsOfficialReviewer(ctx context.Context, issue *Issue, reviewer *user_model.User) (bool, error) {
pr, err := GetPullRequestByIssueID(ctx, issue.ID)
if err != nil {
if err := issue.LoadPullRequest(ctx); err != nil {
return false, err
}
pr := issue.PullRequest
rule, err := git_model.GetFirstMatchProtectedBranchRule(ctx, pr.BaseRepoID, pr.BaseBranch)
if err != nil {
return false, err
@@ -272,11 +272,10 @@ func IsOfficialReviewer(ctx context.Context, issue *Issue, reviewer *user_model.
// IsOfficialReviewerTeam check if reviewer in this team can make official reviews in issue (counts towards required approvals)
func IsOfficialReviewerTeam(ctx context.Context, issue *Issue, team *organization.Team) (bool, error) {
pr, err := GetPullRequestByIssueID(ctx, issue.ID)
if err != nil {
if err := issue.LoadPullRequest(ctx); err != nil {
return false, err
}
pb, err := git_model.GetFirstMatchProtectedBranchRule(ctx, pr.BaseRepoID, pr.BaseBranch)
pb, err := git_model.GetFirstMatchProtectedBranchRule(ctx, issue.PullRequest.BaseRepoID, issue.PullRequest.BaseBranch)
if err != nil {
return false, err
}
@@ -622,7 +621,7 @@ func AddReviewRequest(ctx context.Context, issue *Issue, reviewer, doer *user_mo
// skip it when reviewer hase been request to review
if review != nil && review.Type == ReviewTypeRequest {
return nil, nil
return nil, committer.Commit() // still commit the transaction, or committer.Close() will rollback it, even if it's a reused transaction.
}
// if the reviewer is an official reviewer,
+6 -2
View File
@@ -9,6 +9,7 @@ import (
"fmt"
"strings"
actions_model "code.gitea.io/gitea/models/actions"
"code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/models/perm"
repo_model "code.gitea.io/gitea/models/repo"
@@ -319,8 +320,9 @@ func CreateOrganization(org *Organization, owner *user_model.User) (err error) {
// Add initial creator to organization and owner team.
if err = db.Insert(ctx, &OrgUser{
UID: owner.ID,
OrgID: org.ID,
UID: owner.ID,
OrgID: org.ID,
IsPublic: setting.Service.DefaultOrgMemberVisible,
}); err != nil {
return fmt.Errorf("insert org-user relation: %w", err)
}
@@ -400,6 +402,8 @@ func DeleteOrganization(ctx context.Context, org *Organization) error {
&TeamUnit{OrgID: org.ID},
&TeamInvite{OrgID: org.ID},
&secret_model.Secret{OwnerID: org.ID},
&actions_model.ActionRunner{OwnerID: org.ID},
&actions_model.ActionRunnerToken{OwnerID: org.ID},
); err != nil {
return fmt.Errorf("DeleteBeans: %w", err)
}
+39
View File
@@ -9,7 +9,10 @@ import (
"fmt"
"strings"
actions_model "code.gitea.io/gitea/models/actions"
"code.gitea.io/gitea/models/db"
actions_module "code.gitea.io/gitea/modules/actions"
"code.gitea.io/gitea/modules/log"
secret_module "code.gitea.io/gitea/modules/secret"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/timeutil"
@@ -128,3 +131,39 @@ func UpdateSecret(ctx context.Context, secretID int64, data string) error {
}
return err
}
func GetSecretsOfTask(ctx context.Context, task *actions_model.ActionTask) (map[string]string, error) {
secrets := map[string]string{}
secrets["GITHUB_TOKEN"] = task.Token
secrets["GITEA_TOKEN"] = task.Token
if task.Job.Run.IsForkPullRequest && task.Job.Run.TriggerEvent != actions_module.GithubEventPullRequestTarget {
// ignore secrets for fork pull request, except GITHUB_TOKEN and GITEA_TOKEN which are automatically generated.
// for the tasks triggered by pull_request_target event, they could access the secrets because they will run in the context of the base branch
// see the documentation: https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#pull_request_target
return secrets, nil
}
ownerSecrets, err := FindSecrets(ctx, FindSecretsOptions{OwnerID: task.Job.Run.Repo.OwnerID})
if err != nil {
log.Error("find secrets of owner %v: %v", task.Job.Run.Repo.OwnerID, err)
return nil, err
}
repoSecrets, err := FindSecrets(ctx, FindSecretsOptions{RepoID: task.Job.Run.RepoID})
if err != nil {
log.Error("find secrets of repo %v: %v", task.Job.Run.RepoID, err)
return nil, err
}
for _, secret := range append(ownerSecrets, repoSecrets...) {
v, err := secret_module.DecryptSecret(setting.SecretKey, secret.Data)
if err != nil {
log.Error("decrypt secret %v %q: %v", secret.ID, secret.Name, err)
return nil, err
}
secrets[secret.Name] = v
}
return secrets, nil
}
+2 -2
View File
@@ -491,7 +491,7 @@ func SearchEmails(ctx context.Context, opts *SearchEmailOptions) ([]*SearchEmail
cond = cond.And(builder.Eq{"email_address.is_activated": false})
}
count, err := db.GetEngine(ctx).Join("INNER", "`user`", "`user`.ID = email_address.uid").
count, err := db.GetEngine(ctx).Join("INNER", "`user`", "`user`.id = email_address.uid").
Where(cond).Count(new(EmailAddress))
if err != nil {
return nil, 0, fmt.Errorf("Count: %w", err)
@@ -507,7 +507,7 @@ func SearchEmails(ctx context.Context, opts *SearchEmailOptions) ([]*SearchEmail
emails := make([]*SearchEmailResult, 0, opts.PageSize)
err = db.GetEngine(ctx).Table("email_address").
Select("email_address.*, `user`.name, `user`.full_name").
Join("INNER", "`user`", "`user`.ID = email_address.uid").
Join("INNER", "`user`", "`user`.id = email_address.uid").
Where(cond).
OrderBy(orderby).
Limit(opts.PageSize, (opts.Page-1)*opts.PageSize).
+12 -2
View File
@@ -41,6 +41,12 @@ func FullSteps(task *actions_model.ActionTask) []*actions_model.ActionTaskStep {
}
logIndex += preStep.LogLength
// lastHasRunStep is the last step that has run.
// For example,
// 1. preStep(Success) -> step1(Success) -> step2(Running) -> step3(Waiting) -> postStep(Waiting): lastHasRunStep is step1.
// 2. preStep(Success) -> step1(Success) -> step2(Success) -> step3(Success) -> postStep(Success): lastHasRunStep is step3.
// 3. preStep(Success) -> step1(Success) -> step2(Failure) -> step3 -> postStep(Waiting): lastHasRunStep is step2.
// So its Stopped is the Started of postStep when there are no more steps to run.
var lastHasRunStep *actions_model.ActionTaskStep
for _, step := range task.Steps {
if step.Status.HasRun() {
@@ -56,11 +62,15 @@ func FullSteps(task *actions_model.ActionTask) []*actions_model.ActionTaskStep {
Name: postStepName,
Status: actions_model.StatusWaiting,
}
if task.Status.IsDone() {
// If the lastHasRunStep is the last step, or it has failed, postStep has started.
if lastHasRunStep.Status.IsFailure() || lastHasRunStep == task.Steps[len(task.Steps)-1] {
postStep.LogIndex = logIndex
postStep.LogLength = task.LogLength - postStep.LogIndex
postStep.Status = task.Status
postStep.Started = lastHasRunStep.Stopped
postStep.Status = actions_model.StatusRunning
}
if task.Status.IsDone() {
postStep.Status = task.Status
postStep.Stopped = task.Stopped
}
ret := make([]*actions_model.ActionTaskStep, 0, len(task.Steps)+2)
+34
View File
@@ -103,6 +103,40 @@ func TestFullSteps(t *testing.T) {
{Name: postStepName, Status: actions_model.StatusSuccess, LogIndex: 100, LogLength: 0, Started: 10100, Stopped: 10100},
},
},
{
name: "all steps finished but task is running",
task: &actions_model.ActionTask{
Steps: []*actions_model.ActionTaskStep{
{Status: actions_model.StatusSuccess, LogIndex: 10, LogLength: 80, Started: 10010, Stopped: 10090},
},
Status: actions_model.StatusRunning,
Started: 10000,
Stopped: 0,
LogLength: 100,
},
want: []*actions_model.ActionTaskStep{
{Name: preStepName, Status: actions_model.StatusSuccess, LogIndex: 0, LogLength: 10, Started: 10000, Stopped: 10010},
{Status: actions_model.StatusSuccess, LogIndex: 10, LogLength: 80, Started: 10010, Stopped: 10090},
{Name: postStepName, Status: actions_model.StatusRunning, LogIndex: 90, LogLength: 10, Started: 10090, Stopped: 0},
},
},
{
name: "skipped task",
task: &actions_model.ActionTask{
Steps: []*actions_model.ActionTaskStep{
{Status: actions_model.StatusSkipped, LogIndex: 0, LogLength: 0, Started: 0, Stopped: 0},
},
Status: actions_model.StatusSkipped,
Started: 0,
Stopped: 0,
LogLength: 0,
},
want: []*actions_model.ActionTaskStep{
{Name: preStepName, Status: actions_model.StatusSkipped, LogIndex: 0, LogLength: 0, Started: 0, Stopped: 0},
{Status: actions_model.StatusSkipped, LogIndex: 0, LogLength: 0, Started: 0, Stopped: 0},
{Name: postStepName, Status: actions_model.StatusSkipped, LogIndex: 0, LogLength: 0, Started: 0, Stopped: 0},
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
+6
View File
@@ -216,6 +216,12 @@ func fixBrokenRepoUnit16961(repoUnit *repo_model.RepoUnit, bs []byte) (fixed boo
return false, nil
}
var cfg any
err = json.UnmarshalHandleDoubleEncode(bs, &cfg)
if err == nil {
return false, nil
}
switch repoUnit.Type {
case unit.TypeCode, unit.TypeReleases, unit.TypeWiki, unit.TypeProjects:
cfg := &repo_model.UnitConfig{}
+1 -1
View File
@@ -162,7 +162,7 @@ func checkStorage(opts *checkStorageOptions) func(ctx context.Context, logger lo
if opts.RepoArchives || opts.All {
if err := commonCheckStorage(ctx, logger, autofix,
&commonStorageCheckOptions{
storer: storage.RepoAvatars,
storer: storage.RepoArchives,
isOrphaned: func(path string, obj storage.Object, stat fs.FileInfo) (bool, error) {
exists, err := repo.ExistsRepoArchiverWithStoragePath(ctx, path)
if err == nil || errors.Is(err, util.ErrInvalidArgument) {
+6
View File
@@ -47,6 +47,12 @@ func convertPGPSignature(c *object.Commit) *CommitGPGSignature {
return nil
}
if c.Encoding != "" && c.Encoding != "UTF-8" {
if _, err = fmt.Fprintf(&w, "\nencoding %s\n", c.Encoding); err != nil {
return nil
}
}
if _, err = fmt.Fprintf(&w, "\n\n%s", c.Message); err != nil {
return nil
}
+2
View File
@@ -84,6 +84,8 @@ readLoop:
commit.Committer = &Signature{}
commit.Committer.Decode(data)
_, _ = payloadSB.Write(line)
case "encoding":
_, _ = payloadSB.Write(line)
case "gpgsig":
_, _ = signatureSB.Write(data)
_ = signatureSB.WriteByte('\n')
+67
View File
@@ -125,6 +125,73 @@ empty commit`, commitFromReader.Signature.Payload)
assert.EqualValues(t, commitFromReader, commitFromReader2)
}
func TestCommitWithEncodingFromReader(t *testing.T) {
commitString := `feaf4ba6bc635fec442f46ddd4512416ec43c2c2 commit 1074
tree ca3fad42080dd1a6d291b75acdfc46e5b9b307e5
parent 47b24e7ab977ed31c5a39989d570847d6d0052af
author KN4CK3R <admin@oldschoolhack.me> 1711702962 +0100
committer KN4CK3R <admin@oldschoolhack.me> 1711702962 +0100
encoding ISO-8859-1
gpgsig -----BEGIN PGP SIGNATURE-----
iQGzBAABCgAdFiEE9HRrbqvYxPT8PXbefPSEkrowAa8FAmYGg7IACgkQfPSEkrow
Aa9olwv+P0HhtCM6CRvlUmPaqswRsDPNR4i66xyXGiSxdI9V5oJL7HLiQIM7KrFR
gizKa2COiGtugv8fE+TKqXKaJx6uJUJEjaBd8E9Af9PrAzjWj+A84lU6/PgPS8hq
zOfZraLOEWRH4tZcS+u2yFLu3ez2Wqh1xW5LNy7xqEedMXEFD1HwSJ0+pjacNkzr
frp6Asyt7xRI6YmgFJZJoRsS3Ktr6rtKeRL2IErSQQyorOqj6gKrglhrhfG/114j
FKB1v4or0WZ1DE8iP2SJZ3n+/K1IuWAINh7MVdb7PndfBPEa+IL+ucNk5uzEE8Jd
G8smGxXUeFEt2cP1dj2W8EgAxuA9sTnH9dqI5aRqy5ifDjuya7Emm8sdOUvtGdmn
SONRzusmu5n3DgV956REL7x62h7JuqmBz/12HZkr0z0zgXkcZ04q08pSJATX5N1F
yN+tWxTsWg+zhDk96d5Esdo9JMjcFvPv0eioo30GAERaz1hoD7zCMT4jgUFTQwgz
jw4YcO5u
=r3UU
-----END PGP SIGNATURE-----
ISO-8859-1`
sha := SHA1{0xfe, 0xaf, 0x4b, 0xa6, 0xbc, 0x63, 0x5f, 0xec, 0x44, 0x2f, 0x46, 0xdd, 0xd4, 0x51, 0x24, 0x16, 0xec, 0x43, 0xc2, 0xc2}
gitRepo, err := openRepositoryWithDefaultContext(filepath.Join(testReposDir, "repo1_bare"))
assert.NoError(t, err)
assert.NotNil(t, gitRepo)
defer gitRepo.Close()
commitFromReader, err := CommitFromReader(gitRepo, sha, strings.NewReader(commitString))
assert.NoError(t, err)
if !assert.NotNil(t, commitFromReader) {
return
}
assert.EqualValues(t, sha, commitFromReader.ID)
assert.EqualValues(t, `-----BEGIN PGP SIGNATURE-----
iQGzBAABCgAdFiEE9HRrbqvYxPT8PXbefPSEkrowAa8FAmYGg7IACgkQfPSEkrow
Aa9olwv+P0HhtCM6CRvlUmPaqswRsDPNR4i66xyXGiSxdI9V5oJL7HLiQIM7KrFR
gizKa2COiGtugv8fE+TKqXKaJx6uJUJEjaBd8E9Af9PrAzjWj+A84lU6/PgPS8hq
zOfZraLOEWRH4tZcS+u2yFLu3ez2Wqh1xW5LNy7xqEedMXEFD1HwSJ0+pjacNkzr
frp6Asyt7xRI6YmgFJZJoRsS3Ktr6rtKeRL2IErSQQyorOqj6gKrglhrhfG/114j
FKB1v4or0WZ1DE8iP2SJZ3n+/K1IuWAINh7MVdb7PndfBPEa+IL+ucNk5uzEE8Jd
G8smGxXUeFEt2cP1dj2W8EgAxuA9sTnH9dqI5aRqy5ifDjuya7Emm8sdOUvtGdmn
SONRzusmu5n3DgV956REL7x62h7JuqmBz/12HZkr0z0zgXkcZ04q08pSJATX5N1F
yN+tWxTsWg+zhDk96d5Esdo9JMjcFvPv0eioo30GAERaz1hoD7zCMT4jgUFTQwgz
jw4YcO5u
=r3UU
-----END PGP SIGNATURE-----
`, commitFromReader.Signature.Signature)
assert.EqualValues(t, `tree ca3fad42080dd1a6d291b75acdfc46e5b9b307e5
parent 47b24e7ab977ed31c5a39989d570847d6d0052af
author KN4CK3R <admin@oldschoolhack.me> 1711702962 +0100
committer KN4CK3R <admin@oldschoolhack.me> 1711702962 +0100
encoding ISO-8859-1
ISO-8859-1`, commitFromReader.Signature.Payload)
assert.EqualValues(t, "KN4CK3R <admin@oldschoolhack.me>", commitFromReader.Author.String())
commitFromReader2, err := CommitFromReader(gitRepo, sha, strings.NewReader(commitString+"\n\n"))
assert.NoError(t, err)
commitFromReader.CommitMessage += "\n\n"
commitFromReader.Signature.Payload += "\n\n"
assert.EqualValues(t, commitFromReader, commitFromReader2)
}
func TestHasPreviousCommit(t *testing.T) {
bareRepo1Path := filepath.Join(testReposDir, "repo1_bare")
+1 -1
View File
@@ -248,7 +248,7 @@ type DivergeObject struct {
// GetDivergingCommits returns the number of commits a targetBranch is ahead or behind a baseBranch
func GetDivergingCommits(ctx context.Context, repoPath, baseBranch, targetBranch string) (do DivergeObject, err error) {
cmd := NewCommand(ctx, "rev-list", "--count", "--left-right").
AddDynamicArguments(baseBranch + "..." + targetBranch)
AddDynamicArguments(baseBranch + "..." + targetBranch).AddArguments("--")
stdout, _, err := cmd.RunStdString(&RunOpts{Dir: repoPath})
if err != nil {
return do, err
+7 -14
View File
@@ -10,7 +10,7 @@ import (
)
// ParsePaginator parses a db.Paginator into a skip and limit
func ParsePaginator(paginator db.Paginator, max ...int) (int, int) {
func ParsePaginator(paginator *db.ListOptions, max ...int) (int, int) {
// Use a very large number to indicate no limit
unlimited := math.MaxInt32
if len(max) > 0 {
@@ -19,22 +19,15 @@ func ParsePaginator(paginator db.Paginator, max ...int) (int, int) {
}
if paginator == nil || paginator.IsListAll() {
// It shouldn't happen. In actual usage scenarios, there should not be requests to search all.
// But if it does happen, respect it and return "unlimited".
// And it's also useful for testing.
return 0, unlimited
}
// Warning: Do not use GetSkipTake() for *db.ListOptions
// Its implementation could reset the page size with setting.API.MaxResponseItems
if listOptions, ok := paginator.(*db.ListOptions); ok {
if listOptions.Page >= 0 && listOptions.PageSize > 0 {
var start int
if listOptions.Page == 0 {
start = 0
} else {
start = (listOptions.Page - 1) * listOptions.PageSize
}
return start, listOptions.PageSize
}
return 0, unlimited
if paginator.PageSize == 0 {
// Do not return any results when searching, it's used to get the total count only.
return 0, 0
}
return paginator.GetSkipTake()
+11
View File
@@ -78,6 +78,17 @@ func (i *Indexer) Search(ctx context.Context, options *internal.SearchOptions) (
return nil, err
}
// If pagesize == 0, return total count only. It's a special case for search count.
if options.Paginator != nil && options.Paginator.PageSize == 0 {
total, err := issue_model.CountIssues(ctx, opt, cond)
if err != nil {
return nil, err
}
return &internal.SearchResult{
Total: total,
}, nil
}
ids, total, err := issue_model.IssueIDs(ctx, opt, cond)
if err != nil {
return nil, err
+1 -1
View File
@@ -309,7 +309,7 @@ func SearchIssues(ctx context.Context, opts *SearchOptions) ([]int64, int64, err
// CountIssues counts issues by options. It is a shortcut of SearchIssues(ctx, opts) but only returns the total count.
func CountIssues(ctx context.Context, opts *SearchOptions) (int64, error) {
opts = opts.Copy(func(options *SearchOptions) { opts.Paginator = &db_model.ListOptions{PageSize: 0} })
opts = opts.Copy(func(options *SearchOptions) { options.Paginator = &db_model.ListOptions{PageSize: 0} })
_, total, err := SearchIssues(ctx, opts)
return total, err
+1 -1
View File
@@ -104,7 +104,7 @@ type SearchOptions struct {
UpdatedAfterUnix *int64
UpdatedBeforeUnix *int64
db.Paginator
Paginator *db.ListOptions
SortBy SortBy // sort by field
}
@@ -77,6 +77,13 @@ func TestIndexer(t *testing.T, indexer internal.Indexer) {
assert.Equal(t, c.ExpectedIDs, ids)
assert.Equal(t, c.ExpectedTotal, result.Total)
}
// test counting
c.SearchOptions.Paginator = &db.ListOptions{PageSize: 0}
countResult, err := indexer.Search(context.Background(), c.SearchOptions)
require.NoError(t, err)
assert.Empty(t, countResult.Hits)
assert.Equal(t, result.Total, countResult.Total)
})
}
}
@@ -5,6 +5,7 @@ package meilisearch
import (
"context"
"fmt"
"strconv"
"strings"
@@ -210,7 +211,19 @@ func (b *Indexer) Search(ctx context.Context, options *internal.SearchOptions) (
skip, limit := indexer_internal.ParsePaginator(options.Paginator, maxTotalHits)
searchRes, err := b.inner.Client.Index(b.inner.VersionedIndexName()).Search(options.Keyword, &meilisearch.SearchRequest{
counting := limit == 0
if counting {
// If set limit to 0, it will be 20 by default, and -1 is not allowed.
// See https://www.meilisearch.com/docs/reference/api/search#limit
// So set limit to 1 to make the cost as low as possible, then clear the result before returning.
limit = 1
}
// to make it non fuzzy ("typo tolerance" in meilisearch terms), we have to quote the keyword(s)
// https://www.meilisearch.com/docs/reference/api/search#phrase-search
keyword := doubleQuoteKeyword(options.Keyword)
searchRes, err := b.inner.Client.Index(b.inner.VersionedIndexName()).Search(keyword, &meilisearch.SearchRequest{
Filter: query.Statement(),
Limit: int64(limit),
Offset: int64(skip),
@@ -221,6 +234,10 @@ func (b *Indexer) Search(ctx context.Context, options *internal.SearchOptions) (
return nil, err
}
if counting {
searchRes.Hits = nil
}
hits := make([]internal.Match, 0, len(searchRes.Hits))
for _, hit := range searchRes.Hits {
hits = append(hits, internal.Match{
@@ -241,3 +258,16 @@ func parseSortBy(sortBy internal.SortBy) string {
}
return field + ":asc"
}
func doubleQuoteKeyword(k string) string {
kp := strings.Split(k, " ")
parts := 0
for i := range kp {
part := strings.Trim(kp[i], "\"")
if part != "" {
kp[parts] = fmt.Sprintf(`"%s"`, part)
parts++
}
}
return strings.Join(kp[:parts], " ")
}
@@ -11,6 +11,8 @@ import (
"time"
"code.gitea.io/gitea/modules/indexer/issues/internal/tests"
"github.com/stretchr/testify/assert"
)
func TestMeilisearchIndexer(t *testing.T) {
@@ -48,3 +50,11 @@ func TestMeilisearchIndexer(t *testing.T) {
tests.TestIndexer(t, indexer)
}
func TestDoubleQuoteKeyword(t *testing.T) {
assert.EqualValues(t, "", doubleQuoteKeyword(""))
assert.EqualValues(t, `"a" "b" "c"`, doubleQuoteKeyword("a b c"))
assert.EqualValues(t, `"a" "d" "g"`, doubleQuoteKeyword("a d g"))
assert.EqualValues(t, `"a" "d" "g"`, doubleQuoteKeyword("a d g"))
assert.EqualValues(t, `"a" "d" "g"`, doubleQuoteKeyword(`a "" "d" """g`))
}
+2 -2
View File
@@ -44,7 +44,7 @@ func (c *FilesystemClient) Download(ctx context.Context, objects []Pointer, call
if err != nil {
return err
}
defer f.Close()
if err := callback(p, f, nil); err != nil {
return err
}
@@ -75,7 +75,7 @@ func (c *FilesystemClient) Upload(ctx context.Context, objects []Pointer, callba
if err != nil {
return err
}
defer f.Close()
_, err = io.Copy(f, content)
return err
+18 -2
View File
@@ -503,9 +503,17 @@ func TestMathBlock(t *testing.T) {
`\(a\) \(b\)`,
`<p><code class="language-math is-loading">a</code> <code class="language-math is-loading">b</code></p>` + nl,
},
{
`$a$.`,
`<p><code class="language-math is-loading">a</code>.</p>` + nl,
},
{
`.$a$`,
`<p>.$a$</p>` + nl,
},
{
`$a a$b b$`,
`<p><code class="language-math is-loading">a a$b b</code></p>` + nl,
`<p>$a a$b b$</p>` + nl,
},
{
`a a$b b`,
@@ -513,7 +521,15 @@ func TestMathBlock(t *testing.T) {
},
{
`a$b $a a$b b$`,
`<p>a$b <code class="language-math is-loading">a a$b b</code></p>` + nl,
`<p>a$b $a a$b b$</p>` + nl,
},
{
"a$x$",
`<p>a$x$</p>` + nl,
},
{
"$x$a",
`<p>$x$a</p>` + nl,
},
{
"$$a$$",
+13 -5
View File
@@ -41,9 +41,12 @@ func (parser *inlineParser) Trigger() []byte {
return parser.start[0:1]
}
func isPunctuation(b byte) bool {
return b == '.' || b == '!' || b == '?' || b == ',' || b == ';' || b == ':'
}
func isAlphanumeric(b byte) bool {
// Github only cares about 0-9A-Za-z
return (b >= '0' && b <= '9') || (b >= 'A' && b <= 'Z') || (b >= 'a' && b <= 'z')
return (b >= 'a' && b <= 'z') || (b >= 'A' && b <= 'Z') || (b >= '0' && b <= '9')
}
// Parse parses the current line and returns a result of parsing.
@@ -56,7 +59,7 @@ func (parser *inlineParser) Parse(parent ast.Node, block text.Reader, pc parser.
}
precedingCharacter := block.PrecendingCharacter()
if precedingCharacter < 256 && isAlphanumeric(byte(precedingCharacter)) {
if precedingCharacter < 256 && (isAlphanumeric(byte(precedingCharacter)) || isPunctuation(byte(precedingCharacter))) {
// need to exclude things like `a$` from being considered a start
return nil
}
@@ -75,14 +78,19 @@ func (parser *inlineParser) Parse(parent ast.Node, block text.Reader, pc parser.
ender += pos
// Now we want to check the character at the end of our parser section
// that is ender + len(parser.end)
// that is ender + len(parser.end) and check if char before ender is '\'
pos = ender + len(parser.end)
if len(line) <= pos {
break
}
if !isAlphanumeric(line[pos]) {
suceedingCharacter := line[pos]
if !isPunctuation(suceedingCharacter) && !(suceedingCharacter == ' ') {
return nil
}
if line[ender-1] != '\\' {
break
}
// move the pointer onwards
ender += len(parser.end)
}
+15 -10
View File
@@ -12,6 +12,7 @@ import (
"code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/util"
)
// Git environment variables
@@ -32,13 +33,13 @@ const (
)
// Bool checks for a key in the map and parses as a boolean
func (g GitPushOptions) Bool(key string, def bool) bool {
func (g GitPushOptions) Bool(key string) util.OptionalBool {
if val, ok := g[key]; ok {
if b, err := strconv.ParseBool(val); err == nil {
return b
return util.OptionalBoolOf(b)
}
}
return def
return util.OptionalBoolNone
}
// HookOptions represents the options for the Hook calls
@@ -87,13 +88,17 @@ type HookProcReceiveResult struct {
// HookProcReceiveRefResult represents an individual result from ProcReceive
type HookProcReceiveRefResult struct {
OldOID string
NewOID string
Ref string
OriginalRef git.RefName
IsForcePush bool
IsNotMatched bool
Err string
OldOID string
NewOID string
Ref string
OriginalRef git.RefName
IsForcePush bool
IsNotMatched bool
Err string
IsCreatePR bool
URL string
ShouldShowMessage bool
HeadBranch string
}
// HookPreReceive check whether the provided commits are allowed
+7
View File
@@ -6,6 +6,9 @@ package session
import (
"net/http"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/web/middleware"
"gitea.com/go-chi/session"
)
@@ -18,6 +21,10 @@ type Store interface {
// RegenerateSession regenerates the underlying session and returns the new store
func RegenerateSession(resp http.ResponseWriter, req *http.Request) (Store, error) {
// Ensure that a cookie with a trailing slash does not take precedence over
// the cookie written by the middleware.
middleware.DeleteLegacySiteCookie(resp, setting.SessionConfig.CookieName)
s, err := session.RegenerateSession(resp, req)
return s, err
}
+3
View File
@@ -13,6 +13,7 @@ import (
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/user"
"code.gitea.io/gitea/modules/util"
)
// settings
@@ -158,9 +159,11 @@ func loadCommonSettingsFrom(cfg ConfigProvider) error {
func loadRunModeFrom(rootCfg ConfigProvider) {
rootSec := rootCfg.Section("")
RunUser = rootSec.Key("RUN_USER").MustString(user.CurrentUsername())
// The following is a purposefully undocumented option. Please do not run Gitea as root. It will only cause future headaches.
// Please don't use root as a bandaid to "fix" something that is broken, instead the broken thing should instead be fixed properly.
unsafeAllowRunAsRoot := ConfigSectionKeyBool(rootSec, "I_AM_BEING_UNSAFE_RUNNING_AS_ROOT")
unsafeAllowRunAsRoot = unsafeAllowRunAsRoot || util.OptionalBoolParse(os.Getenv("GITEA_I_AM_BEING_UNSAFE_RUNNING_AS_ROOT")).IsTrue()
RunMode = os.Getenv("GITEA_RUN_MODE")
if RunMode == "" {
RunMode = rootSec.Key("RUN_MODE").MustString("prod")
+21 -17
View File
@@ -142,35 +142,39 @@ type remoteAddress struct {
Password string
}
func mirrorRemoteAddress(ctx context.Context, m *repo_model.Repository, remoteName string, ignoreOriginalURL bool) remoteAddress {
a := remoteAddress{}
remoteURL := m.OriginalURL
if ignoreOriginalURL || remoteURL == "" {
var err error
remoteURL, err = git.GetRemoteAddress(ctx, m.RepoPath(), remoteName)
if err != nil {
log.Error("GetRemoteURL %v", err)
return a
}
func mirrorRemoteAddress(ctx context.Context, m *repo_model.Repository, remoteName string) remoteAddress {
ret := remoteAddress{}
remoteURL, err := git.GetRemoteAddress(ctx, m.RepoPath(), remoteName)
if err != nil {
log.Error("GetRemoteURL %v", err)
return ret
}
u, err := giturl.Parse(remoteURL)
if err != nil {
log.Error("giturl.Parse %v", err)
return a
return ret
}
if u.Scheme != "ssh" && u.Scheme != "file" {
if u.User != nil {
a.Username = u.User.Username()
a.Password, _ = u.User.Password()
ret.Username = u.User.Username()
ret.Password, _ = u.User.Password()
}
u.User = nil
}
a.Address = u.String()
return a
// The URL stored in the git repo could contain authentication,
// erase it, or it will be shown in the UI.
u.User = nil
ret.Address = u.String()
// Why not use m.OriginalURL to set ret.Address?
// It should be OK to use it, since m.OriginalURL should be the same as the authentication-erased URL from the Git repository.
// However, the old code has already stored authentication in m.OriginalURL when updating mirror settings.
// That means we need to use "giturl.Parse" for m.OriginalURL again to ensure authentication is erased.
// Instead of doing this, why not directly use the authentication-erased URL from the Git repository?
// It should be the same as long as there are no bugs.
return ret
}
func FilenameIsImage(filename string) bool {
+9
View File
@@ -45,3 +45,12 @@ func SliceSortedEqual[T comparable](s1, s2 []T) bool {
func SliceRemoveAll[T comparable](slice []T, target T) []T {
return slices.DeleteFunc(slice, func(t T) bool { return t == target })
}
// TODO: Replace with "maps.Keys" once available, current it only in golang.org/x/exp/maps but not in standard library
func KeysOfMap[K comparable, V any](m map[K]V) []K {
keys := make([]K, 0, len(m))
for k := range m {
keys = append(keys, k)
}
return keys
}
+28 -6
View File
@@ -45,10 +45,32 @@ func SetSiteCookie(resp http.ResponseWriter, name, value string, maxAge int) {
SameSite: setting.SessionConfig.SameSite,
}
resp.Header().Add("Set-Cookie", cookie.String())
if maxAge < 0 {
// There was a bug in "setting.SessionConfig.CookiePath" code, the old default value of it was empty "".
// So we have to delete the cookie on path="" again, because some old code leaves cookies on path="".
cookie.Path = strings.TrimSuffix(setting.SessionConfig.CookiePath, "/")
resp.Header().Add("Set-Cookie", cookie.String())
}
// Previous versions would use a cookie path with a trailing /.
// These are more specific than cookies without a trailing /, so
// we need to delete these if they exist.
DeleteLegacySiteCookie(resp, name)
}
// DeleteLegacySiteCookie deletes the cookie with the given name at the cookie
// path with a trailing /, which would unintentionally override the cookie.
func DeleteLegacySiteCookie(resp http.ResponseWriter, name string) {
if setting.SessionConfig.CookiePath == "" || strings.HasSuffix(setting.SessionConfig.CookiePath, "/") {
// If the cookie path ends with /, no legacy cookies will take
// precedence, so do nothing. The exception is that cookies with no
// path could override other cookies, but it's complicated and we don't
// currently handle that.
return
}
cookie := &http.Cookie{
Name: name,
Value: "",
MaxAge: -1,
Path: setting.SessionConfig.CookiePath + "/",
Domain: setting.SessionConfig.Domain,
Secure: setting.SessionConfig.Secure,
HttpOnly: true,
SameSite: setting.SessionConfig.SameSite,
}
resp.Header().Add("Set-Cookie", cookie.String())
}
+3 -1
View File
@@ -1247,6 +1247,8 @@ editor.file_editing_no_longer_exists = The file being edited, "%s", no longer ex
editor.file_deleting_no_longer_exists = The file being deleted, "%s", no longer exists in this repository.
editor.file_changed_while_editing = The file contents have changed since you started editing. <a target="_blank" rel="noopener noreferrer" href="%s">Click here</a> to see them or <strong>Commit Changes again</strong> to overwrite them.
editor.file_already_exists = A file named "%s" already exists in this repository.
editor.commit_id_not_matching = The Commit ID does not match the ID when you began editing. Commit into a patch branch and then merge.
editor.push_out_of_date = The push appears to be out of date.
editor.commit_empty_file_header = Commit an empty file
editor.commit_empty_file_text = The file you're about to commit is empty. Proceed?
editor.no_changes_to_show = There are no changes to show.
@@ -3076,7 +3078,6 @@ config.enable_openid_signin = Enable OpenID Sign-In
config.show_registration_button = Show Register Button
config.require_sign_in_view = Require Sign-In to View Pages
config.mail_notify = Enable Email Notifications
config.disable_key_size_check = Disable Minimum Key Size Check
config.enable_captcha = Enable CAPTCHA
config.active_code_lives = Active Code Lives
config.reset_password_code_lives = Recover Account Code Expiry Time
@@ -3527,6 +3528,7 @@ runs.scheduled = Scheduled
runs.pushed_by = pushed by
runs.invalid_workflow_helper = Workflow config file is invalid. Please check your config file: %s
runs.no_matching_online_runner_helper = No matching online runner with label: %s
runs.no_job_without_needs = The workflow must contain at least one job without dependencies.
runs.actor = Actor
runs.status = Status
runs.actors_no_select = All actors
+18 -4
View File
@@ -27,7 +27,7 @@
"escape-goat": "4.0.0",
"fast-glob": "3.3.1",
"jquery": "3.7.1",
"katex": "0.16.9",
"katex": "0.16.10",
"license-checker-webpack-plugin": "0.2.1",
"lightningcss-loader": "2.1.0",
"mermaid": "10.6.1",
@@ -39,6 +39,7 @@
"pretty-ms": "8.0.0",
"sortablejs": "1.15.0",
"swagger-ui-dist": "5.9.0",
"temporal-polyfill": "0.2.3",
"throttle-debounce": "5.0.0",
"tinycolor2": "1.6.0",
"tippy.js": "6.3.7",
@@ -6726,9 +6727,9 @@
"integrity": "sha512-b+z6yF1d4EOyDgylzQo5IminlUmzSeqR1hs/bzjBNjuGras4FXq/6TrzjxfN0j+TmI0ltJzTNlqXUMCniciwKQ=="
},
"node_modules/katex": {
"version": "0.16.9",
"resolved": "https://registry.npmjs.org/katex/-/katex-0.16.9.tgz",
"integrity": "sha512-fsSYjWS0EEOwvy81j3vRA8TEAhQhKiqO+FQaKWp0m39qwOzHVBgAUBIXWj1pB+O2W3fIpNa6Y9KSKCVbfPhyAQ==",
"version": "0.16.10",
"resolved": "https://registry.npmjs.org/katex/-/katex-0.16.10.tgz",
"integrity": "sha512-ZiqaC04tp2O5utMsl2TEZTXxa6WSC4yo0fv5ML++D3QZv/vx2Mct0mTlRx3O+uUkjfuAgOkzsCmq5MiUEsDDdA==",
"funding": [
"https://opencollective.com/katex",
"https://github.com/sponsors/katex"
@@ -10310,6 +10311,19 @@
"node": ">=6"
}
},
"node_modules/temporal-polyfill": {
"version": "0.2.3",
"resolved": "https://registry.npmjs.org/temporal-polyfill/-/temporal-polyfill-0.2.3.tgz",
"integrity": "sha512-7ZJRc7wq/1XjrOQYkkNpgo2qfE9XLrUU8D/DS+LAC/T0bYqZ46rW6dow0sOTXTPZS4bwer8bD/0OyuKQBfA3yw==",
"dependencies": {
"temporal-spec": "^0.2.0"
}
},
"node_modules/temporal-spec": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/temporal-spec/-/temporal-spec-0.2.0.tgz",
"integrity": "sha512-r1AT0XdEp8TMQ13FLvOt8mOtAxDQsRt2QU5rSWCA7YfshddU651Y1NHVrceLANvixKdf9fYO8B/S9fXHodB7HQ=="
},
"node_modules/terser": {
"version": "5.21.0",
"resolved": "https://registry.npmjs.org/terser/-/terser-5.21.0.tgz",
+2 -1
View File
@@ -26,7 +26,7 @@
"escape-goat": "4.0.0",
"fast-glob": "3.3.1",
"jquery": "3.7.1",
"katex": "0.16.9",
"katex": "0.16.10",
"license-checker-webpack-plugin": "0.2.1",
"lightningcss-loader": "2.1.0",
"mermaid": "10.6.1",
@@ -38,6 +38,7 @@
"pretty-ms": "8.0.0",
"sortablejs": "1.15.0",
"swagger-ui-dist": "5.9.0",
"temporal-polyfill": "0.2.3",
"throttle-debounce": "5.0.0",
"tinycolor2": "1.6.0",
"tippy.js": "6.3.7",
+14
View File
@@ -9,6 +9,8 @@ import (
"net/http"
actions_model "code.gitea.io/gitea/models/actions"
repo_model "code.gitea.io/gitea/models/repo"
user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/actions"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/util"
@@ -54,6 +56,18 @@ func (s *Service) Register(
return nil, errors.New("runner registration token has been invalidated, please use the latest one")
}
if runnerToken.OwnerID > 0 {
if _, err := user_model.GetUserByID(ctx, runnerToken.OwnerID); err != nil {
return nil, errors.New("owner of the token not found")
}
}
if runnerToken.RepoID > 0 {
if _, err := repo_model.GetRepositoryByID(ctx, runnerToken.RepoID); err != nil {
return nil, errors.New("repository of the token not found")
}
}
labels := req.Msg.Labels
// TODO: agent_labels should be removed from pb after Gitea 1.20 released.
// Old version runner's agent_labels slice is not empty and labels slice is empty.
+12 -62
View File
@@ -14,7 +14,6 @@ import (
"code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/json"
"code.gitea.io/gitea/modules/log"
secret_module "code.gitea.io/gitea/modules/secret"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/services/actions"
@@ -31,14 +30,24 @@ func pickTask(ctx context.Context, runner *actions_model.ActionRunner) (*runnerv
return nil, false, nil
}
secrets, err := secret_model.GetSecretsOfTask(ctx, t)
if err != nil {
return nil, false, fmt.Errorf("GetSecretsOfTask: %w", err)
}
vars, err := actions_model.GetVariablesOfRun(ctx, t.Job.Run)
if err != nil {
return nil, false, fmt.Errorf("GetVariablesOfRun: %w", err)
}
actions.CreateCommitStatus(ctx, t.Job)
task := &runnerv1.Task{
Id: t.ID,
WorkflowPayload: t.Job.WorkflowPayload,
Context: generateTaskContext(t),
Secrets: getSecretsOfTask(ctx, t),
Vars: getVariablesOfTask(ctx, t),
Secrets: secrets,
Vars: vars,
}
if needs, err := findTaskNeeds(ctx, t); err != nil {
@@ -54,65 +63,6 @@ func pickTask(ctx context.Context, runner *actions_model.ActionRunner) (*runnerv
return task, true, nil
}
func getSecretsOfTask(ctx context.Context, task *actions_model.ActionTask) map[string]string {
secrets := map[string]string{}
secrets["GITHUB_TOKEN"] = task.Token
secrets["GITEA_TOKEN"] = task.Token
if task.Job.Run.IsForkPullRequest && task.Job.Run.TriggerEvent != actions_module.GithubEventPullRequestTarget {
// ignore secrets for fork pull request, except GITHUB_TOKEN and GITEA_TOKEN which are automatically generated.
// for the tasks triggered by pull_request_target event, they could access the secrets because they will run in the context of the base branch
// see the documentation: https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#pull_request_target
return secrets
}
ownerSecrets, err := secret_model.FindSecrets(ctx, secret_model.FindSecretsOptions{OwnerID: task.Job.Run.Repo.OwnerID})
if err != nil {
log.Error("find secrets of owner %v: %v", task.Job.Run.Repo.OwnerID, err)
// go on
}
repoSecrets, err := secret_model.FindSecrets(ctx, secret_model.FindSecretsOptions{RepoID: task.Job.Run.RepoID})
if err != nil {
log.Error("find secrets of repo %v: %v", task.Job.Run.RepoID, err)
// go on
}
for _, secret := range append(ownerSecrets, repoSecrets...) {
if v, err := secret_module.DecryptSecret(setting.SecretKey, secret.Data); err != nil {
log.Error("decrypt secret %v %q: %v", secret.ID, secret.Name, err)
// go on
} else {
secrets[secret.Name] = v
}
}
return secrets
}
func getVariablesOfTask(ctx context.Context, task *actions_model.ActionTask) map[string]string {
variables := map[string]string{}
// Org / User level
ownerVariables, err := actions_model.FindVariables(ctx, actions_model.FindVariablesOpts{OwnerID: task.Job.Run.Repo.OwnerID})
if err != nil {
log.Error("find variables of org: %d, error: %v", task.Job.Run.Repo.OwnerID, err)
}
// Repo level
repoVariables, err := actions_model.FindVariables(ctx, actions_model.FindVariablesOpts{RepoID: task.Job.Run.RepoID})
if err != nil {
log.Error("find variables of repo: %d, error: %v", task.Job.Run.RepoID, err)
}
// Level precedence: Repo > Org / User
for _, v := range append(ownerVariables, repoVariables...) {
variables[v.Name] = v.Data
}
return variables
}
func generateTaskContext(t *actions_model.ActionTask) *structpb.Struct {
event := map[string]any{}
_ = json.Unmarshal([]byte(t.Job.Run.EventPayload), &event)
+3 -2
View File
@@ -864,10 +864,11 @@ func EditIssue(ctx *context.APIContext) {
}
if form.State != nil {
if issue.IsPull {
if pr, err := issue.GetPullRequest(); err != nil {
if err := issue.LoadPullRequest(ctx); err != nil {
ctx.Error(http.StatusInternalServerError, "GetPullRequest", err)
return
} else if pr.HasMerged {
}
if issue.PullRequest.HasMerged {
ctx.Error(http.StatusPreconditionFailed, "MergedPRState", "cannot change state of this pull request, it was already merged")
return
}
+5 -11
View File
@@ -240,18 +240,12 @@ func ListPinnedPullRequests(ctx *context.APIContext) {
}
apiPrs := make([]*api.PullRequest, len(issues))
if err := issues.LoadPullRequests(ctx); err != nil {
ctx.Error(http.StatusInternalServerError, "LoadPullRequests", err)
return
}
for i, currentIssue := range issues {
pr, err := currentIssue.GetPullRequest()
if err != nil {
ctx.Error(http.StatusInternalServerError, "GetPullRequest", err)
return
}
if err = pr.LoadIssue(ctx); err != nil {
ctx.Error(http.StatusInternalServerError, "LoadIssue", err)
return
}
pr := currentIssue.PullRequest
if err = pr.LoadAttributes(ctx); err != nil {
ctx.Error(http.StatusInternalServerError, "LoadAttributes", err)
return
+2
View File
@@ -969,6 +969,8 @@ func parseCompareInfo(ctx *context.APIContext, form api.CreatePullRequestOption)
return nil, nil, nil, nil, "", ""
}
headBranch = headInfos[1]
// The head repository can also point to the same repo
isSameRepo = ctx.Repo.Owner.ID == headUser.ID
} else {
ctx.NotFound()
+2 -2
View File
@@ -13,7 +13,7 @@ import (
"code.gitea.io/gitea/modules/web"
"code.gitea.io/gitea/routers/api/v1/utils"
"code.gitea.io/gitea/services/convert"
files_service "code.gitea.io/gitea/services/repository/files"
commitstatus_service "code.gitea.io/gitea/services/repository/commitstatus"
)
// NewCommitStatus creates a new CommitStatus
@@ -63,7 +63,7 @@ func NewCommitStatus(ctx *context.APIContext) {
Description: form.Description,
Context: form.Context,
}
if err := files_service.CreateCommitStatus(ctx, ctx.Repo.Repository, ctx.Doer, sha, status); err != nil {
if err := commitstatus_service.CreateCommitStatus(ctx, ctx.Repo.Repository, ctx.Doer, sha, status); err != nil {
ctx.Error(http.StatusInternalServerError, "CreateCommitStatus", err)
return
}
+44 -41
View File
@@ -6,10 +6,11 @@ package private
import (
"fmt"
"net/http"
"strconv"
issues_model "code.gitea.io/gitea/models/issues"
access_model "code.gitea.io/gitea/models/perm/access"
repo_model "code.gitea.io/gitea/models/repo"
user_model "code.gitea.io/gitea/models/user"
gitea_context "code.gitea.io/gitea/modules/context"
"code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/log"
@@ -89,8 +90,10 @@ func HookPostReceive(ctx *gitea_context.PrivateContext) {
}
}
isPrivate := opts.GitPushOptions.Bool(private.GitPushOptionRepoPrivate)
isTemplate := opts.GitPushOptions.Bool(private.GitPushOptionRepoTemplate)
// Handle Push Options
if len(opts.GitPushOptions) > 0 {
if !isPrivate.IsNone() || !isTemplate.IsNone() {
// load the repository
if repo == nil {
repo = loadRepository(ctx, ownerName, repoName)
@@ -101,13 +104,49 @@ func HookPostReceive(ctx *gitea_context.PrivateContext) {
wasEmpty = repo.IsEmpty
}
repo.IsPrivate = opts.GitPushOptions.Bool(private.GitPushOptionRepoPrivate, repo.IsPrivate)
repo.IsTemplate = opts.GitPushOptions.Bool(private.GitPushOptionRepoTemplate, repo.IsTemplate)
if err := repo_model.UpdateRepositoryCols(ctx, repo, "is_private", "is_template"); err != nil {
pusher, err := user_model.GetUserByID(ctx, opts.UserID)
if err != nil {
log.Error("Failed to Update: %s/%s Error: %v", ownerName, repoName, err)
ctx.JSON(http.StatusInternalServerError, private.HookPostReceiveResult{
Err: fmt.Sprintf("Failed to Update: %s/%s Error: %v", ownerName, repoName, err),
})
return
}
perm, err := access_model.GetUserRepoPermission(ctx, repo, pusher)
if err != nil {
log.Error("Failed to Update: %s/%s Error: %v", ownerName, repoName, err)
ctx.JSON(http.StatusInternalServerError, private.HookPostReceiveResult{
Err: fmt.Sprintf("Failed to Update: %s/%s Error: %v", ownerName, repoName, err),
})
return
}
if !perm.IsOwner() && !perm.IsAdmin() {
ctx.JSON(http.StatusNotFound, private.HookPostReceiveResult{
Err: "Permissions denied",
})
return
}
cols := make([]string, 0, len(opts.GitPushOptions))
if !isPrivate.IsNone() {
repo.IsPrivate = isPrivate.IsTrue()
cols = append(cols, "is_private")
}
if !isTemplate.IsNone() {
repo.IsTemplate = isTemplate.IsTrue()
cols = append(cols, "is_template")
}
if len(cols) > 0 {
if err := repo_model.UpdateRepositoryCols(ctx, repo, cols...); err != nil {
log.Error("Failed to Update: %s/%s Error: %v", ownerName, repoName, err)
ctx.JSON(http.StatusInternalServerError, private.HookPostReceiveResult{
Err: fmt.Sprintf("Failed to Update: %s/%s Error: %v", ownerName, repoName, err),
})
return
}
}
}
@@ -122,42 +161,6 @@ func HookPostReceive(ctx *gitea_context.PrivateContext) {
refFullName := opts.RefFullNames[i]
newCommitID := opts.NewCommitIDs[i]
// post update for agit pull request
// FIXME: use pr.Flow to test whether it's an Agit PR or a GH PR
if git.SupportProcReceive && refFullName.IsPull() {
if repo == nil {
repo = loadRepository(ctx, ownerName, repoName)
if ctx.Written() {
return
}
}
pullIndex, _ := strconv.ParseInt(refFullName.PullName(), 10, 64)
if pullIndex <= 0 {
continue
}
pr, err := issues_model.GetPullRequestByIndex(ctx, repo.ID, pullIndex)
if err != nil && !issues_model.IsErrPullRequestNotExist(err) {
log.Error("Failed to get PR by index %v Error: %v", pullIndex, err)
ctx.JSON(http.StatusInternalServerError, private.Response{
Err: fmt.Sprintf("Failed to get PR by index %v Error: %v", pullIndex, err),
})
return
}
if pr == nil {
continue
}
results = append(results, private.HookPostReceiveBranchResult{
Message: setting.Git.PullRequestPushMessage && repo.AllowsPulls(),
Create: false,
Branch: "",
URL: fmt.Sprintf("%s/pulls/%d", repo.HTMLURL(), pr.Index),
})
continue
}
// If we've pushed a branch (and not deleted it)
if newCommitID != git.EmptySHA && refFullName.IsBranch() {
+9 -1
View File
@@ -105,8 +105,13 @@ func List(ctx *context.Context) {
workflows = append(workflows, workflow)
continue
}
// Check whether have matching runner
// The workflow must contain at least one job without "needs". Otherwise, a deadlock will occur and no jobs will be able to run.
hasJobWithoutNeeds := false
// Check whether have matching runner and a job without "needs"
for _, j := range wf.Jobs {
if !hasJobWithoutNeeds && len(j.Needs()) == 0 {
hasJobWithoutNeeds = true
}
runsOnList := j.RunsOn()
for _, ro := range runsOnList {
if strings.Contains(ro, "${{") {
@@ -124,6 +129,9 @@ func List(ctx *context.Context) {
break
}
}
if !hasJobWithoutNeeds {
workflow.ErrMsg = ctx.Locale.Tr("actions.runs.no_job_without_needs")
}
workflows = append(workflows, workflow)
}
}
+21 -5
View File
@@ -289,12 +289,25 @@ func Rerun(ctx *context_module.Context) {
return
}
if jobIndexStr != "" {
jobs = []*actions_model.ActionRunJob{job}
if jobIndexStr == "" { // rerun all jobs
for _, j := range jobs {
// if the job has needs, it should be set to "blocked" status to wait for other jobs
shouldBlock := len(j.Needs) > 0
if err := rerunJob(ctx, j, shouldBlock); err != nil {
ctx.Error(http.StatusInternalServerError, err.Error())
return
}
}
ctx.JSON(http.StatusOK, struct{}{})
return
}
for _, j := range jobs {
if err := rerunJob(ctx, j); err != nil {
rerunJobs := actions_service.GetAllRerunJobs(job, jobs)
for _, j := range rerunJobs {
// jobs other than the specified one should be set to "blocked" status
shouldBlock := j.JobID != job.JobID
if err := rerunJob(ctx, j, shouldBlock); err != nil {
ctx.Error(http.StatusInternalServerError, err.Error())
return
}
@@ -303,7 +316,7 @@ func Rerun(ctx *context_module.Context) {
ctx.JSON(http.StatusOK, struct{}{})
}
func rerunJob(ctx *context_module.Context, job *actions_model.ActionRunJob) error {
func rerunJob(ctx *context_module.Context, job *actions_model.ActionRunJob, shouldBlock bool) error {
status := job.Status
if !status.IsDone() {
return nil
@@ -311,6 +324,9 @@ func rerunJob(ctx *context_module.Context, job *actions_model.ActionRunJob) erro
job.TaskID = 0
job.Status = actions_model.StatusWaiting
if shouldBlock {
job.Status = actions_model.StatusBlocked
}
job.Started = 0
job.Stopped = 0
+2 -2
View File
@@ -333,9 +333,9 @@ func editFilePost(ctx *context.Context, form forms.EditRepoFileForm, isNewFile b
ctx.Error(http.StatusInternalServerError, err.Error())
}
} else if models.IsErrCommitIDDoesNotMatch(err) {
ctx.RenderWithErr(ctx.Tr("repo.editor.file_changed_while_editing", ctx.Repo.RepoLink+"/compare/"+util.PathEscapeSegments(form.LastCommit)+"..."+util.PathEscapeSegments(ctx.Repo.CommitID)), tplEditFile, &form)
ctx.RenderWithErr(ctx.Tr("repo.editor.commit_id_not_matching", ctx.Repo.RepoLink+"/compare/"+util.PathEscapeSegments(form.LastCommit)+"..."+util.PathEscapeSegments(ctx.Repo.CommitID)), tplEditFile, &form)
} else if git.IsErrPushOutOfDate(err) {
ctx.RenderWithErr(ctx.Tr("repo.editor.file_changed_while_editing", ctx.Repo.RepoLink+"/compare/"+util.PathEscapeSegments(form.LastCommit)+"..."+util.PathEscapeSegments(form.NewBranchName)), tplEditFile, &form)
ctx.RenderWithErr(ctx.Tr("repo.editor.push_out_of_date", ctx.Repo.RepoLink+"/compare/"+util.PathEscapeSegments(form.LastCommit)+"..."+util.PathEscapeSegments(form.NewBranchName)), tplEditFile, &form)
} else if git.IsErrPushRejected(err) {
errPushRej := err.(*git.ErrPushRejected)
if len(errPushRej.Message) == 0 {
+3 -2
View File
@@ -8,6 +8,7 @@ import (
"code.gitea.io/gitea/modules/base"
"code.gitea.io/gitea/modules/context"
"code.gitea.io/gitea/modules/util"
)
const (
@@ -17,7 +18,7 @@ const (
// FindFiles render the page to find repository files
func FindFiles(ctx *context.Context) {
path := ctx.Params("*")
ctx.Data["TreeLink"] = ctx.Repo.RepoLink + "/src/" + path
ctx.Data["DataLink"] = ctx.Repo.RepoLink + "/tree-list/" + path
ctx.Data["TreeLink"] = ctx.Repo.RepoLink + "/src/" + util.PathEscapeSegments(path)
ctx.Data["DataLink"] = ctx.Repo.RepoLink + "/tree-list/" + util.PathEscapeSegments(path)
ctx.HTML(http.StatusOK, tplFindFiles)
}
+1 -1
View File
@@ -1910,7 +1910,7 @@ func ViewIssue(ctx *context.Context) {
if pull.HasMerged || issue.IsClosed || !ctx.IsSigned {
return false
}
if pull.CanAutoMerge() || pull.IsWorkInProgress() || pull.IsChecking() {
if pull.CanAutoMerge() || pull.IsWorkInProgress(ctx) || pull.IsChecking() {
return false
}
if (ctx.Doer.IsAdmin || ctx.Repo.IsAdmin()) && prConfig.AllowManualMerge {
+1 -1
View File
@@ -706,7 +706,7 @@ func PrepareViewPullInfo(ctx *context.Context, issue *issues_model.Issue) *git.C
ctx.Data["IsNothingToCompare"] = true
}
if pull.IsWorkInProgress() {
if pull.IsWorkInProgress(ctx) {
ctx.Data["IsPullWorkInProgress"] = true
ctx.Data["WorkInProgressPrefix"] = pull.GetWorkInProgressPrefix(ctx)
}
+17
View File
@@ -4,6 +4,7 @@
package repo
import (
"net/http"
"net/http/httptest"
"testing"
@@ -73,4 +74,20 @@ func TestRenderConversation(t *testing.T) {
renderConversation(ctx, preparedComment, "timeline")
assert.Contains(t, resp.Body.String(), `<div id="code-comments-`)
})
run("diff non-existing review", func(t *testing.T, ctx *context.Context, resp *httptest.ResponseRecorder) {
err := db.TruncateBeans(db.DefaultContext, &issues_model.Review{})
assert.NoError(t, err)
ctx.Data["ShowOutdatedComments"] = true
renderConversation(ctx, preparedComment, "diff")
assert.Equal(t, http.StatusOK, resp.Code)
assert.NotContains(t, resp.Body.String(), `status-page-500`)
})
run("timeline non-existing review", func(t *testing.T, ctx *context.Context, resp *httptest.ResponseRecorder) {
err := db.TruncateBeans(db.DefaultContext, &issues_model.Review{})
assert.NoError(t, err)
ctx.Data["ShowOutdatedComments"] = true
renderConversation(ctx, preparedComment, "timeline")
assert.Equal(t, http.StatusOK, resp.Code)
assert.NotContains(t, resp.Body.String(), `status-page-500`)
})
}
+7 -8
View File
@@ -12,6 +12,7 @@ import (
"code.gitea.io/gitea/modules/charset"
"code.gitea.io/gitea/modules/context"
"code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/markup"
"code.gitea.io/gitea/modules/typesniffer"
"code.gitea.io/gitea/modules/util"
@@ -44,20 +45,17 @@ func RenderFile(ctx *context.Context) {
isTextFile := st.IsText()
rd := charset.ToUTF8WithFallbackReader(io.MultiReader(bytes.NewReader(buf), dataRc), charset.ConvertOpts{})
ctx.Resp.Header().Add("Content-Security-Policy", "frame-src 'self'; sandbox allow-scripts")
if markupType := markup.Type(blob.Name()); markupType == "" {
if isTextFile {
_, err = io.Copy(ctx.Resp, rd)
if err != nil {
ctx.ServerError("Copy", err)
}
return
_, _ = io.Copy(ctx.Resp, rd)
} else {
http.Error(ctx.Resp, "Unsupported file type render", http.StatusInternalServerError)
}
ctx.Error(http.StatusInternalServerError, "Unsupported file type render")
return
}
ctx.Resp.Header().Add("Content-Security-Policy", "frame-src 'self'; sandbox allow-scripts")
err = markup.Render(&markup.RenderContext{
Ctx: ctx,
RelativePath: ctx.Repo.TreePath,
@@ -71,7 +69,8 @@ func RenderFile(ctx *context.Context) {
InStandalonePage: true,
}, rd, ctx.Resp)
if err != nil {
ctx.ServerError("Render", err)
log.Error("Failed to render file %q: %v", ctx.Repo.TreePath, err)
http.Error(ctx.Resp, "Failed to render file", http.StatusInternalServerError)
return
}
}
+22 -30
View File
@@ -34,6 +34,7 @@ import (
"code.gitea.io/gitea/services/forms"
repo_service "code.gitea.io/gitea/services/repository"
archiver_service "code.gitea.io/gitea/services/repository/archiver"
commitstatus_service "code.gitea.io/gitea/services/repository/commitstatus"
)
const (
@@ -575,47 +576,35 @@ func SearchRepo(ctx *context.Context) {
}
}
var err error
// To improve performance when only the count is requested
if ctx.FormBool("count_only") {
if count, err := repo_model.CountRepository(ctx, opts); err != nil {
log.Error("CountRepository: %v", err)
ctx.JSON(http.StatusInternalServerError, nil) // frontend JS doesn't handle error response (same as below)
} else {
ctx.SetTotalCountHeader(count)
ctx.JSONOK()
}
return
}
repos, count, err := repo_model.SearchRepository(ctx, opts)
if err != nil {
ctx.JSON(http.StatusInternalServerError, api.SearchError{
OK: false,
Error: err.Error(),
})
log.Error("SearchRepository: %v", err)
ctx.JSON(http.StatusInternalServerError, nil)
return
}
ctx.SetTotalCountHeader(count)
// To improve performance when only the count is requested
if ctx.FormBool("count_only") {
return
}
// collect the latest commit of each repo
// at most there are dozens of repos (limited by MaxResponseItems), so it's not a big problem at the moment
repoBranchNames := make(map[int64]string, len(repos))
for _, repo := range repos {
repoBranchNames[repo.ID] = repo.DefaultBranch
}
repoIDsToLatestCommitSHAs, err := git_model.FindBranchesByRepoAndBranchName(ctx, repoBranchNames)
latestCommitStatuses, err := commitstatus_service.FindReposLastestCommitStatuses(ctx, repos)
if err != nil {
log.Error("FindBranchesByRepoAndBranchName: %v", err)
return
}
// call the database O(1) times to get the commit statuses for all repos
repoToItsLatestCommitStatuses, err := git_model.GetLatestCommitStatusForPairs(ctx, repoIDsToLatestCommitSHAs, db.ListOptions{})
if err != nil {
log.Error("GetLatestCommitStatusForPairs: %v", err)
log.Error("FindReposLastestCommitStatuses: %v", err)
return
}
results := make([]*repo_service.WebSearchRepository, len(repos))
for i, repo := range repos {
latestCommitStatus := git_model.CalcCommitStatus(repoToItsLatestCommitStatuses[repo.ID])
results[i] = &repo_service.WebSearchRepository{
Repository: &api.Repository{
ID: repo.ID,
@@ -629,8 +618,11 @@ func SearchRepo(ctx *context.Context) {
Link: repo.Link(),
Internal: !repo.IsPrivate && repo.Owner.Visibility == api.VisibleTypePrivate,
},
LatestCommitStatus: latestCommitStatus,
LocaleLatestCommitStatus: latestCommitStatus.LocaleString(ctx.Locale),
}
if latestCommitStatuses[i] != nil {
results[i].LatestCommitStatus = latestCommitStatuses[i]
results[i].LocaleLatestCommitStatus = latestCommitStatuses[i].LocaleString(ctx.Locale)
}
}
+7 -1
View File
@@ -312,7 +312,13 @@ func RenameBranchPost(ctx *context.Context) {
msg, err := repository.RenameBranch(ctx, ctx.Repo.Repository, ctx.Doer, ctx.Repo.GitRepo, form.From, form.To)
if err != nil {
ctx.ServerError("RenameBranch", err)
switch {
case git_model.IsErrBranchAlreadyExists(err):
ctx.Flash.Error(ctx.Tr("repo.branch.branch_already_exists", form.To))
ctx.Redirect(fmt.Sprintf("%s/branches", ctx.Repo.RepoLink))
default:
ctx.ServerError("RenameBranch", err)
}
return
}
+5 -2
View File
@@ -824,12 +824,16 @@ func UsernameSubRoute(ctx *context.Context) {
reloadParam := func(suffix string) (success bool) {
ctx.SetParams("username", strings.TrimSuffix(username, suffix))
context_service.UserAssignmentWeb()(ctx)
if ctx.Written() {
return false
}
// check view permissions
if !user_model.IsUserVisibleToViewer(ctx, ctx.ContextUser, ctx.Doer) {
ctx.NotFound("user", fmt.Errorf(ctx.ContextUser.Name))
return false
}
return !ctx.Written()
return true
}
switch {
case strings.HasSuffix(username, ".png"):
@@ -850,7 +854,6 @@ func UsernameSubRoute(ctx *context.Context) {
return
}
if reloadParam(".rss") {
context_service.UserAssignmentWeb()(ctx)
feed.ShowUserFeedRSS(ctx)
}
case strings.HasSuffix(username, ".atom"):
+6
View File
@@ -128,6 +128,12 @@ func getNotifications(ctx *context.Context) {
ctx.ServerError("LoadIssues", err)
return
}
if err = notifications.LoadIssuePullRequests(ctx); err != nil {
ctx.ServerError("LoadIssuePullRequests", err)
return
}
notifications = notifications.Without(failures)
failCount += len(failures)
+11 -8
View File
@@ -12,9 +12,11 @@ import (
"code.gitea.io/gitea/models/db"
git_model "code.gitea.io/gitea/models/git"
user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/log"
api "code.gitea.io/gitea/modules/structs"
webhook_module "code.gitea.io/gitea/modules/webhook"
commitstatus_service "code.gitea.io/gitea/services/repository/commitstatus"
"github.com/nektos/act/pkg/jobparser"
)
@@ -114,19 +116,20 @@ func createCommitStatus(ctx context.Context, job *actions_model.ActionRunJob) er
}
creator := user_model.NewActionsUser()
if err := git_model.NewCommitStatus(ctx, git_model.NewCommitStatusOptions{
Repo: repo,
SHA: sha,
Creator: creator,
CommitStatus: &git_model.CommitStatus{
SHA: sha,
commitID, err := git.NewIDFromString(sha)
if err != nil {
return fmt.Errorf("HashTypeInterfaceFromHashString: %w", err)
}
if err := commitstatus_service.CreateCommitStatus(ctx, repo, creator,
commitID.String(),
&git_model.CommitStatus{
SHA: commitID.String(),
TargetURL: fmt.Sprintf("%s/jobs/%d", run.Link(), index),
Description: description,
Context: ctxname,
CreatorID: creator.ID,
State: state,
},
}); err != nil {
}); err != nil {
return fmt.Errorf("NewCommitStatus: %w", err)
}
+13 -3
View File
@@ -516,6 +516,12 @@ func (*actionsNotifier) MergePullRequest(ctx context.Context, doer *user_model.U
}
func (n *actionsNotifier) PushCommits(ctx context.Context, pusher *user_model.User, repo *repo_model.Repository, opts *repository.PushUpdateOptions, commits *repository.PushCommits) {
commitID, _ := git.NewIDFromString(opts.NewCommitID)
if commitID.IsZero() {
log.Trace("new commitID is empty")
return
}
ctx = withMethod(ctx, "PushCommits")
apiPusher := convert.ToUser(ctx, pusher, nil)
@@ -548,9 +554,9 @@ func (n *actionsNotifier) CreateRef(ctx context.Context, pusher *user_model.User
apiRepo := convert.ToRepo(ctx, repo, access_model.Permission{AccessMode: perm_model.AccessModeNone})
newNotifyInput(repo, pusher, webhook_module.HookEventCreate).
WithRef(refFullName.ShortName()). // FIXME: should we use a full ref name
WithRef(refFullName.String()).
WithPayload(&api.CreatePayload{
Ref: refFullName.ShortName(),
Ref: refFullName.String(),
Sha: refID,
RefType: refFullName.RefType(),
Repo: apiRepo,
@@ -567,7 +573,7 @@ func (n *actionsNotifier) DeleteRef(ctx context.Context, pusher *user_model.User
newNotifyInput(repo, pusher, webhook_module.HookEventDelete).
WithPayload(&api.DeletePayload{
Ref: refFullName.ShortName(),
Ref: refFullName.String(),
RefType: refFullName.RefType(),
PusherType: api.PusherTypeUser,
Repo: apiRepo,
@@ -624,6 +630,10 @@ func (n *actionsNotifier) UpdateRelease(ctx context.Context, doer *user_model.Us
}
func (n *actionsNotifier) DeleteRelease(ctx context.Context, doer *user_model.User, rel *repo_model.Release) {
if rel.IsTag {
// has sent same action in `PushCommits`, so skip it.
return
}
ctx = withMethod(ctx, "DeleteRelease")
notifyRelease(ctx, doer, rel, api.HookReleaseDeleted)
}
+15 -7
View File
@@ -269,7 +269,18 @@ func handleWorkflows(
run.NeedApproval = need
}
jobs, err := jobparser.Parse(dwf.Content)
if err := run.LoadAttributes(ctx); err != nil {
log.Error("LoadAttributes: %v", err)
continue
}
vars, err := actions_model.GetVariablesOfRun(ctx, run)
if err != nil {
log.Error("GetVariablesOfRun: %v", err)
continue
}
jobs, err := jobparser.Parse(dwf.Content, jobparser.WithVars(vars))
if err != nil {
log.Error("jobparser.Parse: %v", err)
continue
@@ -483,12 +494,9 @@ func DetectAndHandleSchedules(ctx context.Context, repo *repo_model.Repository)
}
// We need a notifyInput to call handleSchedules
// Here we use the commit author as the Doer of the notifyInput
commitUser, err := user_model.GetUserByEmail(ctx, commit.Author.Email)
if err != nil {
return fmt.Errorf("get user by email: %w", err)
}
notifyInput := newNotifyInput(repo, commitUser, webhook_module.HookEventSchedule)
// if repo is a mirror, commit author maybe an external user,
// so we use action user as the Doer of the notifyInput
notifyInput := newNotifyInput(repo, user_model.NewActionsUser(), webhook_module.HookEventSchedule)
return handleSchedules(ctx, scheduleWorkflows, commit, notifyInput, repo.DefaultBranch)
}
+38
View File
@@ -0,0 +1,38 @@
// Copyright 2024 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package actions
import (
actions_model "code.gitea.io/gitea/models/actions"
"code.gitea.io/gitea/modules/container"
)
// GetAllRerunJobs get all jobs that need to be rerun when job should be rerun
func GetAllRerunJobs(job *actions_model.ActionRunJob, allJobs []*actions_model.ActionRunJob) []*actions_model.ActionRunJob {
rerunJobs := []*actions_model.ActionRunJob{job}
rerunJobsIDSet := make(container.Set[string])
rerunJobsIDSet.Add(job.JobID)
for {
found := false
for _, j := range allJobs {
if rerunJobsIDSet.Contains(j.JobID) {
continue
}
for _, need := range j.Needs {
if rerunJobsIDSet.Contains(need) {
found = true
rerunJobs = append(rerunJobs, j)
rerunJobsIDSet.Add(j.JobID)
break
}
}
}
if !found {
break
}
}
return rerunJobs
}
+48
View File
@@ -0,0 +1,48 @@
// Copyright 2024 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package actions
import (
"testing"
actions_model "code.gitea.io/gitea/models/actions"
"github.com/stretchr/testify/assert"
)
func TestGetAllRerunJobs(t *testing.T) {
job1 := &actions_model.ActionRunJob{JobID: "job1"}
job2 := &actions_model.ActionRunJob{JobID: "job2", Needs: []string{"job1"}}
job3 := &actions_model.ActionRunJob{JobID: "job3", Needs: []string{"job2"}}
job4 := &actions_model.ActionRunJob{JobID: "job4", Needs: []string{"job2", "job3"}}
jobs := []*actions_model.ActionRunJob{job1, job2, job3, job4}
testCases := []struct {
job *actions_model.ActionRunJob
rerunJobs []*actions_model.ActionRunJob
}{
{
job1,
[]*actions_model.ActionRunJob{job1, job2, job3, job4},
},
{
job2,
[]*actions_model.ActionRunJob{job2, job3, job4},
},
{
job3,
[]*actions_model.ActionRunJob{job3, job4},
},
{
job4,
[]*actions_model.ActionRunJob{job4},
},
}
for _, tc := range testCases {
rerunJobs := GetAllRerunJobs(tc.job, jobs)
assert.ElementsMatch(t, tc.rerunJobs, rerunJobs)
}
}
+17 -9
View File
@@ -15,6 +15,7 @@ import (
"code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/private"
"code.gitea.io/gitea/modules/setting"
notify_service "code.gitea.io/gitea/services/notify"
pull_service "code.gitea.io/gitea/services/pull"
)
@@ -149,10 +150,14 @@ func ProcReceive(ctx context.Context, repo *repo_model.Repository, gitRepo *git.
log.Trace("Pull request created: %d/%d", repo.ID, prIssue.ID)
results = append(results, private.HookProcReceiveRefResult{
Ref: pr.GetGitRefName(),
OriginalRef: opts.RefFullNames[i],
OldOID: git.EmptySHA,
NewOID: opts.NewCommitIDs[i],
Ref: pr.GetGitRefName(),
OriginalRef: opts.RefFullNames[i],
OldOID: git.EmptySHA,
NewOID: opts.NewCommitIDs[i],
IsCreatePR: true,
URL: fmt.Sprintf("%s/pulls/%d", repo.HTMLURL(), pr.Index),
ShouldShowMessage: setting.Git.PullRequestPushMessage && repo.AllowsPulls(),
HeadBranch: headBranch,
})
continue
}
@@ -214,11 +219,14 @@ func ProcReceive(ctx context.Context, repo *repo_model.Repository, gitRepo *git.
isForcePush := comment != nil && comment.IsForcePush
results = append(results, private.HookProcReceiveRefResult{
OldOID: oldCommitID,
NewOID: opts.NewCommitIDs[i],
Ref: pr.GetGitRefName(),
OriginalRef: opts.RefFullNames[i],
IsForcePush: isForcePush,
OldOID: oldCommitID,
NewOID: opts.NewCommitIDs[i],
Ref: pr.GetGitRefName(),
OriginalRef: opts.RefFullNames[i],
IsForcePush: isForcePush,
IsCreatePR: false,
URL: fmt.Sprintf("%s/pulls/%d", repo.HTMLURL(), pr.Index),
ShouldShowMessage: setting.Git.PullRequestPushMessage && repo.AllowsPulls(),
})
}
+9 -17
View File
@@ -6,7 +6,6 @@ package auth
import (
"net/http"
"code.gitea.io/gitea/models/db"
user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/log"
)
@@ -29,40 +28,33 @@ func (s *Session) Name() string {
// object for that uid.
// Returns nil if there is no user uid stored in the session.
func (s *Session) Verify(req *http.Request, w http.ResponseWriter, store DataStore, sess SessionStore) (*user_model.User, error) {
user := SessionUser(sess)
if user != nil {
return user, nil
}
return nil, nil
}
// SessionUser returns the user object corresponding to the "uid" session variable.
func SessionUser(sess SessionStore) *user_model.User {
if sess == nil {
return nil
return nil, nil
}
// Get user ID
uid := sess.Get("uid")
if uid == nil {
return nil
return nil, nil
}
log.Trace("Session Authorization: Found user[%d]", uid)
id, ok := uid.(int64)
if !ok {
return nil
return nil, nil
}
// Get user object
user, err := user_model.GetUserByID(db.DefaultContext, id)
user, err := user_model.GetUserByID(req.Context(), id)
if err != nil {
if !user_model.IsErrUserNotExist(err) {
log.Error("GetUserById: %v", err)
log.Error("GetUserByID: %v", err)
// Return the err as-is to keep current signed-in session, in case the err is something like context.Canceled. Otherwise non-existing user (nil, nil) will make the caller clear the signed-in session.
return nil, err
}
return nil
return nil, nil
}
log.Trace("Session Authorization: Logged in user %-v", user)
return user
return user, nil
}
+2 -1
View File
@@ -9,6 +9,7 @@ import (
"net/http"
"code.gitea.io/gitea/modules/log"
session_module "code.gitea.io/gitea/modules/session"
chiSession "gitea.com/go-chi/session"
"github.com/gorilla/sessions"
@@ -65,7 +66,7 @@ func (st *SessionsStore) Save(r *http.Request, w http.ResponseWriter, session *s
chiStore := chiSession.GetSession(r)
if session.IsNew {
_, _ = chiSession.RegenerateSession(w, r)
_, _ = session_module.RegenerateSession(w, r)
session.IsNew = false
}
+3 -2
View File
@@ -61,8 +61,9 @@ func ToNotificationThread(ctx context.Context, n *activities_model.Notification)
result.Subject.LatestCommentHTMLURL = comment.HTMLURL(ctx)
}
pr, _ := n.Issue.GetPullRequest()
if pr != nil && pr.HasMerged {
if err := n.Issue.LoadPullRequest(ctx); err == nil &&
n.Issue.PullRequest != nil &&
n.Issue.PullRequest.HasMerged {
result.Subject.State = "merged"
}
}
+1 -1
View File
@@ -68,7 +68,7 @@ func ToAPIPullRequest(ctx context.Context, pr *issues_model.PullRequest, doer *u
PatchURL: pr.Issue.PatchURL(),
HasMerged: pr.HasMerged,
MergeBase: pr.MergeBase,
Mergeable: pr.Mergeable(),
Mergeable: pr.Mergeable(ctx),
Deadline: apiIssue.Deadline,
Created: pr.Issue.CreatedUnix.AsTimePtr(),
Updated: pr.Issue.UpdatedUnix.AsTimePtr(),
+1 -1
View File
@@ -66,7 +66,7 @@ func ToPullReviewList(ctx context.Context, rl []*issues_model.Review, doer *user
result := make([]*api.PullReview, 0, len(rl))
for i := range rl {
// show pending reviews only for the user who created them
if rl[i].Type == issues_model.ReviewTypePending && !(doer.IsAdmin || doer.ID == rl[i].ReviewerID) {
if rl[i].Type == issues_model.ReviewTypePending && (doer == nil || (!doer.IsAdmin && doer.ID != rl[i].ReviewerID)) {
continue
}
r, err := ToPullReview(ctx, rl[i], doer)
+52
View File
@@ -0,0 +1,52 @@
// Copyright 2024 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package convert
import (
"testing"
"code.gitea.io/gitea/models/db"
issues_model "code.gitea.io/gitea/models/issues"
"code.gitea.io/gitea/models/unittest"
user_model "code.gitea.io/gitea/models/user"
"github.com/stretchr/testify/assert"
)
func Test_ToPullReview(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase())
reviewer := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
review := unittest.AssertExistsAndLoadBean(t, &issues_model.Review{ID: 6})
assert.EqualValues(t, reviewer.ID, review.ReviewerID)
assert.EqualValues(t, issues_model.ReviewTypePending, review.Type)
reviewList := []*issues_model.Review{review}
t.Run("Anonymous User", func(t *testing.T) {
prList, err := ToPullReviewList(db.DefaultContext, reviewList, nil)
assert.NoError(t, err)
assert.Empty(t, prList)
})
t.Run("Reviewer Himself", func(t *testing.T) {
prList, err := ToPullReviewList(db.DefaultContext, reviewList, reviewer)
assert.NoError(t, err)
assert.Len(t, prList, 1)
})
t.Run("Other User", func(t *testing.T) {
user4 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 4})
prList, err := ToPullReviewList(db.DefaultContext, reviewList, user4)
assert.NoError(t, err)
assert.Len(t, prList, 0)
})
t.Run("Admin User", func(t *testing.T) {
adminUser := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1})
prList, err := ToPullReviewList(db.DefaultContext, reviewList, adminUser)
assert.NoError(t, err)
assert.Len(t, prList, 1)
})
}
+20 -3
View File
@@ -242,16 +242,33 @@ func TeamReviewRequest(ctx context.Context, issue *issues_model.Issue, doer *use
return nil, nil
}
return comment, teamReviewRequestNotify(ctx, issue, doer, reviewer, isAdd, comment)
}
func ReviewRequestNotify(ctx context.Context, issue *issues_model.Issue, doer *user_model.User, reviewNotifers []*ReviewRequestNotifier) {
for _, reviewNotifer := range reviewNotifers {
if reviewNotifer.Reviwer != nil {
notify_service.PullRequestReviewRequest(ctx, issue.Poster, issue, reviewNotifer.Reviwer, reviewNotifer.IsAdd, reviewNotifer.Comment)
} else if reviewNotifer.ReviewTeam != nil {
if err := teamReviewRequestNotify(ctx, issue, issue.Poster, reviewNotifer.ReviewTeam, reviewNotifer.IsAdd, reviewNotifer.Comment); err != nil {
log.Error("teamReviewRequestNotify: %v", err)
}
}
}
}
// teamReviewRequestNotify notify all user in this team
func teamReviewRequestNotify(ctx context.Context, issue *issues_model.Issue, doer *user_model.User, reviewer *organization.Team, isAdd bool, comment *issues_model.Comment) error {
// notify all user in this team
if err := comment.LoadIssue(ctx); err != nil {
return nil, err
return err
}
members, err := organization.GetTeamMembers(ctx, &organization.SearchMembersOptions{
TeamID: reviewer.ID,
})
if err != nil {
return nil, err
return err
}
for _, member := range members {
@@ -262,5 +279,5 @@ func TeamReviewRequest(ctx context.Context, issue *issues_model.Issue, doer *use
notify_service.PullRequestReviewRequest(ctx, doer, issue, member, isAdd, comment)
}
return comment, err
return err
}
+11 -2
View File
@@ -16,6 +16,7 @@ import (
system_model "code.gitea.io/gitea/models/system"
user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/storage"
notify_service "code.gitea.io/gitea/services/notify"
)
@@ -66,17 +67,25 @@ func ChangeTitle(ctx context.Context, issue *issues_model.Issue, doer *user_mode
return nil
}
if err := issue.LoadRepo(ctx); err != nil {
return err
}
if err := issues_model.ChangeIssueTitle(ctx, issue, doer, oldTitle); err != nil {
return err
}
var reviewNotifers []*ReviewRequestNotifier
if issue.IsPull && issues_model.HasWorkInProgressPrefix(oldTitle) && !issues_model.HasWorkInProgressPrefix(title) {
if err := issues_model.PullRequestCodeOwnersReview(ctx, issue, issue.PullRequest); err != nil {
return err
var err error
reviewNotifers, err = PullRequestCodeOwnersReview(ctx, issue, issue.PullRequest)
if err != nil {
log.Error("PullRequestCodeOwnersReview: %v", err)
}
}
notify_service.IssueChangeTitle(ctx, doer, issue, oldTitle)
ReviewRequestNotify(ctx, issue, issue.Poster, reviewNotifers)
return nil
}
+146
View File
@@ -0,0 +1,146 @@
// Copyright 2024 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package issue
import (
"context"
"fmt"
"time"
issues_model "code.gitea.io/gitea/models/issues"
org_model "code.gitea.io/gitea/models/organization"
user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting"
)
func getMergeBase(repo *git.Repository, pr *issues_model.PullRequest, baseBranch, headBranch string) (string, error) {
// Add a temporary remote
tmpRemote := fmt.Sprintf("mergebase-%d-%d", pr.ID, time.Now().UnixNano())
if err := repo.AddRemote(tmpRemote, repo.Path, false); err != nil {
return "", fmt.Errorf("AddRemote: %w", err)
}
defer func() {
if err := repo.RemoveRemote(tmpRemote); err != nil {
log.Error("getMergeBase: RemoveRemote: %v", err)
}
}()
mergeBase, _, err := repo.GetMergeBase(tmpRemote, baseBranch, headBranch)
return mergeBase, err
}
type ReviewRequestNotifier struct {
Comment *issues_model.Comment
IsAdd bool
Reviwer *user_model.User
ReviewTeam *org_model.Team
}
func PullRequestCodeOwnersReview(ctx context.Context, issue *issues_model.Issue, pr *issues_model.PullRequest) ([]*ReviewRequestNotifier, error) {
files := []string{"CODEOWNERS", "docs/CODEOWNERS", ".gitea/CODEOWNERS"}
if pr.IsWorkInProgress(ctx) {
return nil, nil
}
if err := pr.LoadHeadRepo(ctx); err != nil {
return nil, err
}
if err := pr.LoadBaseRepo(ctx); err != nil {
return nil, err
}
if pr.BaseRepo.IsFork {
return nil, nil
}
repo, err := git.OpenRepository(ctx, pr.BaseRepo.RepoPath())
if err != nil {
return nil, err
}
defer repo.Close()
commit, err := repo.GetBranchCommit(pr.BaseRepo.DefaultBranch)
if err != nil {
return nil, err
}
var data string
for _, file := range files {
if blob, err := commit.GetBlobByPath(file); err == nil {
data, err = blob.GetBlobContent(setting.UI.MaxDisplayFileSize)
if err == nil {
break
}
}
}
rules, _ := issues_model.GetCodeOwnersFromContent(ctx, data)
// get the mergebase
mergeBase, err := getMergeBase(repo, pr, git.BranchPrefix+pr.BaseBranch, pr.GetGitRefName())
if err != nil {
return nil, err
}
// https://github.com/go-gitea/gitea/issues/29763, we need to get the files changed
// between the merge base and the head commit but not the base branch and the head commit
changedFiles, err := repo.GetFilesChangedBetween(mergeBase, pr.GetGitRefName())
if err != nil {
return nil, err
}
uniqUsers := make(map[int64]*user_model.User)
uniqTeams := make(map[string]*org_model.Team)
for _, rule := range rules {
for _, f := range changedFiles {
if (rule.Rule.MatchString(f) && !rule.Negative) || (!rule.Rule.MatchString(f) && rule.Negative) {
for _, u := range rule.Users {
uniqUsers[u.ID] = u
}
for _, t := range rule.Teams {
uniqTeams[fmt.Sprintf("%d/%d", t.OrgID, t.ID)] = t
}
}
}
}
notifiers := make([]*ReviewRequestNotifier, 0, len(uniqUsers)+len(uniqTeams))
if err := issue.LoadPoster(ctx); err != nil {
return nil, err
}
for _, u := range uniqUsers {
if u.ID != issue.Poster.ID {
comment, err := issues_model.AddReviewRequest(ctx, issue, u, issue.Poster)
if err != nil {
log.Warn("Failed add assignee user: %s to PR review: %s#%d, error: %s", u.Name, pr.BaseRepo.Name, pr.ID, err)
return nil, err
}
notifiers = append(notifiers, &ReviewRequestNotifier{
Comment: comment,
IsAdd: true,
Reviwer: u,
})
}
}
for _, t := range uniqTeams {
comment, err := issues_model.AddTeamReviewRequest(ctx, issue, t, issue.Poster)
if err != nil {
log.Warn("Failed add assignee team: %s to PR review: %s#%d, error: %s", t.Name, pr.BaseRepo.Name, pr.ID, err)
return nil, err
}
notifiers = append(notifiers, &ReviewRequestNotifier{
Comment: comment,
IsAdd: true,
ReviewTeam: t,
})
}
return notifiers, nil
}
+1 -1
View File
@@ -82,7 +82,7 @@ func mailIssueCommentToParticipants(ctx *mailCommentContext, mentions []*user_mo
// =========== Repo watchers ===========
// Make repo watchers last, since it's likely the list with the most users
if !(ctx.Issue.IsPull && ctx.Issue.PullRequest.IsWorkInProgress() && ctx.ActionType != activities_model.ActionCreatePullRequest) {
if !(ctx.Issue.IsPull && ctx.Issue.PullRequest.IsWorkInProgress(ctx) && ctx.ActionType != activities_model.ActionCreatePullRequest) {
ids, err = repo_model.GetRepoWatchersIDs(ctx, ctx.Issue.RepoID)
if err != nil {
return fmt.Errorf("GetRepoWatchersIDs(%d): %w", ctx.Issue.RepoID, err)
+1 -1
View File
@@ -79,7 +79,7 @@ func (m *mailNotifier) IssueChangeTitle(ctx context.Context, doer *user_model.Us
log.Error("issue.LoadPullRequest: %v", err)
return
}
if issue.IsPull && issues_model.HasWorkInProgressPrefix(oldTitle) && !issue.PullRequest.IsWorkInProgress() {
if issue.IsPull && issues_model.HasWorkInProgressPrefix(oldTitle) && !issue.PullRequest.IsWorkInProgress(ctx) {
if err := MailParticipants(ctx, issue, doer, activities_model.ActionPullRequestReadyForReview, nil); err != nil {
log.Error("MailParticipants: %v", err)
}
+5
View File
@@ -72,6 +72,11 @@ func (g *GitBucketDownloader) LogString() string {
// NewGitBucketDownloader creates a GitBucket downloader
func NewGitBucketDownloader(ctx context.Context, baseURL, userName, password, token, repoOwner, repoName string) *GitBucketDownloader {
githubDownloader := NewGithubDownloaderV3(ctx, baseURL, userName, password, token, repoOwner, repoName)
// Gitbucket 4.40 uses different internal hard-coded perPage values.
// Issues, PRs, and other major parts use 25. Release page uses 10.
// Some API doesn't support paging yet. Sounds difficult, but using
// minimum number among them worked out very well.
githubDownloader.maxPerPage = 10
githubDownloader.SkipReactions = true
githubDownloader.SkipReviews = true
return &GitBucketDownloader{

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