Compare commits

...

141 Commits

Author SHA1 Message Date
Henry Goodman 21ef7c3a90
Merge a55d21700d into 880e0b7c82 2024-05-07 22:41:57 +10:00
Kemal Zebari 880e0b7c82
Apply to become a maintainer (#30884)
Hello! After contributing for some time I am interested in taking a more
involved role as a maintainer. When time allows it, I plan to perform
code reviews, continue resolving/triaging issues, and engage with the
community to see if I can offer any useful insights. My current
interests are in backend work, but I plan to study the web frontend
architecture to see if I can contribute there as well.

Thanks for this awesome project. I hope I can both learn and contribute
to its continued success!

PR list:
https://github.com/go-gitea/gitea/pulls?q=is%3Apr+is%3Aclosed+author%3Akemzeb
Discord: kemzeb
2024-05-07 14:41:52 +02:00
Henry Goodman a55d21700d
Merge branch 'main' into allow-force-push-protected-branches 2024-05-07 20:25:50 +10:00
wxiaoguang 67c1a07285
Refactor AppURL usage (#30885)
Fix #30883
Fix #29591

---------

Co-authored-by: KN4CK3R <admin@oldschoolhack.me>
2024-05-07 08:26:13 +00:00
Lunny Xiao ebf0c96940
Move database operations of merging a pull request to post receive hook and add a transaction (#30805)
Merging PR may fail because of various problems. The pull request may
have a dirty state because there is no transaction when merging a pull
request. ref
https://github.com/go-gitea/gitea/pull/25741#issuecomment-2074126393

This PR moves all database update operations to post-receive handler for
merging a pull request and having a database transaction. That means if
database operations fail, then the git merging will fail, the git client
will get a fail result.

There are already many tests for pull request merging, so we don't need
to add a new one.

---------

Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2024-05-07 07:36:48 +00:00
Lunny Xiao 6ad77125ca
Fix missing migrate actions artifacts (#30874)
The actions artifacts should be able to be migrate to the new storage
place.
2024-05-07 06:45:30 +00:00
wxiaoguang 9c08637eae
Make "sync branch" also sync object format and add tests (#30878) 2024-05-06 17:02:30 +00:00
wxiaoguang 7c613f100e
Make sure git version&feature are always prepared (#30877)
Otherwise there would be more similar issues like #29287
2024-05-06 18:34:16 +02:00
6543 8e8ca6c653
Get repo list with OrderBy alpha should respect owner too (#30784)
instead of:
- zowner/gcode
- awesome/nul
- zowner/nul
- zowner/zzz

we will get:
- awesome/nul
- zowner/gcode
- zowner/nul
- zowner/zzz
2024-05-06 16:36:02 +02:00
wxiaoguang eda10cc2bb
Fix some UI problems (dropdown/container) (#30849)
Follow #30345
Follow #30547

`ellipsis` / `white-space` shouldn't be put on the general dropdown components.
2024-05-06 07:17:22 +00:00
wxiaoguang ce8b11ae13
Fix some UI problems (install/checkbox) (#30854)
Fix the space between the box and label for checkboxes, and fix incorrect usages in "repo-issue.js"
2024-05-06 06:32:05 +00:00
Kemal Zebari 22c7b3a744
Have time.js use UTC-related getters/setters (#30857)
Before this patch, we were using `Date` getter/setter methods that
worked with local time to get a list of Sundays that are in the range of
some start date and end date. The problem with this was that the Sundays
are in Unix epoch time and when we changed the "startDate" argument that
was passed to make sure it is on a Sunday, this change would be
reflected when we convert it to Unix epoch time. More specifically, I
observed that we may get different Unix epochs depending on your
timezone when the returned list should rather be timezone-agnostic.

This led to issues in US timezones that caused the contributor, code
frequency, and recent commit charts to not show any chart data. This fix
resolves this by using getter/setter methods that work with UTC since it
isn't dependent on timezones.

Fixes #30851.

---------

Co-authored-by: Sam Fisher <fisher@3echelon.local>
2024-05-06 09:36:53 +08:00
wxiaoguang 982b20d259
Do not show monaco JS errors (#30862)
Fix #30861
2024-05-05 16:34:13 +00:00
wxiaoguang 5c236bd4c0
Fix issue/PR title edit (#30858)
1. "enter" doesn't work (I think it is the last enter support for #14843)
2. if a branch name contains something like `&`, then the branch selector doesn't update
2024-05-05 13:09:41 +00:00
yp05327 ecd1d96f49
Add result check in TestAPIEditUser (#29674)
Fix #29514
There are too many usage of `NewRequestWithValues`, so there's no need
to check all of them.
Just one is enough I think.
2024-05-05 02:10:20 +00:00
Neal Caffery bb0e4ce581
Update README.md (#30856)
fix typo for the Docker README
2024-05-03 23:53:18 -04:00
wxiaoguang c7bb3aa034
Fix markdown URL parsing for commit ID (#30812) 2024-05-04 09:48:16 +08:00
wxiaoguang 0f3e717a1a
Improve grep search (#30843)
Reduce the context line number to 1, make "git grep" search respect the
include/exclude patter, and fix #30785
2024-05-03 09:13:48 +00:00
Kemal Zebari 9f0ef3621a
Don't only list code-enabled repositories when using repository API (#30817)
We should be listing all repositories by default.

Fixes #28483.
2024-05-03 15:58:31 +08:00
yp05327 a50026e2f3
Fix no edit history after editing issue's title and content (#30814)
Fix #30807

reuse functions in services
2024-05-03 14:11:51 +08:00
wxiaoguang 53b55223d1
Ignore useless error message "broken pipe" (#30801)
Fix #30792
2024-05-03 02:39:36 +00:00
silverwind c4e875402b
Fix JS error on pull request page (#30838)
Fix this error seen on PR page, regression from
https://github.com/go-gitea/gitea/pull/30803:

Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2024-05-03 10:12:10 +08:00
silverwind b30b7df9f4
Fix body margin shifting with modals, fix error on project column edit (#30831)
Fixes: https://github.com/go-gitea/gitea/issues/30816, regression from
https://github.com/go-gitea/gitea/pull/30723.
Fixes: https://github.com/go-gitea/gitea/pull/30815, regression from
https://github.com/go-gitea/gitea/pull/30723.

Fomantic [expects a
callback](59d9b40987/src/definitions/modules/modal.js (L530-L534))
to be called during `hide` which we did not do, so it could never remove
the margin it added to `body`.

I do observe the body content shifting to right by 1px when modal opens,
but this is a bug that existed on v1.21 as well, so not a regression.

---------

Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2024-05-03 01:48:24 +00:00
silverwind c445a85528
Improve repo button row layout (#30668)
Since there is now a second `<input>` in the repo buttons, we can make a
better-looking layout with no empty space, except on mobile.

Also I fixed one bug with focus border on clone panel.

## Large

<img width="1163" alt="Screenshot 2024-04-23 at 22 25 22"
src="https://github.com/go-gitea/gitea/assets/115237/8135a572-aa67-4672-ad49-b76b06890b52">

## Medium
<img width="870" alt="Screenshot 2024-04-23 at 22 25 34"
src="https://github.com/go-gitea/gitea/assets/115237/9e93f61c-3315-4a78-8328-8cefad5b50fa">

## Mobile
<img width="416" alt="Screenshot 2024-04-23 at 22 25 52"
src="https://github.com/go-gitea/gitea/assets/115237/859e341f-807a-48e6-8bcf-31715963216c">
2024-05-02 19:10:49 +00:00
Bo-Yi Wu e67fbe4f15
refactor: merge ListActionTasks func to action.go file (#30811)
Just merge actions.go file to action.go

Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>
2024-05-02 17:43:29 +00:00
Archer 5c542ca94c
Prevent automatic OAuth grants for public clients (#30790)
This commit forces the resource owner (user) to always approve OAuth 2.0
authorization requests if the client is public (e.g. native
applications).

As detailed in [RFC 6749 Section 10.2](https://www.rfc-editor.org/rfc/rfc6749.html#section-10.2),

> The authorization server SHOULD NOT process repeated authorization
requests automatically (without active resource owner interaction)
without authenticating the client or relying on other measures to ensure
that the repeated request comes from the original client and not an
impersonator.

With the implementation prior to this patch, attackers with access to
the redirect URI (e.g., the loopback interface for
`git-credential-oauth`) can get access to the user account without any
user interaction if they can redirect the user to the
`/login/oauth/authorize` endpoint somehow (e.g., with `xdg-open` on
Linux).

Fixes #25061.

Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2024-05-02 17:05:59 +00:00
Kemal Zebari 872caa17c0
Catch and handle unallowed file type errors in issue attachment API (#30791)
Before, we would just throw 500 if a user passes an attachment that is
not an allowed type. This commit catches this error and throws a 422
instead since this should be considered a validation error.
2024-05-02 16:33:31 +00:00
wxiaoguang 677032d36a
Fix incorrect message id for releaes email (#30825)
Make generateMessageIDForRelease outputs the same format as
generateMessageIDForIssue (old `createReference`)
2024-05-02 15:24:21 +00:00
silverwind 6f89d5e3a0
Add hover outline to heatmap squares (#30828)
Makes it easier to use because you see which square is currently
hovered:

<img width="314" alt="Screenshot 2024-05-02 at 15 38 20"
src="https://github.com/go-gitea/gitea/assets/115237/3a15dad1-2259-4f28-9fae-5cf6ad3d8798">

I did try a `scoped` style for this, but that did not work for some
reason.
2024-05-02 14:56:17 +00:00
silverwind 9235442ba5
Remove external API calls in `TestPassword` (#30716)
The test had a dependency on `https://api.pwnedpasswords.com` which
caused many failures on CI recently:

```
--- FAIL: TestPassword (2.37s)
    pwn_test.go:41: Get "https://api.pwnedpasswords.com/range/e6b6a": context deadline exceeded (Client.Timeout exceeded while awaiting headers)
FAIL
coverage: 82.9% of statements
```
2024-05-02 14:43:23 +00:00
Lunny Xiao cb9e1a3ff6
Upgrade chi-binding (#30826)
Front port #30742
2024-05-02 14:09:38 +00:00
silverwind b1bb3642e5
Improve context popup rendering (#30824)
Before, lot of empty space when no labels or body:

<img width="281" alt="Screenshot 2024-05-02 at 13 51 29"
src="https://github.com/go-gitea/gitea/assets/115237/8a980ccd-d53c-43a3-a059-dc8c614621e1">

After, empty space collapsed:

<img width="306" alt="Screenshot 2024-05-02 at 13 51 16"
src="https://github.com/go-gitea/gitea/assets/115237/8d9c154d-5de1-43d0-8536-afd9194d99b3">

All `<p>` (unsuitable) and `<small>` (discouraged in favor of css) tags
are removed.
2024-05-02 15:42:33 +02:00
wxiaoguang eb8bb82e58
Fix activity heat map padding & locale (#30823)
Fix #30808

---------

Co-authored-by: silverwind <me@silverwind.io>
2024-05-02 13:22:55 +00:00
wxiaoguang 6ff2acc52c
Fix issue card layout (#30800)
Fix #30788
2024-05-02 11:19:44 +00:00
wxiaoguang ebe6f4cad7
Fix branch selector UI (#30803)
Fix  #30802
2024-05-02 10:45:23 +00:00
silverwind 82eca44581
Fix rounded border for segment followed by pagination (#30809)
Fixes https://github.com/go-gitea/gitea/issues/30673, specifically
https://github.com/go-gitea/gitea/issues/30673#issuecomment-2085329812.
2024-05-02 09:25:55 +00:00
wxiaoguang be112c1fc3
Skip gzip for some well-known compressed file types (#30796)
Co-authored-by: silverwind <me@silverwind.io>
2024-05-02 02:27:25 +00:00
wxiaoguang ce08a9fe2f
Fix markdown rendering when mentioning users (#30795) 2024-05-02 01:00:46 +00:00
wxiaoguang 6f7cd94a02
Fix bleve fuzziness (#30799)
Fix #30797
Fix #30317
2024-05-01 15:32:52 +03:00
Kemal Zebari f135cb7c94
Don't have `redis-cluster` as possible cache/session adapter in docs (#30794)
This is because it doesn't exist as an adapter. The `redis` adapter
already handles Redis cluster configurations.

Fixes #30534.
2024-05-01 05:33:40 +00:00
Chester 6709e28da7
Add API endpoints for getting action jobs status (#26673)
Sample of response, it is similar to Github actions

ref
https://docs.github.com/en/rest/actions/workflow-runs?apiVersion=2022-11-28#list-workflow-runs-for-a-repository

``` json
{
    "workflow_runs": [
        {
            "id": 3,
            "name": "Explore-Gitea-Actions",
            "head_branch": "main",
            "head_sha": "6d8d29a9f7a01ded8f8aeb64341cb31ee1ab5f19",
            "run_number": 3,
            "event": "push",
            "display_title": "More job",
            "status": "success",
            "workflow_id": "demo2.yaml",
            "url": "/chester/test/actions/runs/3",
            "created_at": "2023-08-22T13:41:33-04:00",
            "updated_at": "2023-08-22T13:41:37-04:00",
            "run_started_at": "2023-08-22T13:41:33-04:00"
        },
        {
            "id": 2,
            "name": "Explore-Gitea-Actions",
            "head_branch": "main",
            "head_sha": "6d8d29a9f7a01ded8f8aeb64341cb31ee1ab5f19",
            "run_number": 2,
            "event": "push",
            "display_title": "More job",
            "status": "success",
            "workflow_id": "demo.yaml",
            "url": "/chester/test/actions/runs/2",
            "created_at": "2023-08-22T13:41:30-04:00",
            "updated_at": "2023-08-22T13:41:33-04:00",
            "run_started_at": "2023-08-22T13:41:30-04:00"
        },
        {
            "id": 1,
            "name": "Explore-Gitea-Actions",
            "head_branch": "main",
            "head_sha": "e5369ab054cae79899ba36e45ee82811a6e0acd5",
            "run_number": 1,
            "event": "push",
            "display_title": "Add job",
            "status": "failure",
            "workflow_id": "demo.yaml",
            "url": "/chester/test/actions/runs/1",
            "created_at": "2023-08-22T13:15:21-04:00",
            "updated_at": "2023-08-22T13:18:10-04:00",
            "run_started_at": "2023-08-22T13:15:21-04:00"
        }
    ],
    "total_count": 3
}
```

---------

Co-authored-by: yp05327 <576951401@qq.com>
Co-authored-by: puni9869 <80308335+puni9869@users.noreply.github.com>
2024-05-01 09:40:23 +08:00
GiteaBot d8d46d1c48 [skip ci] Updated translations via Crowdin 2024-05-01 00:26:38 +00:00
wxiaoguang a988237eb4
Improve logout from worker (#30775)
A quick fix for #30756
2024-04-30 15:35:42 +00:00
silverwind 564102ce89
Rework and fix stopwatch (#30732)
Fixes https://github.com/go-gitea/gitea/issues/30721 and overhauls the
stopwatch. Time is now shown inside the "dot" icon and on both mobile
and desktop. All rendering is now done by `<relative-time>`, the
`pretty-ms` dependency is dropped.

Desktop:
<img width="557" alt="Screenshot 2024-04-29 at 22 33 27"
src="https://github.com/go-gitea/gitea/assets/115237/3a46cdbf-6af2-4bf9-b07f-021348badaac">

Mobile:
<img width="640" alt="Screenshot 2024-04-29 at 22 34 19"
src="https://github.com/go-gitea/gitea/assets/115237/8a2beea7-bd5d-473f-8fff-66f63fd50877">

Note for tippy:
Previously, tippy instances defaulted to "menu" theme, but that theme is
really only meant for `.ui.menu`, so it was not optimal for the
stopwatch popover.

This introduces a unopinionated `default` theme that has no padding and
should be suitable for all content. I reviewed all existing uses and
explicitely set the desired `theme` on all of them.
2024-04-30 14:52:46 +00:00
wxiaoguang 5f05e7b41a
Fix dashboard commit status null access (#30771)
Fix #30768
2024-04-30 12:39:36 +00:00
silverwind 610802df85
Fix tautological conditions (#30735)
As discovered by https://github.com/go-gitea/gitea/pull/30729.

---------

Co-authored-by: Giteabot <teabot@gitea.io>
2024-04-30 14:34:40 +02:00
6543 f2d8ccc5bb
Get repo assignees and reviewers should ignore deactivated users (#30770)
If an user is deactivated, it should not be in the list of users who are
suggested to be assigned or review-requested.

old assignees or reviewers are not affected.

---
*Sponsored by Kithara Software GmbH*
2024-04-30 08:43:08 +00:00
wxiaoguang 059b2718a5
Right align the "Settings" menu item in overflow-menu (#30764)
I guess there could be enough people liking to make the Settings menu
item right aligned. As a site admin, I found it's easier to find the
right-aligned Settings menu item.

Tested with various sizes:

![image](https://github.com/go-gitea/gitea/assets/2114189/92836527-2cb2-4531-9296-233c5bd698f4)

![image](https://github.com/go-gitea/gitea/assets/2114189/3a0729fc-5e33-44b5-9fb4-3a4e787405b5)

![image](https://github.com/go-gitea/gitea/assets/2114189/9845ab6b-88e3-4e5a-8d6d-2b8af259d593)
2024-04-30 04:26:13 +00:00
Zettat123 7ad5031328
Fix duplicate status check contexts (#30660)
Caused by #30076. 

There may be some duplicate status check contexts when setting status
checks for a branch protection rule. The duplicate contexts should be
removed.

Before:
<img
src="https://github.com/go-gitea/gitea/assets/15528715/97f4de2d-4868-47a3-8a99-5a180f9ac0a3"
width="600px" />

After:
<img
src="https://github.com/go-gitea/gitea/assets/15528715/ff7289c5-9793-4090-ba31-e8cb3c85f8a3"
width="600px" />
2024-04-30 11:53:16 +08:00
wxiaoguang 61b495e5ab
Fix issue label rendering in the issue popup (#30763) 2024-04-30 02:36:32 +00:00
silverwind a3d9f0d915
Fix all rounded borders, change affected tab menus to pills (#30707)
Fixes https://github.com/go-gitea/gitea/issues/30673, all 23 issues.
Notes:

- Tab bar menus had to change to pills because of unsolvable issue with
the border-radius as tab bar renders a overlapping border onto the box
below. And I think pills look better.
- Added padding to code editor empty preview message
- Hide monaco's built-in blue focus border, we don't need it and it
never showed before either.
- Label add menu is simplified, removing the nested segment.

<img width="1322" alt="Screenshot 2024-04-25 at 22 26 19"
src="https://github.com/go-gitea/gitea/assets/115237/7e394e0c-b7ad-417d-8e9f-12f1dea93ed1">
<img width="1326" alt="Screenshot 2024-04-25 at 22 28 00"
src="https://github.com/go-gitea/gitea/assets/115237/66c8499f-aa9f-4d95-8cca-ef13dfa82c65">
<img width="997" alt="Screenshot 2024-04-25 at 22 36 53"
src="https://github.com/go-gitea/gitea/assets/115237/07896102-c71d-4246-8173-c2bc2e1d3cae">
<img width="832" alt="Screenshot 2024-04-25 at 22 56 09"
src="https://github.com/go-gitea/gitea/assets/115237/d83afc96-08ca-4adc-baf4-3d02804be57c">
<img width="361" alt="Screenshot 2024-04-25 at 22 57 12"
src="https://github.com/go-gitea/gitea/assets/115237/c7371a68-00b5-47d8-84d0-ddc5268b2b2c">

---------

Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
Co-authored-by: Giteabot <teabot@gitea.io>
2024-04-29 20:53:15 +00:00
wxiaoguang 4daea7c603
Rename CodeIndexerEnabled to IsRepoIndexerEnabled (#30762)
Fix  #30761

Most places use `IsRepoIndexerEnabled` but not `CodeIndexerEnabled`, so
it should always use `IsRepoIndexerEnabled` for consistency.
2024-04-29 20:15:35 +00:00
silverwind a21ca9b5a5
Remove fomantic dimmer module (#30723)
Tested extensively using modal which is the only dependant.
2024-04-29 14:49:50 +00:00
Chongyi Zheng e80466f734
Resolve lint for unused parameter and unnecessary type arguments (#30750)
Resolve all cases for `unused parameter` and `unnecessary type
arguments`

Related: #30729

---------

Co-authored-by: Giteabot <teabot@gitea.io>
2024-04-29 08:47:56 +00:00
Micash ad4e902d5a
Add support for npm bundleDependencies (#30751) 2024-04-29 16:19:06 +08:00
Sergey Zolotarev d11133b836
Fix cross-compilation errors when CGO_CFLAGS/CGO_LDFLAGS is set (#30749)
When you cross-compile Gitea and you specify one of the envrionment
variables related to C flags, cgo will fail to build the generator
programs (e.g. generate-bindata) because GOOS and GOARCH are unset, but
those additional flags variables are not unset together with those.

To solve this issue, the simplest way that I've found is to disable cgo
in the `go generate` command as it's not really used there.

For example, I've had this problem with cross-compiling Gitea on FreeBSD
x86_64 to ARMv7 where it's necessary to pass `--target` to `clang` via
`CGO_CFLAGS`:
```
GOOS=freebsd \
GOARCH=arm \
GGOARM=7 \
CGO_ENABLED=1 \
SYSROOT=/usr/local/freebsd-sysroot/armv7 \
CC=clang \
CGO_CFLAGS="--target=armv7-unknown-freebsd13.2-gnueabihf" \
TAGS="bindata sqlite sqlite_unlock_notify" \
make SHELL='sh -x' build
```

```
Running go generate...
# runtime/cgo
In file included from gcc_freebsd_amd64.c:9:
In file included from /usr/include/signal.h:42:
/usr/include/sys/_ucontext.h:44:2: error: unknown type name 'mcontext_t'
modules/migration/schemas_bindata.go:8: running "go": exit status 1
# runtime/cgo
In file included from gcc_freebsd_amd64.c:9:
In file included from /usr/include/signal.h:42:
/usr/include/sys/_ucontext.h:44:2: error: unknown type name 'mcontext_t'
modules/options/options_bindata.go:8: running "go": exit status 1
# runtime/cgo
In file included from gcc_freebsd_amd64.c:9:
In file included from /usr/include/signal.h:42:
/usr/include/sys/_ucontext.h:44:2: error: unknown type name 'mcontext_t'
modules/public/public_bindata.go:8: running "go": exit status 1
# runtime/cgo
In file included from gcc_freebsd_amd64.c:9:
In file included from /usr/include/signal.h:42:
/usr/include/sys/_ucontext.h:44:2: error: unknown type name 'mcontext_t'
modules/templates/templates_bindata.go:8: running "go": exit status 1
gmake[1]: *** [Makefile:781: generate-go] Error 1
*** Error code 2

Stop.
```

But with this fix Gitea compiles successfully.
2024-04-29 03:45:53 +00:00
GiteaBot e67141756d [skip ci] Updated licenses and gitignores 2024-04-29 00:25:01 +00:00
silverwind d89bf3d3ec
add built js files to eslint ignore (#30737)
For the rare case that some overzealous tooling wants to lint our output
files.
2024-04-28 22:27:14 +08:00
mainboarder 81a0a031f5
Gitea with first upper case + typos (#30739)
* Corrected gitea to Gitea
* fixed some typos
2024-04-28 21:01:22 +08:00
Lunny Xiao daf841fe14
Fix documentation build problems because of MDX syntax conflicts (#30744)
Documentation building has encountered a problem like below. This is
because MDX syntax doesn't allow `{customPath}`, we have to use
\`{customPath}\`

```
Error: Can't render static file for pathname "/next/administration/config-cheat-sheet"
            at generateStaticFile (/workspace/gitea/gitea-docusaurus/node_modules/@docusaurus/core/lib/ssg.js:119:15)
            at runNextTicks (node:internal/process/task_queues:60:5)
            at process.processImmediate (node:internal/timers:449:9)
            at async /workspace/gitea/gitea-docusaurus/node_modules/p-map/index.js:57:22 {
          [cause]: ReferenceError: CustomPath is not defined
              at _createMdxContent (server.bundle.js:4406:106)
              at MDXContent (server.bundle.js:10745:8)
              at Uc (server.bundle.js:264171:44)
              at Xc (server.bundle.js:264173:253)
              at Z (server.bundle.js:264179:89)
              at Yc (server.bundle.js:264182:98)
              at $c (server.bundle.js:264181:140)
              at Z (server.bundle.js:264179:345)
              at Xc (server.bundle.js:264177:231)
              at Z (server.bundle.js:264179:89)
```
2024-04-28 20:36:14 +08:00
Chongyi Zheng 9a0b449c4f
Remove disk-clean workflow (#30741)
The jobs in the workflow runs in parallel. The `disk-clean` job actually
does nothing, i.e. it will not clean the disk for `nightly-binary`,
`nightly-docker-rootful`, `nightly-docker-rootless`
2024-04-28 05:47:48 +00:00
Chongyi Zheng b2013be910
Bump `github.com/google/go-github` to v61 (#30738) 2024-04-28 01:20:23 -04:00
Chongyi Zheng 970965f6d8
Fix nil dereference on error (#30740)
In both cases, the `err` is nil because of `if` checks before

Reference: #30729
2024-04-28 12:13:57 +08:00
Chongyi Zheng 8b8b48ef5f
Use `ProtonMail/go-crypto` for `opengpg` in tests (#30736) 2024-04-27 19:21:33 -04:00
Chongyi Zheng 7b8e418da1
Replace deprecated `math/rand` functions (#30733)
Suggested by logs in #30729

- Remove `math/rand.Seed`
`rand.Seed is deprecated: As of Go 1.20 there is no reason to call Seed
with a random value.`
- Replace `math/rand.Read`
`rand.Read is deprecated: For almost all use cases, [crypto/rand.Read]
is more appropriate.`
- Replace `math/rand` with `math/rand/v2`, which is available since Go
1.22
2024-04-27 18:50:35 +02:00
wxiaoguang 8de2992ffb
Make Ctrl+Enter work for issue/comment edit (#30720)
Fix #30710
2024-04-27 14:32:00 +00:00
wxiaoguang 6d2a307ad8
Rename migration package name for 1.22-rc1 (#30730)
Ref: Propose to restart 1.22 release #30501
2024-04-27 14:02:07 +00:00
silverwind b93c87b6fe
Issue card improvements (#30687)
Fixes https://github.com/go-gitea/gitea/issues/30682 and does a few
improvements:

- Use gap instead of margin/padding
- Don't render empty image div
- Remove `right floated` class that did nothing

<img width="406" alt="Screenshot 2024-04-24 at 20 21 20"
src="https://github.com/go-gitea/gitea/assets/115237/2fa88707-c2c4-40df-aee7-a684c3097ed0">

---------

Co-authored-by: KN4CK3R <admin@oldschoolhack.me>
2024-04-27 13:35:26 +00:00
Yarden Shoham 51c28d9683
Don't show loading indicators when refreshing the system status (#30712)
Signed-off-by: Yarden Shoham <git@yardenshoham.com>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
Co-authored-by: silverwind <me@silverwind.io>
2024-04-27 13:05:06 +00:00
wxiaoguang d3cdef88ad
Add some tests to clarify the "must-change-password" behavior (#30693)
Follow  #30472:

When a user is created by command line `./gitea admin user create`:

Old behavior before #30472: the first user (admin or non-admin) doesn't
need to change password.

Revert to the old behavior before #30472
2024-04-27 12:23:37 +00:00
Kemal Zebari dd301cae1c
Prevent allow/reject reviews on merged/closed PRs (#30686)
Resolves #30675.
2024-04-27 11:55:03 +00:00
silverwind 238eb3ff9f
Update JS dependencies (#30713)
- Update all JS dependencies
- Remove
[now-unnecessary](https://github.com/microsoft/monaco-editor/issues/4325)
monaco workaround
- Update stylelint config for new rule
- Tested Monaco, Swagger UI, Mermaid
2024-04-27 11:28:28 +00:00
silverwind b2abac5e5f
Improve diff stats bar (#30669)
Minor tweaks:

- Remove unnecessary `item` class which was causing unwanted padding to
be added.
- Add some padding and prevent wrapping so it looks better on mobile.
- Increase width by 4px.

<img width="116" alt="Screenshot 2024-04-24 at 00 15 07"
src="https://github.com/go-gitea/gitea/assets/115237/1f1cf54c-8053-4297-b309-71d9c2ceb9ee">
<img width="441" alt="Screenshot 2024-04-24 at 00 14 57"
src="https://github.com/go-gitea/gitea/assets/115237/2f3a33dc-edad-4b97-b64c-6812aae513cb">
2024-04-27 11:22:55 +00:00
Chongyi Zheng 4ae6b1a553
Remove unused parameter for some functions in `services/mirror` (#30724)
Suggested by gopls `unusedparams`
2024-04-27 10:44:49 +00:00
silverwind 9b2536b78f
Update misspell to 0.5.1 and add `misspellings.csv` (#30573)
Misspell 0.5.0 supports passing a csv file to extend the list of
misspellings, so I added some common ones from the codebase. There is at
least one typo in a API response so we need to decided whether to revert
that and then likely remove the dict entry.
2024-04-27 08:03:49 +00:00
silverwind dcc3c17e5c
Suppress browserslist warning in webpack target (#30571)
1. Set
[`BROWSERSLIST_IGNORE_OLD_DATA`](c6ddf7b387/node.js (L400))
to avoid warning on outdated browserslist data which the end user can
likely not do anything about and which is currently visible in the v1.21
branch.
2. Suppress all command echoing and add a "Running webpack..." message
in place.

Warning in question was this:

```
Browserslist: caniuse-lite is outdated. Please run:
  npx update-browserslist-db@latest
  Why you should do it regularly: https://github.com/browserslist/update-db#readme
```
2024-04-27 07:21:07 +00:00
GiteaBot 27861d711b [skip ci] Updated translations via Crowdin 2024-04-27 00:24:31 +00:00
silverwind c93eefb42b
Diff color enhancements, add line number background (#30670)
1. Bring back the background on line numbers. This feature was lost a
long time ago.

<img width="457" alt="Screenshot 2024-04-24 at 01 36 09"
src="https://github.com/go-gitea/gitea/assets/115237/76a7f5a9-c22a-4c72-9f0a-ebf16a66513e">
<img width="473" alt="Screenshot 2024-04-24 at 01 22 47"
src="https://github.com/go-gitea/gitea/assets/115237/eef06cf2-f1b9-40e3-947d-dd5852ec12a3">
<img width="457" alt="Screenshot 2024-04-24 at 02 13 18"
src="https://github.com/go-gitea/gitea/assets/115237/59e317d4-76a7-468c-8a19-10d88c675cc3">
<img width="459" alt="Screenshot 2024-04-24 at 01 23 21"
src="https://github.com/go-gitea/gitea/assets/115237/f1a46f8d-8846-4d78-a9d7-8b7dc18ac6e4">

2. Expanded lines background is now full-line, including line numbers:

<img width="1303" alt="Screenshot 2024-04-24 at 01 37 12"
src="https://github.com/go-gitea/gitea/assets/115237/271eefe2-0869-424e-93fb-ccd8adc87806">

3. Sort affected colors alphabetically in the CSS

Fixes #14603
2024-04-26 19:37:21 +00:00
Bo-Yi Wu 852547d0dc
feat(api): enhance Actions Secrets Management API for repository (#30656)
- Add endpoint to list repository action secrets in API routes
- Implement `ListActionsSecrets` function to retrieve action secrets
from the database
- Update Swagger documentation to include the new
`/repos/{owner}/{repo}/actions/secrets` endpoint
- Add `actions` package import and define new routes for actions,
secrets, variables, and runners in `api.go`.
- Refactor action-related API functions into `Action` struct methods in
`org/action.go` and `repo/action.go`.
- Remove `actionAPI` struct and related functions, replacing them with
`NewAction()` calls.
- Rename `variables.go` to `action.go` in `org` directory.
- Delete `runners.go` and `secrets.go` in both `org` and `repo`
directories, consolidating their content into `action.go`.
- Update copyright year and add new imports in `org/action.go`.
- Implement `API` interface in `services/actions/interface.go` for
action-related methods.
- Remove individual action-related functions and replace them with
methods on the `Action` struct in `repo/action.go`.

---------

Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>
Signed-off-by: appleboy <appleboy.tw@gmail.com>
2024-04-26 21:11:49 +08:00
wxiaoguang 993736d838
Fix code search input for different views (#30678)
Now only show the "code search" on the repo home page, because it only
does global search.
So do not show it when viewing file or directory to avoid misleading
users (it doesn't search in a directory)
2024-04-26 11:21:04 +00:00
wxiaoguang cd70ab31cd
Fix incorrect object id hash function (#30708)
Great thanks to @oliverpool for figuring out the problem and proposing a
fix.

Regression of #28138

Incorrect hash causes the user's LFS files get all deleted when running
`doctor fix all`

(by the way, remove unused/non-standard comments)

Co-authored-by: Giteabot <teabot@gitea.io>
2024-04-26 09:49:48 +00:00
wxiaoguang 1e749b80d7
Add route handler info for debugging purpose (#30705)
Follow #30519
2024-04-26 09:09:49 +00:00
Yarden Shoham 68a3e6b5e6
Bump htmx version to 1.9.12 (#30711)
There are no breaking changes. I tested and everything works as before.

Signed-off-by: Yarden Shoham <git@yardenshoham.com>
2024-04-26 09:27:34 +02:00
wxiaoguang ed8c63cea3
Deduplicate lfs common code (#30704) 2024-04-26 02:53:30 +00:00
yp05327 2a3906d755
Improve job commit description (#30579)
Fix https://github.com/go-gitea/gitea/issues/30567

When job is a schedule:

![image](https://github.com/go-gitea/gitea/assets/18380374/b07e9d43-e8b7-4ee2-87b3-a7050c3a8ca5)
When it is a normal one:

![image](https://github.com/go-gitea/gitea/assets/18380374/0d58dab9-74bb-421b-8952-0578cdf21a52)

also add a 'space' behind  `:`

![image](https://github.com/go-gitea/gitea/assets/18380374/4cebece0-bfe6-4ad9-b806-e5c49bb9be43)


![image](https://github.com/go-gitea/gitea/assets/18380374/02da7681-474b-4c0f-9dad-b6558f6cb484)

---------

Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2024-04-26 02:22:45 +00:00
Lunny Xiao 2a6418abb1
Improve test for TestPullCompare (#30699) 2024-04-26 01:52:28 +00:00
wxiaoguang 6a0750177f
Allow to save empty comment (#30706)
Fix #29986
2024-04-26 01:17:43 +00:00
GiteaBot 935330b1b9 [skip ci] Updated translations via Crowdin 2024-04-26 00:26:00 +00:00
wxiaoguang fd63b96f6a
Refactor imagediff and fix regression bug (#30694)
Fix #30683
2024-04-25 21:01:38 +08:00
wxiaoguang bffbbf5470
Improve oauth2 client "preferred username field" logic and the error handling (#30622)
Follow #30454
And fix #24957

When using "preferred_username", if no such field,
`extractUserNameFromOAuth2` (old `getUserName`) shouldn't return an
error. All other USERNAME options do not return such error.

And fine tune some logic and error messages, make code more stable and
more friendly to end users.
2024-04-25 11:22:32 +00:00
silverwind d0bfc978de
Fix active item in tab menu (#30690)
Before, item would also resize on hover because of font weight:
<img width="381" alt="Screenshot 2024-04-25 at 01 28 53"
src="https://github.com/go-gitea/gitea/assets/115237/4f3291fc-90be-4d66-ae8b-3c2f763cb956">

After:
<img width="381" alt="Screenshot 2024-04-25 at 01 28 40"
src="https://github.com/go-gitea/gitea/assets/115237/06145bf2-1ddd-4171-9217-d92c100ea405">

Co-authored-by: Giteabot <teabot@gitea.io>
2024-04-25 12:53:39 +02:00
Lunny Xiao c685eefe4a
If a repository return no commitstatus, then still cache it but not query it from database (#30700)
The previous repository default branch commit status cache will only
store if the commit status has value. So the repository which have no
any commit status will always be fetched from database.

This PR will store the empty state of commit status of a repository into
cache because the cache will be updated once there is a commit status
stored.
2024-04-25 17:14:23 +08:00
GiteaBot 4ff54933f8 [skip ci] Updated translations via Crowdin 2024-04-25 00:26:13 +00:00
Jiaxin Zhu a63f14b908
Fix view of readme file in the home code page. (#30564)
Gitea attempts to display image file, pdf file, etc. named readme in the
home code page (but it cannot).
I think only the markdown and plain-text file should be displayed, which
is also the behavior of GitHub.

Co-authored-by: jxshin <zhujiaxinabc@gmail.com>
2024-04-25 00:07:38 +00:00
Lunny Xiao a19d2bbd90
Add test for #30674 (#30679) 2024-04-24 14:11:49 +00:00
silverwind 3f19a63345
Fix border-radius of header+segment boxes (#30667)
This is a very old bug with the bottom border-radiuses not being there
and the `:has` selector now makes it possible to cleanly solve it. It
affects all header+segment boxes, which there are many throughout the
UI:

<img width="1017" alt="Screenshot 2024-04-23 at 20 47 21"
src="https://github.com/go-gitea/gitea/assets/115237/870fe352-cc38-4bd6-bfe6-9fe8c3066f92">
2024-04-24 13:11:52 +00:00
Lunny Xiao 8b3632435e
Fix a panic bug when head repository deleting (#30674)
When visiting a pull request files which head repository has been
deleted, it will panic because headrepo is nil.
2024-04-24 13:26:50 +08:00
Lunny Xiao 2ad9ef4984
Fix some bug on migrations (#30647)
Fix https://github.com/go-gitea/gitea/pull/23894#discussion_r1573718690
2024-04-24 01:58:24 +00:00
silverwind 1a2ae64b16
Fix checkbox field markup (#30666)
Fixes https://github.com/go-gitea/gitea/issues/30664.

Previous use was not a supported way by fomantic and the misuse only
became visible after the checkbox migration.
2024-04-23 21:53:57 +00:00
wxiaoguang 2ee93ea178
Avoid doubled border for the PR info segment (#30663) 2024-04-23 19:24:10 +00:00
sillyguodong 2f6b1c46a1
Interpolate runs-on with variables when scheduling tasks (#30640)
Follow #29468
1. Interpolate runs-on with variables when scheduling tasks.
2. The `GetVariablesOfRun` function will check if the `Repo` of the run
is nil.

---------

Co-authored-by: Giteabot <teabot@gitea.io>
2024-04-23 20:55:25 +02:00
wxiaoguang b79e3db264
Initial support for colorblindness-friendly themes (#30625)
Initial support for #25680

This PR only adds some simple styles from GitHub, it is big enough and
it focuses on adding the necessary framework-level supports. More styles
could be fine-tuned later.
2024-04-24 00:18:41 +08:00
wxiaoguang dd2aaadce3
Fix flash message for flex-container (#30657) 2024-04-23 08:31:51 +00:00
Kemal Zebari 9b7af4340c
Perform Newest sort type correctly when sorting issues (#30644)
Should resolve #30642.

Before this commit, we were treating an empty `?sort=` query parameter
as the correct sorting type (which is to sort issues in descending order
by their created UNIX time). But when we perform `sort=latest`, we did
not include this as a type so we would sort by the most recently updated
when reaching the `default` switch statement block.

This commit fixes this by considering the empty string, "latest", and
just any other string that is not mentioned in the switch statement as
sorting by newest.
2024-04-23 15:10:01 +08:00
silverwind 370b1bdb37
Fix project name wrapping, remove horizontal margin on header (#30631)
Enable wrapping of unbroken lines:

<img width="1308" alt="Screenshot 2024-04-22 at 00 31 33"
src="https://github.com/go-gitea/gitea/assets/115237/1a28ade1-d708-4260-96a3-cf508b6dcb79">

Remove extra margin added by nested `.ui.container` on certain
viewports:

Before:
<img width="1305" alt="Screenshot 2024-04-22 at 00 40 23"
src="https://github.com/go-gitea/gitea/assets/115237/d3d8c0d1-380c-4867-b95c-4d53d70d4a93">

After:
<img width="1310" alt="Screenshot 2024-04-22 at 00 40 33"
src="https://github.com/go-gitea/gitea/assets/115237/2ba7b9f2-db2f-4bcc-8cce-5c415625ddea">
2024-04-23 04:17:51 +00:00
Zettat123 30dd4beeee
Add a db consistency check to remove runners that do not belong to a repository (#30614)
Follow #30406
2024-04-23 03:51:52 +00:00
Lunny Xiao e94864e86c
Fix wrong table name (#30557)
The table name should be `oauth2_application` but `o_auth2_application`

Caused by
https://github.com/go-gitea/gitea/pull/21316/files#diff-9610efbc608a41f1f2eaff5790423f0a187906f6ff0beb23a5e8d18366cc2ccfR38
2024-04-23 03:00:57 +00:00
Lunny Xiao 8924d9b2ef
Fix compare api swagger (#30648)
The swagger format on #30349 is not right. This PR will fix it.
2024-04-23 02:22:43 +00:00
GiteaBot 7d5a03fda2 [skip ci] Updated translations via Crowdin 2024-04-23 00:24:55 +00:00
wxiaoguang e6103955cc
Fix queue test (#30646)
Fix #30643

The old test code is not stable due to the data-race described in the
TODO added at that time.

Make it stable, and remove a debug-only field from old test code.
2024-04-22 23:55:43 +00:00
silverwind 99c5683da5
Enable jquery-related eslint rules that have no violations (#30632)
All these have no violations, so enable them.
2024-04-22 14:24:47 +00:00
silverwind 74f0c84fa4
Enable more `revive` linter rules (#30608)
Noteable additions:

- `redefines-builtin-id` forbid variable names that shadow go builtins
- `empty-lines` remove unnecessary empty lines that `gofumpt` does not
remove for some reason
- `superfluous-else` eliminate more superfluous `else` branches

Rules are also sorted alphabetically and I cleaned up various parts of
`.golangci.yml`.
2024-04-22 11:48:42 +00:00
silverwind aff7b7bdd2
Remove obsolete CSS text classes (#30576)
- `.text-thin` and `.text-italic` are not present in CSS so were doing nothing and I removed them.
- `.text.middle` was unused so I removed it.
- `.text.italic` is replaced with `tw-italic`.
- `.text.normal` had exactly one use and it wasn't even needed.
- add a `muted` class to the link to `org_profile_avatar.tmpl`.

---------

Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2024-04-22 11:21:06 +00:00
silverwind 0386a42f70
Hide diff stats on empty PRs (#30629)
When a PR is empty, e.g. has neither additions nor deletions, we don't
need to show this:

<img width="125" alt="Screenshot 2024-04-21 at 23 25 38"
src="https://github.com/go-gitea/gitea/assets/115237/0b987eb5-66f5-4b9b-b5aa-7e9e267e9b52">
2024-04-22 10:48:14 +00:00
GiteaBot 31386dc2bb [skip ci] Updated licenses and gitignores 2024-04-22 00:25:56 +00:00
wxiaoguang 7cb88e9c18
Use correct hash for "git update-index" (#30626) 2024-04-22 00:13:44 +00:00
wxiaoguang f4a1cf7eab
Fix repo home UI when there is no repo description (#30552)
Fix #30502 by a new approach.


![image](https://github.com/go-gitea/gitea/assets/2114189/22f48bca-82d1-45cc-b1b7-ee2344b81a76)
2024-04-21 23:47:31 +00:00
wxiaoguang 1e4867730b
Fix dropdown text ellipsis (#30628)
Follow
https://github.com/go-gitea/gitea/pull/30547#discussion_r1573866519

Fix #30624

The Fomantic UI Dropdown wasn't designed to work that way, its "text"
element might contain images. So the "overflow" shouldn't be added to
any general dropdown text.


![image](https://github.com/go-gitea/gitea/assets/2114189/f6ceaabd-bc89-4bf2-baa2-a6f0324c1962)
2024-04-21 23:14:33 +00:00
Bo-Yi Wu 6459c50278
fix(api): refactor branch and tag existence checks (#30618)
- Update branch existence check to also include tag existence check
- Adjust error message for branch/tag existence check

ref: https://github.com/go-gitea/gitea/pull/30349

---------

Signed-off-by: appleboy <appleboy.tw@gmail.com>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
Co-authored-by: Giteabot <teabot@gitea.io>
2024-04-22 00:19:59 +02:00
Henry Goodman dd2b74d6a7
Fix typo in logging 2024-04-19 21:06:23 +10:00
Henry Goodman b58a3af938
Remove debug log 2024-04-19 21:03:51 +10:00
Henry Goodman d038bc5676
Make format 2024-04-19 20:51:13 +10:00
Henry Goodman a4d344c5b8
Fix whitespace err 2024-04-19 20:35:40 +10:00
Henry Goodman 11acb60343
Merge branch 'main' into allow-force-push-protected-branches 2024-04-19 20:32:32 +10:00
Henry Goodman bf135f1242
Merge branch 'main' into allow-force-push-protected-branches 2024-04-13 18:55:58 +10:00
Henry Goodman 622e87c94a
Merge branch 'main' into allow-force-push-protected-branches 2024-04-05 17:27:28 +11:00
Henry Goodman 996802052a
Merge branch 'main' into allow-force-push-protected-branches 2024-02-17 16:47:15 +11:00
Henry Goodman a06a3e9e5f
Merge branch 'main' into allow-force-push-protected-branches 2024-02-02 18:09:09 +11:00
Henry Goodman 945ea90acd
Merge branch 'main' into allow-force-push-protected-branches 2024-02-02 12:21:35 +11:00
Henry Goodman 5896945109
Use slices.Contains instead of base.Int64sContains 2024-01-31 12:07:31 +11:00
Henry Goodman d102809251
Merge branch 'main' into allow-force-push-protected-branches 2024-01-31 12:06:44 +11:00
Henry Goodman 21cb9bc590
Merge branch 'main' into allow-force-push-protected-branches 2024-01-15 18:33:43 +11:00
Henry Goodman cb057ff2a3
Merge branch 'main' into allow-force-push-protected-branches 2024-01-11 18:59:27 +11:00
Henry Goodman be622e5db9
Merge branch 'main' into allow-force-push-protected-branches 2023-12-19 20:36:12 +11:00
Henry Goodman fdbe77fd8b
Merge branch 'main' into allow-force-push-protected-branches 2023-12-14 23:05:31 +11:00
Henry f28ecbe420 Fix backend dup code lint err and generate swagger 2023-11-24 23:55:11 +11:00
Henry Goodman 2d2bbf28f9 Update strings for clarity 2023-11-24 23:55:11 +11:00
Henry Goodman 7c6cd8b867 Make fmt whitespace fix 2023-11-24 23:55:11 +11:00
Henry Goodman 9da0dc16ad Update RemoveUserIDFromProtectedBranch for forcepush user/team IDs 2023-11-24 23:55:11 +11:00
Henry Goodman f610efa38e Updating label for whitelist deploy keys force push 2023-11-24 23:55:11 +11:00
Henry Goodman 50819b0424 Allow force pushes to protected branches 2023-11-24 23:55:11 +11:00
470 changed files with 5433 additions and 4605 deletions

View File

@ -4,6 +4,7 @@ reportUnusedDisableDirectives: true
ignorePatterns:
- /web_src/js/vendor
- /web_src/fomantic
- /public/assets/js
parserOptions:
sourceType: module
@ -310,7 +311,7 @@ rules:
jquery/no-merge: [2]
jquery/no-param: [2]
jquery/no-parent: [0]
jquery/no-parents: [0]
jquery/no-parents: [2]
jquery/no-parse-html: [2]
jquery/no-prop: [2]
jquery/no-proxy: [2]
@ -319,8 +320,8 @@ rules:
jquery/no-show: [2]
jquery/no-size: [2]
jquery/no-sizzle: [2]
jquery/no-slide: [0]
jquery/no-submit: [0]
jquery/no-slide: [2]
jquery/no-submit: [2]
jquery/no-text: [0]
jquery/no-toggle: [2]
jquery/no-trigger: [0]
@ -458,7 +459,7 @@ rules:
no-jquery/no-other-utils: [2]
no-jquery/no-param: [2]
no-jquery/no-parent: [0]
no-jquery/no-parents: [0]
no-jquery/no-parents: [2]
no-jquery/no-parse-html-literal: [0]
no-jquery/no-parse-html: [2]
no-jquery/no-parse-json: [2]

View File

@ -1,25 +0,0 @@
name: disk-clean
on:
workflow_call:
jobs:
triage:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Free Disk Space (Ubuntu)
uses: jlumbroso/free-disk-space@main
with:
# this might remove tools that are actually needed,
# if set to "true" but frees about 6 GB
tool-cache: false
# all of these default to true, but feel free to set to
# "false" if necessary for your workflow
android: true
dotnet: true
haskell: true
large-packages: false
docker-images: false
swap-storage: true

View File

@ -9,8 +9,6 @@ concurrency:
cancel-in-progress: true
jobs:
disk-clean:
uses: ./.github/workflows/disk-clean.yml
nightly-binary:
runs-on: nscloud
steps:

View File

@ -1,13 +1,14 @@
linters:
enable-all: false
disable-all: true
fast: false
enable:
- bidichk
# - deadcode # deprecated - https://github.com/golangci/golangci-lint/issues/1841
- depguard
- dupl
- errcheck
- forbidigo
- gocritic
# - gocyclo # The cyclomatic complexety of a lot of functions is too high, we should refactor those another time.
- gofmt
- gofumpt
- gosimple
@ -17,20 +18,18 @@ linters:
- nolintlint
- revive
- staticcheck
# - structcheck # deprecated - https://github.com/golangci/golangci-lint/issues/1841
- stylecheck
- typecheck
- unconvert
- unused
# - varcheck # deprecated - https://github.com/golangci/golangci-lint/issues/1841
- wastedassign
enable-all: false
disable-all: true
fast: false
run:
timeout: 10m
output:
sort-results: true
linters-settings:
stylecheck:
checks: ["all", "-ST1005", "-ST1003"]
@ -47,27 +46,37 @@ linters-settings:
errorCode: 1
warningCode: 1
rules:
- name: atomic
- name: bare-return
- name: blank-imports
- name: constant-logical-expr
- name: context-as-argument
- name: context-keys-type
- name: dot-imports
- name: duplicated-imports
- name: empty-lines
- name: error-naming
- name: error-return
- name: error-strings
- name: error-naming
- name: errorf
- name: exported
- name: identical-branches
- name: if-return
- name: increment-decrement
- name: var-naming
- name: var-declaration
- name: indent-error-flow
- name: modifies-value-receiver
- name: package-comments
- name: range
- name: receiver-naming
- name: redefines-builtin-id
- name: string-of-int
- name: superfluous-else
- name: time-naming
- name: unconditional-recursion
- name: unexported-return
- name: indent-error-flow
- name: errorf
- name: duplicated-imports
- name: modifies-value-receiver
- name: unreachable-code
- name: var-declaration
- name: var-naming
gofumpt:
extra-rules: true
depguard:
@ -93,8 +102,8 @@ issues:
max-issues-per-linter: 0
max-same-issues: 0
exclude-dirs: [node_modules, public, web_src]
exclude-case-sensitive: true
exclude-rules:
# Exclude some linters from running on tests files.
- path: _test\.go
linters:
- gocyclo
@ -112,19 +121,19 @@ issues:
- path: cmd
linters:
- forbidigo
- linters:
- text: "webhook"
linters:
- dupl
text: "webhook"
- linters:
- text: "`ID' should not be capitalized"
linters:
- gocritic
text: "`ID' should not be capitalized"
- linters:
- text: "swagger"
linters:
- unused
- deadcode
text: "swagger"
- linters:
- text: "argument x is overwritten before first use"
linters:
- staticcheck
text: "argument x is overwritten before first use"
- text: "commentFormatting: put a space between `//` and comment text"
linters:
- gocritic

View File

@ -61,3 +61,4 @@ kerwin612 <kerwin612@qq.com> (@kerwin612)
Gary Wang <git@blumia.net> (@BLumia)
Tim-Niclas Oelschläger <zokki.softwareschmiede@gmail.com> (@zokkis)
Yu Liu <1240335630@qq.com> (@HEREYUA)
Kemal Zebari <kemalzebra@gmail.com> (@kemzeb)

View File

@ -30,7 +30,7 @@ EDITORCONFIG_CHECKER_PACKAGE ?= github.com/editorconfig-checker/editorconfig-che
GOFUMPT_PACKAGE ?= mvdan.cc/gofumpt@v0.6.0
GOLANGCI_LINT_PACKAGE ?= github.com/golangci/golangci-lint/cmd/golangci-lint@v1.57.2
GXZ_PACKAGE ?= github.com/ulikunitz/xz/cmd/gxz@v0.5.11
MISSPELL_PACKAGE ?= github.com/golangci/misspell/cmd/misspell@v0.4.1
MISSPELL_PACKAGE ?= github.com/golangci/misspell/cmd/misspell@v0.5.1
SWAGGER_PACKAGE ?= github.com/go-swagger/go-swagger/cmd/swagger@db51e79a0e37c572d8b59ae0c58bf2bbbbe53285
XGO_PACKAGE ?= src.techknowlogick.com/xgo@latest
GO_LICENSES_PACKAGE ?= github.com/google/go-licenses@v1
@ -397,11 +397,11 @@ lint-md: node_modules
.PHONY: lint-spell
lint-spell:
@go run $(MISSPELL_PACKAGE) -error $(SPELLCHECK_FILES)
@go run $(MISSPELL_PACKAGE) -dict tools/misspellings.csv -error $(SPELLCHECK_FILES)
.PHONY: lint-spell-fix
lint-spell-fix:
@go run $(MISSPELL_PACKAGE) -w $(SPELLCHECK_FILES)
@go run $(MISSPELL_PACKAGE) -dict tools/misspellings.csv -w $(SPELLCHECK_FILES)
.PHONY: lint-go
lint-go:
@ -778,7 +778,7 @@ generate-backend: $(TAGS_PREREQ) generate-go
.PHONY: generate-go
generate-go: $(TAGS_PREREQ)
@echo "Running go generate..."
@CC= GOOS= GOARCH= $(GO) generate -tags '$(TAGS)' ./...
@CC= GOOS= GOARCH= CGO_ENABLED=0 $(GO) generate -tags '$(TAGS)' ./...
.PHONY: security-check
security-check:
@ -908,8 +908,9 @@ webpack: $(WEBPACK_DEST)
$(WEBPACK_DEST): $(WEBPACK_SOURCES) $(WEBPACK_CONFIGS) package-lock.json
@$(MAKE) -s node-check node_modules
rm -rf $(WEBPACK_DEST_ENTRIES)
npx webpack
@rm -rf $(WEBPACK_DEST_ENTRIES)
@echo "Running webpack..."
@BROWSERSLIST_IGNORE_OLD_DATA=true npx webpack
@touch $(WEBPACK_DEST)
.PHONY: svg

View File

@ -540,8 +540,8 @@
"licenseText": "Copyright (c) 2011 The Snappy-Go Authors. All rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are\nmet:\n\n * Redistributions of source code must retain the above copyright\nnotice, this list of conditions and the following disclaimer.\n * Redistributions in binary form must reproduce the above\ncopyright notice, this list of conditions and the following disclaimer\nin the documentation and/or other materials provided with the\ndistribution.\n * Neither the name of Google Inc. nor the names of its\ncontributors may be used to endorse or promote products derived from\nthis software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n\"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\nLIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\nA PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\nOWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\nSPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\nLIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\nDATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\nTHEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n"
},
{
"name": "github.com/google/go-github/v57/github",
"path": "github.com/google/go-github/v57/github/LICENSE",
"name": "github.com/google/go-github/v61/github",
"path": "github.com/google/go-github/v61/github/LICENSE",
"licenseText": "Copyright (c) 2013 The go-github AUTHORS. All rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are\nmet:\n\n * Redistributions of source code must retain the above copyright\nnotice, this list of conditions and the following disclaimer.\n * Redistributions in binary form must reproduce the above\ncopyright notice, this list of conditions and the following disclaimer\nin the documentation and/or other materials provided with the\ndistribution.\n * Neither the name of Google Inc. nor the names of its\ncontributors may be used to endorse or promote products derived from\nthis software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n\"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\nLIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\nA PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\nOWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\nSPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\nLIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\nDATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\nTHEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n"
},
{

View File

@ -35,7 +35,7 @@ var microcmdUserChangePassword = &cli.Command{
},
&cli.BoolFlag{
Name: "must-change-password",
Usage: "User must change password",
Usage: "User must change password (can be disabled by --must-change-password=false)",
Value: true,
},
},

View File

@ -4,6 +4,7 @@
package cmd
import (
"context"
"errors"
"fmt"
@ -48,7 +49,7 @@ var microcmdUserCreate = &cli.Command{
},
&cli.BoolFlag{
Name: "must-change-password",
Usage: "Set to false to prevent forcing the user to change their password after initial login",
Usage: "User must change password after initial login, defaults to true for all users except the first one (can be disabled by --must-change-password=false)",
DisableDefaultText: true,
},
&cli.IntFlag{
@ -91,11 +92,16 @@ func runCreateUser(c *cli.Context) error {
_, _ = fmt.Fprintf(c.App.ErrWriter, "--name flag is deprecated. Use --username instead.\n")
}
ctx, cancel := installSignals()
defer cancel()
if err := initDB(ctx); err != nil {
return err
ctx := c.Context
if !setting.IsInTesting {
// FIXME: need to refactor the "installSignals/initDB" related code later
// it doesn't make sense to call it in (almost) every command action function
var cancel context.CancelFunc
ctx, cancel = installSignals()
defer cancel()
if err := initDB(ctx); err != nil {
return err
}
}
var password string
@ -123,8 +129,8 @@ func runCreateUser(c *cli.Context) error {
if err != nil {
return fmt.Errorf("IsTableNotEmpty: %w", err)
}
if !hasUserRecord && isAdmin {
// if this is the first admin being created, don't force to change password (keep the old behavior)
if !hasUserRecord {
// if this is the first one being created, don't force to change password (keep the old behavior)
mustChangePassword = false
}
}

View File

@ -0,0 +1,44 @@
// Copyright 2023 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package cmd
import (
"fmt"
"strings"
"testing"
"code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/models/unittest"
user_model "code.gitea.io/gitea/models/user"
"github.com/stretchr/testify/assert"
)
func TestAdminUserCreate(t *testing.T) {
app := NewMainApp(AppVersion{})
reset := func() {
assert.NoError(t, db.TruncateBeans(db.DefaultContext, &user_model.User{}))
assert.NoError(t, db.TruncateBeans(db.DefaultContext, &user_model.EmailAddress{}))
}
type createCheck struct{ IsAdmin, MustChangePassword bool }
createUser := func(name, args string) createCheck {
assert.NoError(t, app.Run(strings.Fields(fmt.Sprintf("./gitea admin user create --username %s --email %s@gitea.local %s --password foobar", name, name, args))))
u := unittest.AssertExistsAndLoadBean(t, &user_model.User{LowerName: name})
return createCheck{u.IsAdmin, u.MustChangePassword}
}
reset()
assert.Equal(t, createCheck{IsAdmin: false, MustChangePassword: false}, createUser("u", ""), "first non-admin user doesn't need to change password")
reset()
assert.Equal(t, createCheck{IsAdmin: true, MustChangePassword: false}, createUser("u", "--admin"), "first admin user doesn't need to change password")
reset()
assert.Equal(t, createCheck{IsAdmin: true, MustChangePassword: true}, createUser("u", "--admin --must-change-password"))
assert.Equal(t, createCheck{IsAdmin: true, MustChangePassword: true}, createUser("u2", "--admin"))
assert.Equal(t, createCheck{IsAdmin: true, MustChangePassword: false}, createUser("u3", "--admin --must-change-password=false"))
assert.Equal(t, createCheck{IsAdmin: false, MustChangePassword: true}, createUser("u4", ""))
assert.Equal(t, createCheck{IsAdmin: false, MustChangePassword: false}, createUser("u5", "--must-change-password=false"))
}

View File

@ -220,10 +220,7 @@ Gitea or set your environment appropriately.`, "")
}
}
supportProcReceive := false
if git.CheckGitVersionAtLeast("2.29") == nil {
supportProcReceive = true
}
supportProcReceive := git.DefaultFeatures().SupportProcReceive
for scanner.Scan() {
// TODO: support news feeds for wiki
@ -341,6 +338,7 @@ Gitea or set your environment appropriately.`, "")
isWiki, _ := strconv.ParseBool(os.Getenv(repo_module.EnvRepoIsWiki))
repoName := os.Getenv(repo_module.EnvRepoName)
pusherID, _ := strconv.ParseInt(os.Getenv(repo_module.EnvPusherID), 10, 64)
prID, _ := strconv.ParseInt(os.Getenv(repo_module.EnvPRID), 10, 64)
pusherName := os.Getenv(repo_module.EnvPusherName)
hookOptions := private.HookOptions{
@ -350,6 +348,8 @@ Gitea or set your environment appropriately.`, "")
GitObjectDirectory: os.Getenv(private.GitObjectDirectory),
GitQuarantinePath: os.Getenv(private.GitQuarantinePath),
GitPushOptions: pushOptions(),
PullRequestID: prID,
PushTrigger: repo_module.PushTrigger(os.Getenv(repo_module.EnvPushTrigger)),
}
oldCommitIDs := make([]string, hookBatchSize)
newCommitIDs := make([]string, hookBatchSize)
@ -465,7 +465,7 @@ func hookPrintResult(output, isCreate bool, branch, url string) {
fmt.Fprintf(os.Stderr, " %s\n", url)
}
fmt.Fprintln(os.Stderr, "")
os.Stderr.Sync()
_ = os.Stderr.Sync()
}
func pushOptions() map[string]string {
@ -497,7 +497,7 @@ Gitea or set your environment appropriately.`, "")
return nil
}
if git.CheckGitVersionAtLeast("2.29") != nil {
if !git.DefaultFeatures().SupportProcReceive {
return fail(ctx, "No proc-receive support", "current git version doesn't support proc-receive.")
}

View File

@ -112,13 +112,18 @@ func prepareWorkPathAndCustomConf(action cli.ActionFunc) func(ctx *cli.Context)
}
}
func NewMainApp(version, versionExtra string) *cli.App {
type AppVersion struct {
Version string
Extra string
}
func NewMainApp(appVer AppVersion) *cli.App {
app := cli.NewApp()
app.Name = "Gitea"
app.HelpName = "gitea"
app.Usage = "A painless self-hosted Git service"
app.Description = `Gitea program contains "web" and other subcommands. If no subcommand is given, it starts the web server by default. Use "web" subcommand for more web server arguments, use other subcommands for other purposes.`
app.Version = version + versionExtra
app.Version = appVer.Version + appVer.Extra
app.EnableBashCompletion = true
// these sub-commands need to use config file

View File

@ -28,7 +28,7 @@ func makePathOutput(workPath, customPath, customConf string) string {
}
func newTestApp(testCmdAction func(ctx *cli.Context) error) *cli.App {
app := NewMainApp("version", "version-extra")
app := NewMainApp(AppVersion{})
testCmd := &cli.Command{Name: "test-cmd", Action: testCmdAction}
prepareSubcommandWithConfig(testCmd, appGlobalFlags())
app.Commands = append(app.Commands, testCmd)

View File

@ -34,7 +34,7 @@ var CmdMigrateStorage = &cli.Command{
Name: "type",
Aliases: []string{"t"},
Value: "",
Usage: "Type of stored files to copy. Allowed types: 'attachments', 'lfs', 'avatars', 'repo-avatars', 'repo-archivers', 'packages', 'actions-log'",
Usage: "Type of stored files to copy. Allowed types: 'attachments', 'lfs', 'avatars', 'repo-avatars', 'repo-archivers', 'packages', 'actions-log', 'actions-artifacts",
},
&cli.StringFlag{
Name: "storage",
@ -160,6 +160,13 @@ func migrateActionsLog(ctx context.Context, dstStorage storage.ObjectStorage) er
})
}
func migrateActionsArtifacts(ctx context.Context, dstStorage storage.ObjectStorage) error {
return db.Iterate(ctx, nil, func(ctx context.Context, artifact *actions_model.ActionArtifact) error {
_, err := storage.Copy(dstStorage, artifact.ArtifactPath, storage.ActionsArtifacts, artifact.ArtifactPath)
return err
})
}
func runMigrateStorage(ctx *cli.Context) error {
stdCtx, cancel := installSignals()
defer cancel()
@ -223,13 +230,14 @@ func runMigrateStorage(ctx *cli.Context) error {
}
migratedMethods := map[string]func(context.Context, storage.ObjectStorage) error{
"attachments": migrateAttachments,
"lfs": migrateLFS,
"avatars": migrateAvatars,
"repo-avatars": migrateRepoAvatars,
"repo-archivers": migrateRepoArchivers,
"packages": migratePackages,
"actions-log": migrateActionsLog,
"attachments": migrateAttachments,
"lfs": migrateLFS,
"avatars": migrateAvatars,
"repo-avatars": migrateRepoAvatars,
"repo-archivers": migrateRepoArchivers,
"packages": migratePackages,
"actions-log": migrateActionsLog,
"actions-artifacts": migrateActionsArtifacts,
}
tp := strings.ToLower(ctx.String("type"))

View File

@ -178,7 +178,7 @@ func runServ(c *cli.Context) error {
}
if len(words) < 2 {
if git.CheckGitVersionAtLeast("2.29") == nil {
if git.DefaultFeatures().SupportProcReceive {
// for AGit Flow
if cmd == "ssh_info" {
fmt.Print(`{"type":"gitea","version":1}`)

View File

@ -17,7 +17,7 @@ import (
"strings"
"syscall"
"github.com/google/go-github/v57/github"
"github.com/google/go-github/v61/github"
"github.com/urfave/cli/v2"
"gopkg.in/yaml.v3"
)

View File

@ -1231,7 +1231,8 @@ LEVEL = Info
;DEFAULT_THEME = gitea-auto
;;
;; All available themes. Allow users select personalized themes regardless of the value of `DEFAULT_THEME`.
;THEMES = gitea-auto,gitea-light,gitea-dark
;; Leave it empty to allow users to select any theme from "{CustomPath}/public/assets/css/theme-*.css"
;THEMES =
;;
;; All available reactions users can choose on issues/prs and comments.
;; Values can be emoji alias (:smile:) or a unicode emoji.
@ -1455,7 +1456,7 @@ LEVEL = Info
;; Batch size to send for batched queues
;BATCH_LENGTH = 20
;;
;; Connection string for redis queues this will store the redis or redis-cluster connection string.
;; Connection string for redis queues this will store the redis (or Redis cluster) connection string.
;; When `TYPE` is `persistable-channel`, this provides a directory for the underlying leveldb
;; or additional options of the form `leveldb://path/to/db?option=value&....`, and will override `DATADIR`.
;CONN_STR = "redis://127.0.0.1:6379/0"
@ -1557,8 +1558,8 @@ LEVEL = Info
;; email = use the username part of the email attribute
;; Note: `nickname`, `preferred_username` and `email` options will normalize input strings using the following criteria:
;; - diacritics are removed
;; - the characters in the set `['´\x60]` are removed
;; - the characters in the set `[\s~+]` are replaced with `-`
;; - the characters in the set ['´`] are removed
;; - the characters in the set [\s~+] are replaced with "-"
;USERNAME = nickname
;;
;; Update avatar if available from oauth2 provider.
@ -1739,9 +1740,8 @@ LEVEL = Info
;; For "memory" only, GC interval in seconds, default is 60
;INTERVAL = 60
;;
;; For "redis", "redis-cluster" and "memcache", connection host address
;; redis: `redis://127.0.0.1:6379/0?pool_size=100&idle_timeout=180s`
;; redis-cluster: `redis+cluster://127.0.0.1:6379/0?pool_size=100&idle_timeout=180s`
;; For "redis" and "memcache", connection host address
;; redis: `redis://127.0.0.1:6379/0?pool_size=100&idle_timeout=180s` (or `redis+cluster://127.0.0.1:6379/0?pool_size=100&idle_timeout=180s` for a Redis cluster)
;; memcache: `127.0.0.1:11211`
;; twoqueue: `{"size":50000,"recent_ratio":0.25,"ghost_ratio":0.5}` or `50000`
;HOST =
@ -1771,15 +1771,14 @@ LEVEL = Info
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; Either "memory", "file", "redis", "redis-cluster", "db", "mysql", "couchbase", "memcache" or "postgres"
;; Either "memory", "file", "redis", "db", "mysql", "couchbase", "memcache" or "postgres"
;; Default is "memory". "db" will reuse the configuration in [database]
;PROVIDER = memory
;;
;; Provider config options
;; memory: doesn't have any config yet
;; file: session file path, e.g. `data/sessions`
;; redis: `redis://127.0.0.1:6379/0?pool_size=100&idle_timeout=180s`
;; redis-cluster: `redis+cluster://127.0.0.1:6379/0?pool_size=100&idle_timeout=180s`
;; redis: `redis://127.0.0.1:6379/0?pool_size=100&idle_timeout=180s` (or `redis+cluster://127.0.0.1:6379/0?pool_size=100&idle_timeout=180s` for a Redis cluster)
;; mysql: go-sql-driver/mysql dsn config string, e.g. `root:password@/session_table`
;PROVIDER_CONFIG = data/sessions ; Relative paths will be made absolute against _`AppWorkPath`_.
;;

View File

@ -1,7 +1,7 @@
# Gitea - Docker
Dockerfile is found in root of repository.
Dockerfile is found in the root of the repository.
Docker image can be found on [docker hub](https://hub.docker.com/r/gitea/gitea)
Docker image can be found on [docker hub](https://hub.docker.com/r/gitea/gitea).
Documentation on using docker image can be found on [Gitea Docs site](https://docs.gitea.com/installation/install-with-docker-rootless)
Documentation on using docker image can be found on [Gitea Docs site](https://docs.gitea.com/installation/install-with-docker-rootless).

View File

@ -214,10 +214,9 @@ The following configuration set `Content-Type: application/vnd.android.package-a
- `SITEMAP_PAGING_NUM`: **20**: Number of items that are displayed in a single subsitemap.
- `GRAPH_MAX_COMMIT_NUM`: **100**: Number of maximum commits shown in the commit graph.
- `CODE_COMMENT_LINES`: **4**: Number of line of codes shown for a code comment.
- `DEFAULT_THEME`: **gitea-auto**: \[gitea-auto, gitea-light, gitea-dark\]: Set the default theme for the Gitea installation.
- `DEFAULT_THEME`: **gitea-auto**: Set the default theme for the Gitea installation, custom themes could be provided by `{CustomPath}/public/assets/css/theme-*.css`.
- `SHOW_USER_EMAIL`: **true**: Whether the email of the user should be shown in the Explore Users page.
- `THEMES`: **gitea-auto,gitea-light,gitea-dark**: All available themes. Allow users select personalized themes.
regardless of the value of `DEFAULT_THEME`.
- `THEMES`: **_empty_**: All available themes by `{CustomPath}/public/assets/css/theme-*.css`. Allow users select personalized themes.
- `MAX_DISPLAY_FILE_SIZE`: **8388608**: Max size of files to be displayed (default is 8MiB)
- `AMBIGUOUS_UNICODE_DETECTION`: **true**: Detect ambiguous unicode characters in file contents and show warnings on the UI
- `REACTIONS`: All available reactions users can choose on issues/prs and comments
@ -493,7 +492,7 @@ Configuration at `[queue]` will set defaults for queues with overrides for indiv
- `DATADIR`: **queues/common**: Base DataDir for storing level queues. `DATADIR` for individual queues can be set in `queue.name` sections. Relative paths will be made absolute against `%(APP_DATA_PATH)s`.
- `LENGTH`: **100000**: Maximal queue size before channel queues block
- `BATCH_LENGTH`: **20**: Batch data before passing to the handler
- `CONN_STR`: **redis://127.0.0.1:6379/0**: Connection string for the redis queue type. For `redis-cluster` use `redis+cluster://127.0.0.1:6379/0`. Options can be set using query params. Similarly, LevelDB options can also be set using: **leveldb://relative/path?option=value** or **leveldb:///absolute/path?option=value**, and will override `DATADIR`
- `CONN_STR`: **redis://127.0.0.1:6379/0**: Connection string for the redis queue type. If you're running a Redis cluster, use `redis+cluster://127.0.0.1:6379/0`. Options can be set using query params. Similarly, LevelDB options can also be set using: **leveldb://relative/path?option=value** or **leveldb:///absolute/path?option=value**, and will override `DATADIR`
- `QUEUE_NAME`: **_queue**: The suffix for default redis and disk queue name. Individual queues will default to **`name`**`QUEUE_NAME` but can be overridden in the specific `queue.name` section.
- `SET_NAME`: **_unique**: The suffix that will be added to the default redis and disk queue `set` name for unique queues. Individual queues will default to **`name`**`QUEUE_NAME`_`SET_NAME`_ but can be overridden in the specific `queue.name` section.
- `MAX_WORKERS`: **(dynamic)**: Maximum number of worker go-routines for the queue. Default value is "CpuNum/2" clipped to between 1 and 10.
@ -613,7 +612,7 @@ And the following unique queues:
- `email` - use the username part of the email attribute
- Note: `nickname`, `preferred_username` and `email` options will normalize input strings using the following criteria:
- diacritics are removed
- the characters in the set `['´\x60]` are removed
- the characters in the set ```['´`]``` are removed
- the characters in the set `[\s~+]` are replaced with `-`
- `UPDATE_AVATAR`: **false**: Update avatar if available from oauth2 provider. Update will be performed on each login.
- `ACCOUNT_LINKING`: **login**: How to handle if an account / email already exists:
@ -778,11 +777,11 @@ and
## Cache (`cache`)
- `ADAPTER`: **memory**: Cache engine adapter, either `memory`, `redis`, `redis-cluster`, `twoqueue` or `memcache`. (`twoqueue` represents a size limited LRU cache.)
- `ADAPTER`: **memory**: Cache engine adapter, either `memory`, `redis`, `twoqueue` or `memcache`. (`twoqueue` represents a size limited LRU cache.)
- `INTERVAL`: **60**: Garbage Collection interval (sec), for memory and twoqueue cache only.
- `HOST`: **_empty_**: Connection string for `redis`, `redis-cluster` and `memcache`. For `twoqueue` sets configuration for the queue.
- `HOST`: **_empty_**: Connection string for `redis` and `memcache`. For `twoqueue` sets configuration for the queue.
- Redis: `redis://:macaron@127.0.0.1:6379/0?pool_size=100&idle_timeout=180s`
- Redis-cluster `redis+cluster://:macaron@127.0.0.1:6379/0?pool_size=100&idle_timeout=180s`
- For a Redis cluster: `redis+cluster://:macaron@127.0.0.1:6379/0?pool_size=100&idle_timeout=180s`
- Memcache: `127.0.0.1:9090;127.0.0.1:9091`
- TwoQueue LRU cache: `{"size":50000,"recent_ratio":0.25,"ghost_ratio":0.5}` or `50000` representing the maximum number of objects stored in the cache.
- `ITEM_TTL`: **16h**: Time to keep items in cache if not used, Setting it to -1 disables caching.
@ -794,7 +793,7 @@ and
## Session (`session`)
- `PROVIDER`: **memory**: Session engine provider \[memory, file, redis, redis-cluster, db, mysql, couchbase, memcache, postgres\]. Setting `db` will reuse the configuration in `[database]`
- `PROVIDER`: **memory**: Session engine provider \[memory, file, redis, db, mysql, couchbase, memcache, postgres\]. Setting `db` will reuse the configuration in `[database]`
- `PROVIDER_CONFIG`: **data/sessions**: For file, the root path; for db, empty (database config will be used); for others, the connection string. Relative paths will be made absolute against _`AppWorkPath`_.
- `COOKIE_SECURE`:**_empty_**: `true` or `false`. Enable this to force using HTTPS for all session access. If not set, it defaults to `true` if the ROOT_URL is an HTTPS URL.
- `COOKIE_NAME`: **i\_like\_gitea**: The name of the cookie used for the session ID.
@ -1323,7 +1322,7 @@ Defaultly every storage has their default base path like below
| actions_log | actions_log/ |
| actions_artifacts | actions_artifacts/ |
And bucket, basepath or `SERVE_DIRECT` could be special or overrided, if you want to use a different you can:
And bucket, basepath or `SERVE_DIRECT` could be special or overridden, if you want to use a different you can:
```ini
[storage.actions_log]

View File

@ -212,10 +212,9 @@ menu:
- `SITEMAP_PAGING_NUM`: **20**: 在单个子SiteMap中显示的项数。
- `GRAPH_MAX_COMMIT_NUM`: **100**: 提交图中显示的最大commit数量。
- `CODE_COMMENT_LINES`: **4**: 在代码评论中能够显示的最大代码行数。
- `DEFAULT_THEME`: **gitea-auto**: \[gitea-auto, gitea-light, gitea-dark\]: 在Gitea安装时候设置的默认主题。
- `DEFAULT_THEME`: **gitea-auto**: 在Gitea安装时候设置的默认主题,自定义的主题可以通过 `{CustomPath}/public/assets/css/theme-*.css` 提供
- `SHOW_USER_EMAIL`: **true**: 用户的电子邮件是否应该显示在`Explore Users`页面中。
- `THEMES`: **gitea-auto,gitea-light,gitea-dark**: 所有可用的主题。允许用户选择个性化的主题,
而不受DEFAULT_THEME 值的影响。
- `THEMES`: **_empty_**: 所有可用的主题(由 `{CustomPath}/public/assets/css/theme-*.css` 提供)。允许用户选择个性化的主题,
- `MAX_DISPLAY_FILE_SIZE`: **8388608**: 能够显示文件的最大大小默认为8MiB
- `REACTIONS`: 用户可以在问题Issue、Pull RequestPR以及评论中选择的所有可选的反应。
这些值可以是表情符号别名(例如::smile:或Unicode表情符号。

View File

@ -381,7 +381,7 @@ To make a custom theme available to all users:
1. Add a CSS file to `$GITEA_CUSTOM/public/assets/css/theme-<theme-name>.css`.
The value of `$GITEA_CUSTOM` of your instance can be queried by calling `gitea help` and looking up the value of "CustomPath".
2. Add `<theme-name>` to the comma-separated list of setting `THEMES` in `app.ini`
2. Add `<theme-name>` to the comma-separated list of setting `THEMES` in `app.ini`, or leave `THEMES` empty to allow all themes.
Community themes are listed in [gitea/awesome-gitea#themes](https://gitea.com/gitea/awesome-gitea#themes).

View File

@ -178,17 +178,6 @@ At some point, a customer or third party needs access to a specific repo and onl
Use [Fail2Ban](administration/fail2ban-setup.md) to monitor and stop automated login attempts or other malicious behavior based on log patterns
## How to add/use custom themes
Gitea supports three official themes right now, `gitea-light`, `gitea-dark`, and `gitea-auto` (automatically switches between the previous two depending on operating system settings).
To add your own theme, currently the only way is to provide a complete theme (not just color overrides)
As an example, let's say our theme is `arc-blue` (this is a real theme, and can be found [in this issue](https://github.com/go-gitea/gitea/issues/6011))
Name the `.css` file `theme-arc-blue.css` and add it to your custom folder in `custom/public/assets/css`
Allow users to use it by adding `arc-blue` to the list of `THEMES` in your `app.ini`
## SSHD vs built-in SSH
SSHD is the built-in SSH server on most Unix systems.

View File

@ -182,17 +182,6 @@ Gitea不提供内置的Pages服务器。您需要一个专用的域名来提供
使用 [Fail2Ban](administration/fail2ban-setup.md) 监视并阻止基于日志模式的自动登录尝试或其他恶意行为。
## 如何添加/使用自定义主题
Gitea 目前支持三个官方主题,分别是 `gitea-light`、`gitea-dark` 和 `gitea-auto`(根据操作系统设置自动切换前两个主题)。
要添加自己的主题,目前唯一的方法是提供一个完整的主题(不仅仅是颜色覆盖)。
假设我们的主题是 `arc-blue`(这是一个真实的主题,可以在[此问题](https://github.com/go-gitea/gitea/issues/6011)中找到)
将`.css`文件命名为`theme-arc-blue.css`并将其添加到`custom/public/assets/css`文件夹中
通过将`arc-blue`添加到`app.ini`中的`THEMES`列表中,允许用户使用该主题
## SSHD vs 内建SSH
SSHD是大多数Unix系统上内建的SSH服务器。

View File

@ -58,7 +58,7 @@ The repository now gets mirrored periodically to the remote repository. You can
To set up a mirror from Gitea to GitHub, you need to follow these steps:
1. Create a [GitHub personal access token](https://docs.github.com/en/github/authenticating-to-github/creating-a-personal-access-token) with the *public_repo* box checked. Also check the **workflow** checkbox in case your repo using act for continuous integration.
1. Create a [GitHub personal access token](https://docs.github.com/en/github/authenticating-to-github/creating-a-personal-access-token) with the *public_repo* box checked. Also check the **workflow** checkbox in case your repo uses GitHub Actions for continuous integration.
2. Create a repository with that name on GitHub. Unlike Gitea, GitHub does not support creating repositories by pushing to the remote. You can also use an existing remote repo if it has the same commit history as your Gitea repo.
3. In the settings of your Gitea repo, fill in the **Git Remote Repository URL**: `https://github.com/<your_github_group>/<your_github_project>.git`.
4. Fill in the **Authorization** fields with your GitHub username and the personal access token as **Password**.
@ -91,10 +91,10 @@ The repository pushes shortly thereafter. To force a push, select the **Synchron
### Mirror an existing ssh repository
Currently gitea supports no ssh push mirrors. You can work around this by adding a `post-receive` hook to your gitea repository that pushes manually.
Currently Gitea supports no ssh push mirrors. You can work around this by adding a `post-receive` hook to your Gitea repository that pushes manually.
1. Make sure the user running gitea has access to the git repo you are trying to mirror to from shell.
2. On the Webinterface at the repository settings > git hooks add a post-receive hook for the mirror. I.e.
1. Make sure the user running Gitea has access to the git repo you are trying to mirror to from shell.
2. On the web interface at the repository settings > git hooks add a post-receive hook for the mirror. I.e.
```
#!/usr/bin/env bash

8
go.mod
View File

@ -8,7 +8,7 @@ require (
code.gitea.io/sdk/gitea v0.17.1
codeberg.org/gusted/mcaptcha v0.0.0-20220723083913-4f3072e1d570
connectrpc.com/connect v1.15.0
gitea.com/go-chi/binding v0.0.0-20240316035258-17450c5f3028
gitea.com/go-chi/binding v0.0.0-20240430071103-39a851e106ed
gitea.com/go-chi/cache v0.2.0
gitea.com/go-chi/captcha v0.0.0-20240315150714-fb487f629098
gitea.com/go-chi/session v0.0.0-20240316035857-16768d98ec96
@ -16,6 +16,7 @@ require (
gitea.com/lunny/levelqueue v0.4.2-0.20230414023320-3c0159fe0fe4
github.com/42wim/sshsig v0.0.0-20211121163825-841cf5bbc121
github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358
github.com/ProtonMail/go-crypto v1.0.0
github.com/PuerkitoBio/goquery v1.9.1
github.com/alecthomas/chroma/v2 v2.13.0
github.com/blakesmith/ar v0.0.0-20190502131153-809d4375e1fb
@ -53,11 +54,12 @@ require (
github.com/gogs/chardet v0.0.0-20211120154057-b7413eaefb8f
github.com/gogs/go-gogs-client v0.0.0-20210131175652-1d7215cd8d85
github.com/golang-jwt/jwt/v5 v5.2.1
github.com/google/go-github/v57 v57.0.0
github.com/google/go-github/v61 v61.0.0
github.com/google/pprof v0.0.0-20240227163752-401108e1b7e7
github.com/google/uuid v1.6.0
github.com/gorilla/feeds v1.1.2
github.com/gorilla/sessions v1.2.2
github.com/h2non/gock v1.2.0
github.com/hashicorp/go-version v1.6.0
github.com/hashicorp/golang-lru/v2 v2.0.7
github.com/huandu/xstrings v1.4.0
@ -135,7 +137,6 @@ require (
github.com/Masterminds/semver/v3 v3.2.1 // indirect
github.com/Masterminds/sprig/v3 v3.2.3 // indirect
github.com/Microsoft/go-winio v0.6.1 // indirect
github.com/ProtonMail/go-crypto v1.0.0 // indirect
github.com/RoaringBitmap/roaring v1.9.0 // indirect
github.com/andybalholm/brotli v1.1.0 // indirect
github.com/andybalholm/cascadia v1.3.2 // indirect
@ -209,6 +210,7 @@ require (
github.com/gorilla/handlers v1.5.2 // indirect
github.com/gorilla/mux v1.8.1 // indirect
github.com/gorilla/securecookie v1.1.2 // indirect
github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542 // indirect
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
github.com/hashicorp/go-retryablehttp v0.7.5 // indirect
github.com/hashicorp/hcl v1.0.0 // indirect

14
go.sum
View File

@ -20,8 +20,8 @@ git.sr.ht/~mariusor/go-xsd-duration v0.0.0-20220703122237-02e73435a078 h1:cliQ4H
git.sr.ht/~mariusor/go-xsd-duration v0.0.0-20220703122237-02e73435a078/go.mod h1:g/V2Hjas6Z1UHUp4yIx6bATpNzJ7DYtD0FG3+xARWxs=
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-20240316035258-17450c5f3028 h1:6/QAx4+s0dyRwdaTFPTnhGppuiuu0OqxIH9szyTpvKw=
gitea.com/go-chi/binding v0.0.0-20240316035258-17450c5f3028/go.mod h1:E3i3cgB04dDx0v3CytCgRTTn9Z/9x891aet3r456RVw=
gitea.com/go-chi/binding v0.0.0-20240430071103-39a851e106ed h1:EZZBtilMLSZNWtHHcgq2mt6NSGhJSZBuduAlinMEmso=
gitea.com/go-chi/binding v0.0.0-20240430071103-39a851e106ed/go.mod h1:E3i3cgB04dDx0v3CytCgRTTn9Z/9x891aet3r456RVw=
gitea.com/go-chi/cache v0.2.0 h1:E0npuTfDW6CT1yD8NMDVc1SK6IeRjfmRL2zlEsCEd7w=
gitea.com/go-chi/cache v0.2.0/go.mod h1:iQlVK2aKTZ/rE9UcHyz9pQWGvdP9i1eI2spOpzgCrtE=
gitea.com/go-chi/captcha v0.0.0-20240315150714-fb487f629098 h1:p2ki+WK0cIeNQuqjR98IP2KZQKRzJJiV7aTeMAFwaWo=
@ -394,8 +394,8 @@ github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/go-github/v57 v57.0.0 h1:L+Y3UPTY8ALM8x+TV0lg+IEBI+upibemtBD8Q9u7zHs=
github.com/google/go-github/v57 v57.0.0/go.mod h1:s0omdnye0hvK/ecLvpsGfJMiRt85PimQh4oygmLIxHw=
github.com/google/go-github/v61 v61.0.0 h1:VwQCBwhyE9JclCI+22/7mLB1PuU9eowCXKY5pNlu1go=
github.com/google/go-github/v61 v61.0.0/go.mod h1:0WR+KmsWX75G2EbpyGsGmradjo3IiciuI4BmdVCobQY=
github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8=
github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU=
github.com/google/go-tpm v0.9.0 h1:sQF6YqWMi+SCXpsmS3fd21oPy/vSddwZry4JnmltHVk=
@ -430,6 +430,10 @@ github.com/gorilla/securecookie v1.1.2/go.mod h1:NfCASbcHqRSY+3a8tlWJwsQap2VX5pw
github.com/gorilla/sessions v1.2.0/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM=
github.com/gorilla/sessions v1.2.2 h1:lqzMYz6bOfvn2WriPUjNByzeXIlVzURcPmgMczkmTjY=
github.com/gorilla/sessions v1.2.2/go.mod h1:ePLdVu+jbEgHH+KWw8I1z2wqd0BAdAQh/8LRvBeoNcQ=
github.com/h2non/gock v1.2.0 h1:K6ol8rfrRkUOefooBC8elXoaNGYkpp7y2qcxGG6BzUE=
github.com/h2non/gock v1.2.0/go.mod h1:tNhoxHYW2W42cYkYb1WqzdbYIieALC99kpYr7rH/BQk=
github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542 h1:2VTzZjLZBgl62/EtslCrtky5vbi9dd7HrQPQIx6wqiw=
github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542/go.mod h1:Ow0tF8D4Kplbc8s8sSb3V2oUCygFHVp8gC3Dn6U4MNI=
github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ=
github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48=
github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ=
@ -591,6 +595,8 @@ github.com/mschoch/smat v0.2.0 h1:8imxQsjDm8yFEAVBe7azKmKSgzSkZXDuKkSq9374khM=
github.com/mschoch/smat v0.2.0/go.mod h1:kc9mz7DoBKqDyiRL7VZN8KvXQMWeTaVnttLRXOlotKw=
github.com/msteinert/pam v1.2.0 h1:mYfjlvN2KYs2Pb9G6nb/1f/nPfAttT/Jee5Sq9r3bGE=
github.com/msteinert/pam v1.2.0/go.mod h1:d2n0DCUK8rGecChV3JzvmsDjOY4R7AYbsNxAT+ftQl0=
github.com/nbio/st v0.0.0-20140626010706-e9e8d9816f32 h1:W6apQkHrMkS0Muv8G/TipAy/FJl/rCYT0+EuS8+Z0z4=
github.com/nbio/st v0.0.0-20140626010706-e9e8d9816f32/go.mod h1:9wM+0iRr9ahx58uYLpLIr5fm8diHn0JbqRycJi6w0Ms=
github.com/niklasfasching/go-org v1.7.0 h1:vyMdcMWWTe/XmANk19F4k8XGBYg0GQ/gJGMimOjGMek=
github.com/niklasfasching/go-org v1.7.0/go.mod h1:WuVm4d45oePiE0eX25GqTDQIt/qPW1T9DGkRscqLW5o=
github.com/nwaples/rardecode v1.1.0/go.mod h1:5DzqNKiOdpKKBH87u8VlvAnPZMXcGRhxWkRpHbbfGS0=

View File

@ -42,7 +42,7 @@ func main() {
log.GetManager().Close()
os.Exit(code)
}
app := cmd.NewMainApp(Version, formatBuiltWith())
app := cmd.NewMainApp(cmd.AppVersion{Version: Version, Extra: formatBuiltWith()})
_ = cmd.RunMainApp(app, os.Args...) // all errors should have been handled by the RunMainApp
log.GetManager().Close()
}

View File

@ -74,6 +74,13 @@ func (run *ActionRun) Link() string {
return fmt.Sprintf("%s/actions/runs/%d", run.Repo.Link(), run.Index)
}
func (run *ActionRun) WorkflowLink() string {
if run.Repo == nil {
return ""
}
return fmt.Sprintf("%s/actions/?workflow=%s", run.Repo.Link(), run.WorkflowID)
}
// RefLink return the url of run's ref
func (run *ActionRun) RefLink() string {
refName := git.RefName(run.Ref)
@ -98,13 +105,10 @@ func (run *ActionRun) LoadAttributes(ctx context.Context) error {
return nil
}
if run.Repo == nil {
repo, err := repo_model.GetRepositoryByID(ctx, run.RepoID)
if err != nil {
return err
}
run.Repo = repo
if err := run.LoadRepo(ctx); err != nil {
return err
}
if err := run.Repo.LoadAttributes(ctx); err != nil {
return err
}
@ -120,6 +124,19 @@ func (run *ActionRun) LoadAttributes(ctx context.Context) error {
return nil
}
func (run *ActionRun) LoadRepo(ctx context.Context) error {
if run == nil || run.Repo != nil {
return nil
}
repo, err := repo_model.GetRepositoryByID(ctx, run.RepoID)
if err != nil {
return err
}
run.Repo = repo
return nil
}
func (run *ActionRun) Duration() time.Duration {
return calculateDuration(run.Started, run.Stopped, run.Status) + run.PreviousDuration
}
@ -146,6 +163,10 @@ func (run *ActionRun) GetPullRequestEventPayload() (*api.PullRequestPayload, err
return nil, fmt.Errorf("event %s is not a pull request event", run.Event)
}
func (run *ActionRun) IsSchedule() bool {
return run.ScheduleID > 0
}
func updateRepoRunsNumbers(ctx context.Context, repo *repo_model.Repository) error {
_, err := db.GetEngine(ctx).ID(repo.ID).
SetExpr("num_action_runs",
@ -241,11 +262,11 @@ func CancelPreviousJobs(ctx context.Context, repoID int64, ref, workflowID strin
// InsertRun inserts a run
func InsertRun(ctx context.Context, run *ActionRun, jobs []*jobparser.SingleWorkflow) error {
ctx, commiter, err := db.TxContext(ctx)
ctx, committer, err := db.TxContext(ctx)
if err != nil {
return err
}
defer commiter.Close()
defer committer.Close()
index, err := db.GetNextResourceIndex(ctx, "action_run_index", run.RepoID)
if err != nil {
@ -310,7 +331,7 @@ func InsertRun(ctx context.Context, run *ActionRun, jobs []*jobparser.SingleWork
}
}
return commiter.Commit()
return committer.Commit()
}
func GetRunByID(ctx context.Context, id int64) (*ActionRun, error) {

View File

@ -270,7 +270,7 @@ func CountRunnersWithoutBelongingOwner(ctx context.Context) (int64, error) {
// Only affect action runners were a owner ID is set, as actions runners
// could also be created on a repository.
return db.GetEngine(ctx).Table("action_runner").
Join("LEFT", "user", "`action_runner`.owner_id = `user`.id").
Join("LEFT", "`user`", "`action_runner`.owner_id = `user`.id").
Where("`action_runner`.owner_id != ?", 0).
And(builder.IsNull{"`user`.id"}).
Count(new(ActionRunner))
@ -279,7 +279,7 @@ func CountRunnersWithoutBelongingOwner(ctx context.Context) (int64, error) {
func FixRunnersWithoutBelongingOwner(ctx context.Context) (int64, error) {
subQuery := builder.Select("`action_runner`.id").
From("`action_runner`").
Join("LEFT", "user", "`action_runner`.owner_id = `user`.id").
Join("LEFT", "`user`", "`action_runner`.owner_id = `user`.id").
Where(builder.Neq{"`action_runner`.owner_id": 0}).
And(builder.IsNull{"`user`.id"})
b := builder.Delete(builder.In("id", subQuery)).From("`action_runner`")
@ -289,3 +289,25 @@ func FixRunnersWithoutBelongingOwner(ctx context.Context) (int64, error) {
}
return res.RowsAffected()
}
func CountRunnersWithoutBelongingRepo(ctx context.Context) (int64, error) {
return db.GetEngine(ctx).Table("action_runner").
Join("LEFT", "`repository`", "`action_runner`.repo_id = `repository`.id").
Where("`action_runner`.repo_id != ?", 0).
And(builder.IsNull{"`repository`.id"}).
Count(new(ActionRunner))
}
func FixRunnersWithoutBelongingRepo(ctx context.Context) (int64, error) {
subQuery := builder.Select("`action_runner`.id").
From("`action_runner`").
Join("LEFT", "`repository`", "`action_runner`.repo_id = `repository`.id").
Where(builder.Neq{"`action_runner`.repo_id": 0}).
And(builder.IsNull{"`repository`.id"})
b := builder.Delete(builder.In("id", subQuery)).From("`action_runner`")
res, err := db.GetEngine(ctx).Exec(b)
if err != nil {
return 0, err
}
return res.RowsAffected()
}

View File

@ -216,11 +216,11 @@ func GetRunningTaskByToken(ctx context.Context, token string) (*ActionTask, erro
}
func CreateTaskForRunner(ctx context.Context, runner *ActionRunner) (*ActionTask, bool, error) {
ctx, commiter, err := db.TxContext(ctx)
ctx, committer, err := db.TxContext(ctx)
if err != nil {
return nil, false, err
}
defer commiter.Close()
defer committer.Close()
e := db.GetEngine(ctx)
@ -322,7 +322,7 @@ func CreateTaskForRunner(ctx context.Context, runner *ActionRunner) (*ActionTask
task.Job = job
if err := commiter.Commit(); err != nil {
if err := committer.Commit(); err != nil {
return nil, false, err
}
@ -347,11 +347,11 @@ func UpdateTaskByState(ctx context.Context, state *runnerv1.TaskState) (*ActionT
stepStates[v.Id] = v
}
ctx, commiter, err := db.TxContext(ctx)
ctx, committer, err := db.TxContext(ctx)
if err != nil {
return nil, err
}
defer commiter.Close()
defer committer.Close()
e := db.GetEngine(ctx)
@ -412,7 +412,7 @@ func UpdateTaskByState(ctx context.Context, state *runnerv1.TaskState) (*ActionT
}
}
if err := commiter.Commit(); err != nil {
if err := committer.Commit(); err != nil {
return nil, err
}

View File

@ -13,7 +13,7 @@ import (
// ActionTasksVersion
// If both ownerID and repoID is zero, its scope is global.
// If ownerID is not zero and repoID is zero, its scope is org (there is no user-level runner currrently).
// If ownerID is not zero and repoID is zero, its scope is org (there is no user-level runner currently).
// If ownerID is zero and repoID is not zero, its scope is repo.
type ActionTasksVersion struct {
ID int64 `xorm:"pk autoincr"`
@ -73,11 +73,11 @@ func increaseTasksVersionByScope(ctx context.Context, ownerID, repoID int64) err
}
func IncreaseTaskVersion(ctx context.Context, ownerID, repoID int64) error {
ctx, commiter, err := db.TxContext(ctx)
ctx, committer, err := db.TxContext(ctx)
if err != nil {
return err
}
defer commiter.Close()
defer committer.Close()
// 1. increase global
if err := increaseTasksVersionByScope(ctx, 0, 0); err != nil {
@ -101,5 +101,5 @@ func IncreaseTaskVersion(ctx context.Context, ownerID, repoID int64) error {
}
}
return commiter.Commit()
return committer.Commit()
}

View File

@ -92,6 +92,11 @@ func DeleteVariable(ctx context.Context, id int64) error {
func GetVariablesOfRun(ctx context.Context, run *ActionRun) (map[string]string, error) {
variables := map[string]string{}
if err := run.LoadRepo(ctx); err != nil {
log.Error("LoadRepo: %v", err)
return nil, err
}
// Global
globalVariables, err := db.Find[ActionVariable](ctx, FindVariablesOpts{})
if err != nil {

View File

@ -110,7 +110,6 @@ func ParseCommitWithSignature(ctx context.Context, c *git.Commit) *CommitVerific
Reason: "gpg.error.no_committer_account",
}
}
}
}

View File

@ -13,8 +13,6 @@ import (
"github.com/stretchr/testify/assert"
)
//////////////////// Application
func TestOAuth2Application_GenerateClientSecret(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase())
app := unittest.AssertExistsAndLoadBean(t, &auth_model.OAuth2Application{ID: 1})

View File

@ -227,7 +227,6 @@ func NamesToBean(names ...string) ([]any, error) {
// Need to map provided names to beans...
beanMap := make(map[string]any)
for _, bean := range tables {
beanMap[strings.ToLower(reflect.Indirect(reflect.ValueOf(bean)).Type().Name())] = bean
beanMap[strings.ToLower(x.TableName(bean))] = bean
beanMap[strings.ToLower(x.TableName(bean, true))] = bean

View File

@ -1,7 +1,7 @@
-
id: 1
type: 0 # gitea pull request
status: 2 # mergable
status: 2 # mergeable
issue_id: 2
index: 2
head_repo_id: 1
@ -16,7 +16,7 @@
-
id: 2
type: 0 # gitea pull request
status: 2 # mergable
status: 2 # mergeable
issue_id: 3
index: 3
head_repo_id: 1
@ -29,7 +29,7 @@
-
id: 3
type: 0 # gitea pull request
status: 2 # mergable
status: 2 # mergeable
issue_id: 8
index: 1
head_repo_id: 11
@ -42,7 +42,7 @@
-
id: 4
type: 0 # gitea pull request
status: 2 # mergable
status: 2 # mergeable
issue_id: 9
index: 1
head_repo_id: 48
@ -55,7 +55,7 @@
-
id: 5 # this PR is outdated (one commit behind branch1 )
type: 0 # gitea pull request
status: 2 # mergable
status: 2 # mergeable
issue_id: 11
index: 5
head_repo_id: 1
@ -68,7 +68,7 @@
-
id: 6
type: 0 # gitea pull request
status: 2 # mergable
status: 2 # mergeable
issue_id: 12
index: 2
head_repo_id: 3
@ -81,7 +81,7 @@
-
id: 7
type: 0 # gitea pull request
status: 2 # mergable
status: 2 # mergeable
issue_id: 19
index: 1
head_repo_id: 58
@ -94,7 +94,7 @@
-
id: 8
type: 0 # gitea pull request
status: 2 # mergable
status: 2 # mergeable
issue_id: 20
index: 1
head_repo_id: 23
@ -103,7 +103,7 @@
-
id: 9
type: 0 # gitea pull request
status: 2 # mergable
status: 2 # mergeable
issue_id: 21
index: 1
head_repo_id: 60
@ -112,7 +112,7 @@
-
id: 10
type: 0 # gitea pull request
status: 2 # mergable
status: 2 # mergeable
issue_id: 22
index: 1
head_repo_id: 61

View File

@ -397,36 +397,16 @@ 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)
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 {
var contexts []string
if err := db.GetEngine(ctx).Table("commit_status").
Where("repo_id = ?", repoID).And("updated_unix >= ?", start).
Cols("context").Distinct().Find(&contexts); err != nil {
return nil, err
}
contexts := make([]string, 0, len(results))
if len(results) == 0 {
return contexts, nil
}
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)
return contexts, nil
}
// NewCommitStatusOptions holds options for creating a CommitStatus

View File

@ -5,11 +5,15 @@ package git_test
import (
"testing"
"time"
"code.gitea.io/gitea/models/db"
git_model "code.gitea.io/gitea/models/git"
repo_model "code.gitea.io/gitea/models/repo"
"code.gitea.io/gitea/models/unittest"
user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/gitrepo"
"code.gitea.io/gitea/modules/structs"
"github.com/stretchr/testify/assert"
@ -175,3 +179,55 @@ func Test_CalcCommitStatus(t *testing.T) {
assert.Equal(t, kase.expected, git_model.CalcCommitStatus(kase.statuses))
}
}
func TestFindRepoRecentCommitStatusContexts(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase())
repo2 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 2})
user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
gitRepo, err := gitrepo.OpenRepository(git.DefaultContext, repo2)
assert.NoError(t, err)
defer gitRepo.Close()
commit, err := gitRepo.GetBranchCommit(repo2.DefaultBranch)
assert.NoError(t, err)
defer func() {
_, err := db.DeleteByBean(db.DefaultContext, &git_model.CommitStatus{
RepoID: repo2.ID,
CreatorID: user2.ID,
SHA: commit.ID.String(),
})
assert.NoError(t, err)
}()
err = git_model.NewCommitStatus(db.DefaultContext, git_model.NewCommitStatusOptions{
Repo: repo2,
Creator: user2,
SHA: commit.ID,
CommitStatus: &git_model.CommitStatus{
State: structs.CommitStatusFailure,
TargetURL: "https://example.com/tests/",
Context: "compliance/lint-backend",
},
})
assert.NoError(t, err)
err = git_model.NewCommitStatus(db.DefaultContext, git_model.NewCommitStatusOptions{
Repo: repo2,
Creator: user2,
SHA: commit.ID,
CommitStatus: &git_model.CommitStatus{
State: structs.CommitStatusSuccess,
TargetURL: "https://example.com/tests/",
Context: "compliance/lint-backend",
},
})
assert.NoError(t, err)
contexts, err := git_model.FindRepoRecentCommitStatusContexts(db.DefaultContext, repo2.ID, time.Hour)
assert.NoError(t, err)
if assert.Len(t, contexts, 1) {
assert.Equal(t, "compliance/lint-backend", contexts[0])
}
}

View File

@ -38,10 +38,15 @@ type ProtectedBranch struct {
isPlainName bool `xorm:"-"`
CanPush bool `xorm:"NOT NULL DEFAULT false"`
EnableWhitelist bool
WhitelistUserIDs []int64 `xorm:"JSON TEXT"`
WhitelistTeamIDs []int64 `xorm:"JSON TEXT"`
WhitelistUserIDs []int64 `xorm:"JSON TEXT"`
WhitelistTeamIDs []int64 `xorm:"JSON TEXT"`
WhitelistDeployKeys bool `xorm:"NOT NULL DEFAULT false"`
CanForcePush bool `xorm:"NOT NULL DEFAULT false"`
EnableForcePushWhitelist bool
ForcePushWhitelistUserIDs []int64 `xorm:"JSON TEXT"`
ForcePushWhitelistTeamIDs []int64 `xorm:"JSON TEXT"`
ForcePushWhitelistDeployKeys bool `xorm:"NOT NULL DEFAULT false"`
EnableMergeWhitelist bool `xorm:"NOT NULL DEFAULT false"`
WhitelistDeployKeys bool `xorm:"NOT NULL DEFAULT false"`
MergeWhitelistUserIDs []int64 `xorm:"JSON TEXT"`
MergeWhitelistTeamIDs []int64 `xorm:"JSON TEXT"`
EnableStatusCheck bool `xorm:"NOT NULL DEFAULT false"`
@ -143,6 +148,33 @@ func (protectBranch *ProtectedBranch) CanUserPush(ctx context.Context, user *use
return in
}
// CanUserForcePush returns if some user could force push to this protected branch
// Since force-push extends normal push, we also check if user has regular push access
func (protectBranch *ProtectedBranch) CanUserForcePush(ctx context.Context, user *user_model.User) bool {
if !protectBranch.CanForcePush {
return false
}
if !protectBranch.EnableForcePushWhitelist {
return protectBranch.CanUserPush(ctx, user)
}
if slices.Contains(protectBranch.ForcePushWhitelistUserIDs, user.ID) {
return protectBranch.CanUserPush(ctx, user)
}
if len(protectBranch.ForcePushWhitelistTeamIDs) == 0 {
return false
}
in, err := organization.IsUserInTeams(ctx, user.ID, protectBranch.ForcePushWhitelistTeamIDs)
if err != nil {
log.Error("IsUserInTeams: %v", err)
return false
}
return in && protectBranch.CanUserPush(ctx, user)
}
// IsUserMergeWhitelisted checks if some user is whitelisted to merge to this branch
func IsUserMergeWhitelisted(ctx context.Context, protectBranch *ProtectedBranch, userID int64, permissionInRepo access_model.Permission) bool {
if !protectBranch.EnableMergeWhitelist {
@ -301,6 +333,9 @@ type WhitelistOptions struct {
UserIDs []int64
TeamIDs []int64
ForcePushUserIDs []int64
ForcePushTeamIDs []int64
MergeUserIDs []int64
MergeTeamIDs []int64
@ -328,6 +363,12 @@ func UpdateProtectBranch(ctx context.Context, repo *repo_model.Repository, prote
}
protectBranch.WhitelistUserIDs = whitelist
whitelist, err = updateUserWhitelist(ctx, repo, protectBranch.ForcePushWhitelistUserIDs, opts.ForcePushUserIDs)
if err != nil {
return err
}
protectBranch.ForcePushWhitelistUserIDs = whitelist
whitelist, err = updateUserWhitelist(ctx, repo, protectBranch.MergeWhitelistUserIDs, opts.MergeUserIDs)
if err != nil {
return err
@ -347,6 +388,12 @@ func UpdateProtectBranch(ctx context.Context, repo *repo_model.Repository, prote
}
protectBranch.WhitelistTeamIDs = whitelist
whitelist, err = updateTeamWhitelist(ctx, repo, protectBranch.ForcePushWhitelistTeamIDs, opts.ForcePushTeamIDs)
if err != nil {
return err
}
protectBranch.ForcePushWhitelistTeamIDs = whitelist
whitelist, err = updateTeamWhitelist(ctx, repo, protectBranch.MergeWhitelistTeamIDs, opts.MergeTeamIDs)
if err != nil {
return err
@ -468,43 +515,58 @@ func DeleteProtectedBranch(ctx context.Context, repo *repo_model.Repository, id
return nil
}
// RemoveUserIDFromProtectedBranch remove all user ids from protected branch options
// removeIDsFromProtectedBranch is a helper function to remove IDs from protected branch options
func removeIDsFromProtectedBranch(ctx context.Context, p *ProtectedBranch, userID, teamID int64, columnNames []string) error {
lenUserIDs, lenForcePushIDs, lenApprovalIDs, lenMergeIDs := len(p.WhitelistUserIDs), len(p.ForcePushWhitelistUserIDs), len(p.ApprovalsWhitelistUserIDs), len(p.MergeWhitelistUserIDs)
lenTeamIDs, lenForcePushTeamIDs, lenApprovalTeamIDs, lenMergeTeamIDs := len(p.WhitelistTeamIDs), len(p.ForcePushWhitelistTeamIDs), len(p.ApprovalsWhitelistTeamIDs), len(p.MergeWhitelistTeamIDs)
if userID > 0 {
p.WhitelistUserIDs = util.SliceRemoveAll(p.WhitelistUserIDs, userID)
p.ForcePushWhitelistUserIDs = util.SliceRemoveAll(p.ForcePushWhitelistUserIDs, userID)
p.ApprovalsWhitelistUserIDs = util.SliceRemoveAll(p.ApprovalsWhitelistUserIDs, userID)
p.MergeWhitelistUserIDs = util.SliceRemoveAll(p.MergeWhitelistUserIDs, userID)
}
if teamID > 0 {
p.WhitelistTeamIDs = util.SliceRemoveAll(p.WhitelistTeamIDs, teamID)
p.ForcePushWhitelistTeamIDs = util.SliceRemoveAll(p.ForcePushWhitelistTeamIDs, teamID)
p.ApprovalsWhitelistTeamIDs = util.SliceRemoveAll(p.ApprovalsWhitelistTeamIDs, teamID)
p.MergeWhitelistTeamIDs = util.SliceRemoveAll(p.MergeWhitelistTeamIDs, teamID)
}
if (lenUserIDs != len(p.WhitelistUserIDs) ||
lenForcePushIDs != len(p.ForcePushWhitelistUserIDs) ||
lenApprovalIDs != len(p.ApprovalsWhitelistUserIDs) ||
lenMergeIDs != len(p.MergeWhitelistUserIDs)) ||
(lenTeamIDs != len(p.WhitelistTeamIDs) ||
lenForcePushTeamIDs != len(p.ForcePushWhitelistTeamIDs) ||
lenApprovalTeamIDs != len(p.ApprovalsWhitelistTeamIDs) ||
lenMergeTeamIDs != len(p.MergeWhitelistTeamIDs)) {
if _, err := db.GetEngine(ctx).ID(p.ID).Cols(columnNames...).Update(p); err != nil {
return fmt.Errorf("updateProtectedBranches: %v", err)
}
}
return nil
}
// RemoveUserIDFromProtectedBranch removes all user ids from protected branch options
func RemoveUserIDFromProtectedBranch(ctx context.Context, p *ProtectedBranch, userID int64) error {
lenIDs, lenApprovalIDs, lenMergeIDs := len(p.WhitelistUserIDs), len(p.ApprovalsWhitelistUserIDs), len(p.MergeWhitelistUserIDs)
p.WhitelistUserIDs = util.SliceRemoveAll(p.WhitelistUserIDs, userID)
p.ApprovalsWhitelistUserIDs = util.SliceRemoveAll(p.ApprovalsWhitelistUserIDs, userID)
p.MergeWhitelistUserIDs = util.SliceRemoveAll(p.MergeWhitelistUserIDs, userID)
if lenIDs != len(p.WhitelistUserIDs) || lenApprovalIDs != len(p.ApprovalsWhitelistUserIDs) ||
lenMergeIDs != len(p.MergeWhitelistUserIDs) {
if _, err := db.GetEngine(ctx).ID(p.ID).Cols(
"whitelist_user_i_ds",
"merge_whitelist_user_i_ds",
"approvals_whitelist_user_i_ds",
).Update(p); err != nil {
return fmt.Errorf("updateProtectedBranches: %v", err)
}
columnNames := []string{
"whitelist_user_i_ds",
"force_push_whitelist_user_i_ds",
"merge_whitelist_user_i_ds",
"approvals_whitelist_user_i_ds",
}
return nil
return removeIDsFromProtectedBranch(ctx, p, userID, 0, columnNames)
}
// RemoveTeamIDFromProtectedBranch remove all team ids from protected branch options
// RemoveTeamIDFromProtectedBranch removes all team ids from protected branch options
func RemoveTeamIDFromProtectedBranch(ctx context.Context, p *ProtectedBranch, teamID int64) error {
lenIDs, lenApprovalIDs, lenMergeIDs := len(p.WhitelistTeamIDs), len(p.ApprovalsWhitelistTeamIDs), len(p.MergeWhitelistTeamIDs)
p.WhitelistTeamIDs = util.SliceRemoveAll(p.WhitelistTeamIDs, teamID)
p.ApprovalsWhitelistTeamIDs = util.SliceRemoveAll(p.ApprovalsWhitelistTeamIDs, teamID)
p.MergeWhitelistTeamIDs = util.SliceRemoveAll(p.MergeWhitelistTeamIDs, teamID)
if lenIDs != len(p.WhitelistTeamIDs) ||
lenApprovalIDs != len(p.ApprovalsWhitelistTeamIDs) ||
lenMergeIDs != len(p.MergeWhitelistTeamIDs) {
if _, err := db.GetEngine(ctx).ID(p.ID).Cols(
"whitelist_team_i_ds",
"merge_whitelist_team_i_ds",
"approvals_whitelist_team_i_ds",
).Update(p); err != nil {
return fmt.Errorf("updateProtectedBranches: %v", err)
}
columnNames := []string{
"whitelist_team_i_ds",
"force_push_whitelist_team_i_ds",
"merge_whitelist_team_i_ds",
"approvals_whitelist_team_i_ds",
}
return nil
return removeIDsFromProtectedBranch(ctx, p, 0, teamID, columnNames)
}

View File

@ -429,62 +429,6 @@ func UpdateIssueMentions(ctx context.Context, issueID int64, mentions []*user_mo
return nil
}
// UpdateIssueByAPI updates all allowed fields of given issue.
// If the issue status is changed a statusChangeComment is returned
// similarly if the title is changed the titleChanged bool is set to true
func UpdateIssueByAPI(ctx context.Context, issue *Issue, doer *user_model.User) (statusChangeComment *Comment, titleChanged bool, err error) {
ctx, committer, err := db.TxContext(ctx)
if err != nil {
return nil, false, err
}
defer committer.Close()
if err := issue.LoadRepo(ctx); err != nil {
return nil, false, fmt.Errorf("loadRepo: %w", err)
}
// Reload the issue
currentIssue, err := GetIssueByID(ctx, issue.ID)
if err != nil {
return nil, false, err
}
if _, err := db.GetEngine(ctx).ID(issue.ID).Cols(
"name", "content", "milestone_id", "priority",
"deadline_unix", "updated_unix", "is_locked").
Update(issue); err != nil {
return nil, false, err
}
titleChanged = currentIssue.Title != issue.Title
if titleChanged {
opts := &CreateCommentOptions{
Type: CommentTypeChangeTitle,
Doer: doer,
Repo: issue.Repo,
Issue: issue,
OldTitle: currentIssue.Title,
NewTitle: issue.Title,
}
_, err := CreateComment(ctx, opts)
if err != nil {
return nil, false, fmt.Errorf("createComment: %w", err)
}
}
if currentIssue.IsClosed != issue.IsClosed {
statusChangeComment, err = doChangeIssueStatus(ctx, issue, doer, false)
if err != nil {
return nil, false, err
}
}
if err := issue.AddCrossReferences(ctx, doer, true); err != nil {
return nil, false, err
}
return statusChangeComment, titleChanged, committer.Commit()
}
// UpdateIssueDeadline updates an issue deadline and adds comments. Setting a deadline to 0 means deleting it.
func UpdateIssueDeadline(ctx context.Context, issue *Issue, deadlineUnix timeutil.TimeStamp, doer *user_model.User) (err error) {
// if the deadline hasn't changed do nothing

View File

@ -34,7 +34,7 @@ func TestXRef_AddCrossReferences(t *testing.T) {
// Comment on PR to reopen issue #1
content = fmt.Sprintf("content2, reopens #%d", itarget.Index)
c := testCreateComment(t, 1, 2, pr.ID, content)
c := testCreateComment(t, 2, pr.ID, content)
ref = unittest.AssertExistsAndLoadBean(t, &issues_model.Comment{IssueID: itarget.ID, RefIssueID: pr.ID, RefCommentID: c.ID})
assert.Equal(t, issues_model.CommentTypeCommentRef, ref.Type)
assert.Equal(t, pr.RepoID, ref.RefRepoID)
@ -104,18 +104,18 @@ func TestXRef_ResolveCrossReferences(t *testing.T) {
pr := testCreatePR(t, 1, 2, "titlepr", fmt.Sprintf("closes #%d", i1.Index))
rp := unittest.AssertExistsAndLoadBean(t, &issues_model.Comment{IssueID: i1.ID, RefIssueID: pr.Issue.ID, RefCommentID: 0})
c1 := testCreateComment(t, 1, 2, pr.Issue.ID, fmt.Sprintf("closes #%d", i2.Index))
c1 := testCreateComment(t, 2, pr.Issue.ID, fmt.Sprintf("closes #%d", i2.Index))
r1 := unittest.AssertExistsAndLoadBean(t, &issues_model.Comment{IssueID: i2.ID, RefIssueID: pr.Issue.ID, RefCommentID: c1.ID})
// Must be ignored
c2 := testCreateComment(t, 1, 2, pr.Issue.ID, fmt.Sprintf("mentions #%d", i2.Index))
c2 := testCreateComment(t, 2, pr.Issue.ID, fmt.Sprintf("mentions #%d", i2.Index))
unittest.AssertExistsAndLoadBean(t, &issues_model.Comment{IssueID: i2.ID, RefIssueID: pr.Issue.ID, RefCommentID: c2.ID})
// Must be superseded by c4/r4
c3 := testCreateComment(t, 1, 2, pr.Issue.ID, fmt.Sprintf("reopens #%d", i3.Index))
c3 := testCreateComment(t, 2, pr.Issue.ID, fmt.Sprintf("reopens #%d", i3.Index))
unittest.AssertExistsAndLoadBean(t, &issues_model.Comment{IssueID: i3.ID, RefIssueID: pr.Issue.ID, RefCommentID: c3.ID})
c4 := testCreateComment(t, 1, 2, pr.Issue.ID, fmt.Sprintf("closes #%d", i3.Index))
c4 := testCreateComment(t, 2, pr.Issue.ID, fmt.Sprintf("closes #%d", i3.Index))
r4 := unittest.AssertExistsAndLoadBean(t, &issues_model.Comment{IssueID: i3.ID, RefIssueID: pr.Issue.ID, RefCommentID: c4.ID})
refs, err := pr.ResolveCrossReferences(db.DefaultContext)
@ -168,7 +168,7 @@ func testCreatePR(t *testing.T, repo, doer int64, title, content string) *issues
return pr
}
func testCreateComment(t *testing.T, repo, doer, issue int64, content string) *issues_model.Comment {
func testCreateComment(t *testing.T, doer, issue int64, content string) *issues_model.Comment {
d := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: doer})
i := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: issue})
c := &issues_model.Comment{Type: issues_model.CommentTypeComment, PosterID: doer, Poster: d, IssueID: issue, Issue: i, Content: content}

View File

@ -807,7 +807,7 @@ func UpdateAllowEdits(ctx context.Context, pr *PullRequest) error {
// Mergeable returns if the pullrequest is mergeable.
func (pr *PullRequest) Mergeable(ctx context.Context) bool {
// If a pull request isn't mergable if it's:
// If a pull request isn't mergeable if it's:
// - Being conflict checked.
// - Has a conflict.
// - Received a error while being conflict checked.

View File

@ -345,11 +345,9 @@ func CreateReview(ctx context.Context, opts CreateReviewOptions) (*Review, error
return nil, err
}
}
} else if opts.ReviewerTeam != nil {
review.Type = ReviewTypeRequest
review.ReviewerTeamID = opts.ReviewerTeam.ID
} else {
return nil, fmt.Errorf("provide either reviewer or reviewer team")
}

View File

@ -187,8 +187,8 @@ func AddTime(ctx context.Context, user *user_model.User, issue *Issue, amount in
Issue: issue,
Repo: issue.Repo,
Doer: user,
// Content before v1.21 did store the formated string instead of seconds,
// so use "|" as delimeter to mark the new format
// Content before v1.21 did store the formatted string instead of seconds,
// so use "|" as delimiter to mark the new format
Content: fmt.Sprintf("|%d", amount),
Type: CommentTypeAddTimeManual,
TimeID: t.ID,
@ -267,8 +267,8 @@ func DeleteIssueUserTimes(ctx context.Context, issue *Issue, user *user_model.Us
Issue: issue,
Repo: issue.Repo,
Doer: user,
// Content before v1.21 did store the formated string instead of seconds,
// so use "|" as delimeter to mark the new format
// Content before v1.21 did store the formatted string instead of seconds,
// so use "|" as delimiter to mark the new format
Content: fmt.Sprintf("|%d", removedTime),
Type: CommentTypeDeleteTimeManual,
}); err != nil {
@ -298,8 +298,8 @@ func DeleteTime(ctx context.Context, t *TrackedTime) error {
Issue: t.Issue,
Repo: t.Issue.Repo,
Doer: t.User,
// Content before v1.21 did store the formated string instead of seconds,
// so use "|" as delimeter to mark the new format
// Content before v1.21 did store the formatted string instead of seconds,
// so use "|" as delimiter to mark the new format
Content: fmt.Sprintf("|%d", t.Time),
Type: CommentTypeDeleteTimeManual,
}); err != nil {

View File

@ -177,7 +177,6 @@ func RecreateTable(sess *xorm.Session, bean any) error {
log.Error("Unable to recreate uniques on table %s. Error: %v", tableName, err)
return err
}
case setting.Database.Type.IsMySQL():
// MySQL will drop all the constraints on the old table
if _, err := sess.Exec(fmt.Sprintf("DROP TABLE `%s`", tableName)); err != nil {
@ -228,7 +227,6 @@ func RecreateTable(sess *xorm.Session, bean any) error {
return err
}
sequenceMap[sequence] = sequenceData
}
// CASCADE causes postgres to drop all the constraints on the old table
@ -293,9 +291,7 @@ func RecreateTable(sess *xorm.Session, bean any) error {
return err
}
}
}
case setting.Database.Type.IsMSSQL():
// MSSQL will drop all the constraints on the old table
if _, err := sess.Exec(fmt.Sprintf("DROP TABLE `%s`", tableName)); err != nil {
@ -308,7 +304,6 @@ func RecreateTable(sess *xorm.Session, bean any) error {
log.Error("Unable to rename %s to %s. Error: %v", tempTableName, tableName, err)
return err
}
default:
log.Fatal("Unrecognized DB")
}

View File

@ -21,7 +21,6 @@ import (
"code.gitea.io/gitea/models/migrations/v1_20"
"code.gitea.io/gitea/models/migrations/v1_21"
"code.gitea.io/gitea/models/migrations/v1_22"
"code.gitea.io/gitea/models/migrations/v1_23"
"code.gitea.io/gitea/models/migrations/v1_6"
"code.gitea.io/gitea/models/migrations/v1_7"
"code.gitea.io/gitea/models/migrations/v1_8"
@ -574,16 +573,20 @@ var migrations = []Migration{
// v293 -> v294
NewMigration("Ensure every project has exactly one default column", v1_22.CheckProjectColumnsConsistency),
// Gitea 1.22.0 ends at 294
// Gitea 1.22.0-rc0 ends at 294
// v294 -> v295
NewMigration("Add unique index for project issue table", v1_23.AddUniqueIndexForProjectIssue),
NewMigration("Add unique index for project issue table", v1_22.AddUniqueIndexForProjectIssue),
// v295 -> v296
NewMigration("Add commit status summary table", v1_23.AddCommitStatusSummary),
NewMigration("Add commit status summary table", v1_22.AddCommitStatusSummary),
// v296 -> v297
NewMigration("Add missing field of commit status summary table", v1_23.AddCommitStatusSummary2),
NewMigration("Add missing field of commit status summary table", v1_22.AddCommitStatusSummary2),
// v297 -> v298
NewMigration("Add everyone_access_mode for repo_unit", v1_23.AddRepoUnitEveryoneAccessMode),
NewMigration("Add everyone_access_mode for repo_unit", v1_22.AddRepoUnitEveryoneAccessMode),
// v298 -> v299
NewMigration("Drop wrongly created table o_auth2_application", v1_22.DropWronglyCreatedTable),
// Gitea 1.22.0-rc1 ends at 299
}
// GetCurrentDBVersion returns the current db version

View File

@ -262,7 +262,6 @@ func AddBranchProtectionCanPushAndEnableWhitelist(x *xorm.Engine) error {
for _, u := range units {
var found bool
for _, team := range teams {
var teamU []*TeamUnit
var unitEnabled bool
err = sess.Where("team_id = ?", team.ID).Find(&teamU)
@ -331,7 +330,6 @@ func AddBranchProtectionCanPushAndEnableWhitelist(x *xorm.Engine) error {
}
if !protectedBranch.EnableApprovalsWhitelist {
perm, err := getUserRepoPermission(sess, baseRepo, reviewer)
if err != nil {
return false, err

View File

@ -43,11 +43,6 @@ func RemigrateU2FCredentials(x *xorm.Engine) error {
if err != nil {
return err
}
case schemas.ORACLE:
_, err := x.Exec("ALTER TABLE webauthn_credential MODIFY credential_id VARCHAR(410)")
if err != nil {
return err
}
case schemas.MSSQL:
// This column has an index on it. I could write all of the code to attempt to change the index OR
// I could just use recreate table.

View File

@ -4,4 +4,4 @@
package v1_17 //nolint
// This migration added non-ideal indices to the action table which on larger datasets slowed things down
// it has been superceded by v218.go
// it has been superseded by v218.go

View File

@ -9,9 +9,9 @@ import (
// AddConfidentialColumnToOAuth2ApplicationTable: add ConfidentialClient column, setting existing rows to true
func AddConfidentialClientColumnToOAuth2ApplicationTable(x *xorm.Engine) error {
type OAuth2Application struct {
type oauth2Application struct {
ID int64
ConfidentialClient bool `xorm:"NOT NULL DEFAULT TRUE"`
}
return x.Sync(new(OAuth2Application))
return x.Sync(new(oauth2Application))
}

View File

@ -13,12 +13,12 @@ import (
func Test_AddConfidentialClientColumnToOAuth2ApplicationTable(t *testing.T) {
// premigration
type OAuth2Application struct {
type oauth2Application struct {
ID int64
}
// Prepare and load the testing database
x, deferable := base.PrepareTestEnv(t, 0, new(OAuth2Application))
x, deferable := base.PrepareTestEnv(t, 0, new(oauth2Application))
defer deferable()
if x == nil || t.Failed() {
return
@ -36,7 +36,7 @@ func Test_AddConfidentialClientColumnToOAuth2ApplicationTable(t *testing.T) {
}
got := []ExpectedOAuth2Application{}
if err := x.Table("o_auth2_application").Select("id, confidential_client").Find(&got); !assert.NoError(t, err) {
if err := x.Table("oauth2_application").Select("id, confidential_client").Find(&got); !assert.NoError(t, err) {
return
}

View File

@ -104,7 +104,7 @@ func ChangeContainerMetadataMultiArch(x *xorm.Engine) error {
// Convert to new metadata format
new := &MetadataNew{
newMetadata := &MetadataNew{
Type: old.Type,
IsTagged: old.IsTagged,
Platform: old.Platform,
@ -119,7 +119,7 @@ func ChangeContainerMetadataMultiArch(x *xorm.Engine) error {
Manifests: manifests,
}
metadataJSON, err := json.Marshal(new)
metadataJSON, err := json.Marshal(newMetadata)
if err != nil {
return err
}

View File

@ -53,7 +53,7 @@ func expandHashReferencesToSha256(x *xorm.Engine) error {
if setting.Database.Type.IsMySQL() {
_, err = db.Exec(fmt.Sprintf("ALTER TABLE `%s` MODIFY COLUMN `%s` VARCHAR(64)", alts[0], alts[1]))
} else if setting.Database.Type.IsMSSQL() {
_, err = db.Exec(fmt.Sprintf("ALTER TABLE [%s] ALTER COLUMN [%s] VARCHAR(64)", alts[0], alts[1]))
_, err = db.Exec(fmt.Sprintf("ALTER TABLE [%s] ALTER COLUMN [%s] NVARCHAR(64)", alts[0], alts[1]))
} else {
_, err = db.Exec(fmt.Sprintf("ALTER TABLE `%s` ALTER COLUMN `%s` TYPE VARCHAR(64)", alts[0], alts[1]))
}

View File

@ -1,7 +1,7 @@
// Copyright 2024 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package v1_23 //nolint
package v1_22 //nolint
import (
"fmt"

View File

@ -1,7 +1,7 @@
// Copyright 2024 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package v1_23 //nolint
package v1_22 //nolint
import (
"slices"

View File

@ -1,7 +1,7 @@
// Copyright 2024 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package v1_23 //nolint
package v1_22 //nolint
import "xorm.io/xorm"

View File

@ -1,7 +1,7 @@
// Copyright 2024 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package v1_23 //nolint
package v1_22 //nolint
import "xorm.io/xorm"

View File

@ -1,7 +1,7 @@
// Copyright 2024 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package v1_23 //nolint
package v1_22 //nolint
import (
"code.gitea.io/gitea/models/perm"

View File

@ -0,0 +1,10 @@
// Copyright 2024 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package v1_22 //nolint
import "xorm.io/xorm"
func DropWronglyCreatedTable(x *xorm.Engine) error {
return x.DropTables("o_auth2_application")
}

View File

@ -61,7 +61,6 @@ func AddScratchHash(x *xorm.Engine) error {
if _, err := sess.ID(tfa.ID).Cols("scratch_salt, scratch_hash").Update(tfa); err != nil {
return fmt.Errorf("couldn't add in scratch_hash and scratch_salt: %w", err)
}
}
}

View File

@ -81,7 +81,6 @@ func HashAppToken(x *xorm.Engine) error {
if _, err := sess.ID(token.ID).Cols("token_hash, token_salt, token_last_eight, sha1").Update(token); err != nil {
return fmt.Errorf("couldn't add in sha1, token_hash, token_salt and token_last_eight: %w", err)
}
}
}

View File

@ -291,15 +291,15 @@ func TestAccessibleReposEnv_CountRepos(t *testing.T) {
func TestAccessibleReposEnv_RepoIDs(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase())
org := unittest.AssertExistsAndLoadBean(t, &organization.Organization{ID: 3})
testSuccess := func(userID, _, pageSize int64, expectedRepoIDs []int64) {
testSuccess := func(userID int64, expectedRepoIDs []int64) {
env, err := organization.AccessibleReposEnv(db.DefaultContext, org, userID)
assert.NoError(t, err)
repoIDs, err := env.RepoIDs(1, 100)
assert.NoError(t, err)
assert.Equal(t, expectedRepoIDs, repoIDs)
}
testSuccess(2, 1, 100, []int64{3, 5, 32})
testSuccess(4, 0, 100, []int64{3, 32})
testSuccess(2, []int64{3, 5, 32})
testSuccess(4, []int64{3, 32})
}
func TestAccessibleReposEnv_Repos(t *testing.T) {

View File

@ -226,9 +226,8 @@ func GetTeamIDsByNames(ctx context.Context, orgID int64, names []string, ignoreN
if err != nil {
if ignoreNonExistent {
continue
} else {
return nil, err
}
return nil, err
}
ids = append(ids, u.ID)
}

View File

@ -110,13 +110,11 @@ func createBoardsForProjectsType(ctx context.Context, project *Project) error {
var items []string
switch project.BoardType {
case BoardTypeBugTriage:
items = setting.Project.ProjectBoardBugTriageType
case BoardTypeBasicKanban:
items = setting.Project.ProjectBoardBasicKanbanType
case BoardTypeNone:
fallthrough
default:

View File

@ -9,10 +9,10 @@ import (
"image/png"
"io"
"net/url"
"strings"
"code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/modules/avatar"
"code.gitea.io/gitea/modules/httplib"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/storage"
@ -84,13 +84,7 @@ func (repo *Repository) relAvatarLink(ctx context.Context) string {
return setting.AppSubURL + "/repo-avatars/" + url.PathEscape(repo.Avatar)
}
// AvatarLink returns a link to the repository's avatar.
// AvatarLink returns the full avatar url with http host. TODO: refactor it to a relative URL, but it is still used in API response at the moment
func (repo *Repository) AvatarLink(ctx context.Context) string {
link := repo.relAvatarLink(ctx)
// we only prepend our AppURL to our known (relative, internal) avatar link to get an absolute URL
if strings.HasPrefix(link, "/") && !strings.HasPrefix(link, "//") {
return setting.AppURL + strings.TrimPrefix(link, setting.AppSubURL)[1:]
}
// otherwise, return the link as it is
return link
return httplib.MakeAbsoluteURL(ctx, repo.relAvatarLink(ctx))
}

View File

@ -8,14 +8,14 @@ import "code.gitea.io/gitea/models/db"
// SearchOrderByMap represents all possible search order
var SearchOrderByMap = map[string]map[string]db.SearchOrderBy{
"asc": {
"alpha": db.SearchOrderByAlphabetically,
"alpha": "owner_name ASC, name ASC",
"created": db.SearchOrderByOldest,
"updated": db.SearchOrderByLeastUpdated,
"size": db.SearchOrderBySize,
"id": db.SearchOrderByID,
},
"desc": {
"alpha": db.SearchOrderByAlphabeticallyReverse,
"alpha": "owner_name DESC, name DESC",
"created": db.SearchOrderByNewest,
"updated": db.SearchOrderByRecentUpdated,
"size": db.SearchOrderBySizeReverse,

View File

@ -130,7 +130,10 @@ func GetRepoAssignees(ctx context.Context, repo *Repository) (_ []*user_model.Us
// and just waste 1 unit is cheaper than re-allocate memory once.
users := make([]*user_model.User, 0, len(uniqueUserIDs)+1)
if len(userIDs) > 0 {
if err = e.In("id", uniqueUserIDs.Values()).OrderBy(user_model.GetOrderByName()).Find(&users); err != nil {
if err = e.In("id", uniqueUserIDs.Values()).
Where(builder.Eq{"`user`.is_active": true}).
OrderBy(user_model.GetOrderByName()).
Find(&users); err != nil {
return nil, err
}
}
@ -152,7 +155,8 @@ func GetReviewers(ctx context.Context, repo *Repository, doerID, posterID int64)
return nil, err
}
cond := builder.And(builder.Neq{"`user`.id": posterID})
cond := builder.And(builder.Neq{"`user`.id": posterID}).
And(builder.Eq{"`user`.is_active": true})
if repo.IsPrivate || repo.Owner.Visibility == api.VisibleTypePrivate {
// This a private repository:
@ -170,7 +174,6 @@ func GetReviewers(ctx context.Context, repo *Repository, doerID, posterID int64)
// the owner of a private repo needs to be explicitly added.
cond = cond.Or(builder.Eq{"`user`.id": repo.Owner.ID})
}
} else {
// This is a "public" repository:
// Any user that has read access, is a watcher or organization member can be requested to review

View File

@ -9,6 +9,7 @@ import (
"code.gitea.io/gitea/models/db"
repo_model "code.gitea.io/gitea/models/repo"
"code.gitea.io/gitea/models/unittest"
user_model "code.gitea.io/gitea/models/user"
"github.com/stretchr/testify/assert"
)
@ -25,8 +26,17 @@ func TestRepoAssignees(t *testing.T) {
repo21 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 21})
users, err = repo_model.GetRepoAssignees(db.DefaultContext, repo21)
assert.NoError(t, err)
assert.Len(t, users, 4)
assert.ElementsMatch(t, []int64{10, 15, 16, 18}, []int64{users[0].ID, users[1].ID, users[2].ID, users[3].ID})
if assert.Len(t, users, 4) {
assert.ElementsMatch(t, []int64{10, 15, 16, 18}, []int64{users[0].ID, users[1].ID, users[2].ID, users[3].ID})
}
// do not return deactivated users
assert.NoError(t, user_model.UpdateUserCols(db.DefaultContext, &user_model.User{ID: 15, IsActive: false}, "is_active"))
users, err = repo_model.GetRepoAssignees(db.DefaultContext, repo21)
assert.NoError(t, err)
if assert.Len(t, users, 3) {
assert.NotContains(t, []int64{users[0].ID, users[1].ID, users[2].ID}, 15)
}
}
func TestRepoGetReviewers(t *testing.T) {
@ -38,17 +48,19 @@ func TestRepoGetReviewers(t *testing.T) {
ctx := db.DefaultContext
reviewers, err := repo_model.GetReviewers(ctx, repo1, 2, 2)
assert.NoError(t, err)
assert.Len(t, reviewers, 4)
if assert.Len(t, reviewers, 3) {
assert.ElementsMatch(t, []int64{1, 4, 11}, []int64{reviewers[0].ID, reviewers[1].ID, reviewers[2].ID})
}
// should include doer if doer is not PR poster.
reviewers, err = repo_model.GetReviewers(ctx, repo1, 11, 2)
assert.NoError(t, err)
assert.Len(t, reviewers, 4)
assert.Len(t, reviewers, 3)
// should not include PR poster, if PR poster would be otherwise eligible
reviewers, err = repo_model.GetReviewers(ctx, repo1, 11, 4)
assert.NoError(t, err)
assert.Len(t, reviewers, 3)
assert.Len(t, reviewers, 2)
// test private user repo
repo2 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 2})

View File

@ -6,7 +6,6 @@ package unittest
import (
"context"
"fmt"
"log"
"os"
"path/filepath"
"strings"
@ -16,7 +15,9 @@ import (
"code.gitea.io/gitea/models/system"
"code.gitea.io/gitea/modules/auth/password/hash"
"code.gitea.io/gitea/modules/base"
"code.gitea.io/gitea/modules/cache"
"code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/setting/config"
"code.gitea.io/gitea/modules/storage"
@ -45,6 +46,14 @@ func fatalTestError(fmtStr string, args ...any) {
// InitSettings initializes config provider and load common settings for tests
func InitSettings() {
setting.IsInTesting = true
log.OsExiter = func(code int) {
if code != 0 {
// non-zero exit code (log.Fatal) shouldn't occur during testing, if it happens, show a full stacktrace for more details
panic(fmt.Errorf("non-zero exit code during testing: %d", code))
}
os.Exit(0)
}
if setting.CustomConf == "" {
setting.CustomConf = filepath.Join(setting.CustomPath, "conf/app-unittest-tmp.ini")
_ = os.Remove(setting.CustomConf)
@ -53,7 +62,7 @@ func InitSettings() {
setting.LoadCommonSettings()
if err := setting.PrepareAppDataPath(); err != nil {
log.Fatalf("Can not prepare APP_DATA_PATH: %v", err)
log.Fatal("Can not prepare APP_DATA_PATH: %v", err)
}
// register the dummy hash algorithm function used in the test fixtures
_ = hash.Register("dummy", hash.NewDummyHasher)
@ -106,6 +115,7 @@ func MainTest(m *testing.M, testOpts ...*TestOptions) {
fatalTestError("Error creating test engine: %v\n", err)
}
setting.IsInTesting = true
setting.AppURL = "https://try.gitea.io/"
setting.RunUser = "runuser"
setting.SSH.User = "sshuser"
@ -148,6 +158,9 @@ func MainTest(m *testing.M, testOpts ...*TestOptions) {
config.SetDynGetter(system.NewDatabaseDynKeyGetter())
if err = cache.Init(); err != nil {
fatalTestError("cache.Init: %v\n", err)
}
if err = storage.Init(); err != nil {
fatalTestError("storage.Init: %v\n", err)
}

View File

@ -9,11 +9,11 @@ import (
"fmt"
"image/png"
"io"
"strings"
"code.gitea.io/gitea/models/avatars"
"code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/modules/avatar"
"code.gitea.io/gitea/modules/httplib"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/storage"
@ -89,13 +89,9 @@ func (u *User) AvatarLinkWithSize(ctx context.Context, size int) string {
return avatars.GenerateEmailAvatarFastLink(ctx, u.AvatarEmail, size)
}
// AvatarLink returns the full avatar link with http host
// AvatarLink returns the full avatar url with http host. TODO: refactor it to a relative URL, but it is still used in API response at the moment
func (u *User) AvatarLink(ctx context.Context) string {
link := u.AvatarLinkWithSize(ctx, 0)
if !strings.HasPrefix(link, "//") && !strings.Contains(link, "://") {
return setting.AppURL + strings.TrimPrefix(link, setting.AppSubURL+"/")
}
return link
return httplib.MakeAbsoluteURL(ctx, u.AvatarLinkWithSize(ctx, 0))
}
// IsUploadAvatarChanged returns true if the current user's avatar would be changed with the provided data

View File

@ -501,19 +501,19 @@ func GetUserSalt() (string, error) {
// Note: The set of characters here can safely expand without a breaking change,
// but characters removed from this set can cause user account linking to break
var (
customCharsReplacement = strings.NewReplacer("Æ", "AE")
removeCharsRE = regexp.MustCompile(`['´\x60]`)
removeDiacriticsTransform = transform.Chain(norm.NFD, runes.Remove(runes.In(unicode.Mn)), norm.NFC)
replaceCharsHyphenRE = regexp.MustCompile(`[\s~+]`)
customCharsReplacement = strings.NewReplacer("Æ", "AE")
removeCharsRE = regexp.MustCompile("['`´]")
transformDiacritics = transform.Chain(norm.NFD, runes.Remove(runes.In(unicode.Mn)), norm.NFC)
replaceCharsHyphenRE = regexp.MustCompile(`[\s~+]`)
)
// normalizeUserName returns a string with single-quotes and diacritics
// removed, and any other non-supported username characters replaced with
// a `-` character
// NormalizeUserName only takes the name part if it is an email address, transforms it diacritics to ASCII characters.
// It returns a string with the single-quotes removed, and any other non-supported username characters are replaced with a `-` character
func NormalizeUserName(s string) (string, error) {
strDiacriticsRemoved, n, err := transform.String(removeDiacriticsTransform, customCharsReplacement.Replace(s))
s, _, _ = strings.Cut(s, "@")
strDiacriticsRemoved, n, err := transform.String(transformDiacritics, customCharsReplacement.Replace(s))
if err != nil {
return "", fmt.Errorf("Failed to normalize character `%v` in provided username `%v`", s[n], s)
return "", fmt.Errorf("failed to normalize the string of provided username %q at position %d", s, n)
}
return replaceCharsHyphenRE.ReplaceAllLiteralString(removeCharsRE.ReplaceAllLiteralString(strDiacriticsRemoved, ""), "-"), nil
}
@ -988,9 +988,8 @@ func GetUserIDsByNames(ctx context.Context, names []string, ignoreNonExistent bo
if err != nil {
if ignoreNonExistent {
continue
} else {
return nil, err
}
return nil, err
}
ids = append(ids, u.ID)
}

View File

@ -5,8 +5,8 @@ package user_test
import (
"context"
"crypto/rand"
"fmt"
"math/rand"
"strings"
"testing"
"time"
@ -506,15 +506,16 @@ func Test_NormalizeUserFromEmail(t *testing.T) {
Expected string
IsNormalizedValid bool
}{
{"test", "test", true},
{"name@example.com", "name", true},
{"test'`´name", "testname", true},
{"Sinéad.O'Connor", "Sinead.OConnor", true},
{"Æsir", "AEsir", true},
// \u00e9\u0065\u0301
{"éé", "ee", true},
{"éé", "ee", true}, // \u00e9\u0065\u0301
{"Awareness Hub", "Awareness-Hub", true},
{"double__underscore", "double__underscore", false}, // We should consider squashing double non-alpha characters
{".bad.", ".bad.", false},
{"new😀user", "new😀user", false}, // No plans to support
{`"quoted"`, `"quoted"`, false}, // No plans to support
}
for _, testCase := range testCases {
normalizedName, err := user_model.NormalizeUserName(testCase.Input)

View File

@ -208,14 +208,14 @@ func detectMatched(gitRepo *git.Repository, commit *git.Commit, triggedEvent web
webhook_module.HookEventIssueAssign,
webhook_module.HookEventIssueLabel,
webhook_module.HookEventIssueMilestone:
return matchIssuesEvent(commit, payload.(*api.IssuePayload), evt)
return matchIssuesEvent(payload.(*api.IssuePayload), evt)
case // issue_comment
webhook_module.HookEventIssueComment,
// `pull_request_comment` is same as `issue_comment`
// See https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#pull_request_comment-use-issue_comment
webhook_module.HookEventPullRequestComment:
return matchIssueCommentEvent(commit, payload.(*api.IssueCommentPayload), evt)
return matchIssueCommentEvent(payload.(*api.IssueCommentPayload), evt)
case // pull_request
webhook_module.HookEventPullRequest,
@ -229,19 +229,19 @@ func detectMatched(gitRepo *git.Repository, commit *git.Commit, triggedEvent web
case // pull_request_review
webhook_module.HookEventPullRequestReviewApproved,
webhook_module.HookEventPullRequestReviewRejected:
return matchPullRequestReviewEvent(commit, payload.(*api.PullRequestPayload), evt)
return matchPullRequestReviewEvent(payload.(*api.PullRequestPayload), evt)
case // pull_request_review_comment
webhook_module.HookEventPullRequestReviewComment:
return matchPullRequestReviewCommentEvent(commit, payload.(*api.PullRequestPayload), evt)
return matchPullRequestReviewCommentEvent(payload.(*api.PullRequestPayload), evt)
case // release
webhook_module.HookEventRelease:
return matchReleaseEvent(commit, payload.(*api.ReleasePayload), evt)
return matchReleaseEvent(payload.(*api.ReleasePayload), evt)
case // registry_package
webhook_module.HookEventPackage:
return matchPackageEvent(commit, payload.(*api.PackagePayload), evt)
return matchPackageEvent(payload.(*api.PackagePayload), evt)
default:
log.Warn("unsupported event %q", triggedEvent)
@ -347,7 +347,7 @@ func matchPushEvent(commit *git.Commit, pushPayload *api.PushPayload, evt *jobpa
return matchTimes == len(evt.Acts())
}
func matchIssuesEvent(commit *git.Commit, issuePayload *api.IssuePayload, evt *jobparser.Event) bool {
func matchIssuesEvent(issuePayload *api.IssuePayload, evt *jobparser.Event) bool {
// with no special filter parameters
if len(evt.Acts()) == 0 {
return true
@ -495,7 +495,7 @@ func matchPullRequestEvent(gitRepo *git.Repository, commit *git.Commit, prPayloa
return activityTypeMatched && matchTimes == len(evt.Acts())
}
func matchIssueCommentEvent(commit *git.Commit, issueCommentPayload *api.IssueCommentPayload, evt *jobparser.Event) bool {
func matchIssueCommentEvent(issueCommentPayload *api.IssueCommentPayload, evt *jobparser.Event) bool {
// with no special filter parameters
if len(evt.Acts()) == 0 {
return true
@ -527,7 +527,7 @@ func matchIssueCommentEvent(commit *git.Commit, issueCommentPayload *api.IssueCo
return matchTimes == len(evt.Acts())
}
func matchPullRequestReviewEvent(commit *git.Commit, prPayload *api.PullRequestPayload, evt *jobparser.Event) bool {
func matchPullRequestReviewEvent(prPayload *api.PullRequestPayload, evt *jobparser.Event) bool {
// with no special filter parameters
if len(evt.Acts()) == 0 {
return true
@ -576,7 +576,7 @@ func matchPullRequestReviewEvent(commit *git.Commit, prPayload *api.PullRequestP
return matchTimes == len(evt.Acts())
}
func matchPullRequestReviewCommentEvent(commit *git.Commit, prPayload *api.PullRequestPayload, evt *jobparser.Event) bool {
func matchPullRequestReviewCommentEvent(prPayload *api.PullRequestPayload, evt *jobparser.Event) bool {
// with no special filter parameters
if len(evt.Acts()) == 0 {
return true
@ -625,7 +625,7 @@ func matchPullRequestReviewCommentEvent(commit *git.Commit, prPayload *api.PullR
return matchTimes == len(evt.Acts())
}
func matchReleaseEvent(commit *git.Commit, payload *api.ReleasePayload, evt *jobparser.Event) bool {
func matchReleaseEvent(payload *api.ReleasePayload, evt *jobparser.Event) bool {
// with no special filter parameters
if len(evt.Acts()) == 0 {
return true
@ -662,7 +662,7 @@ func matchReleaseEvent(commit *git.Commit, payload *api.ReleasePayload, evt *job
return matchTimes == len(evt.Acts())
}
func matchPackageEvent(commit *git.Commit, payload *api.PackagePayload, evt *jobparser.Event) bool {
func matchPackageEvent(payload *api.PackagePayload, evt *jobparser.Event) bool {
// with no special filter parameters
if len(evt.Acts()) == 0 {
return true

View File

@ -63,16 +63,16 @@ func NewComplexity() {
func setupComplexity(values []string) {
if len(values) != 1 || values[0] != "off" {
for _, val := range values {
if complex, ok := charComplexities[val]; ok {
validChars += complex.ValidChars
requiredList = append(requiredList, complex)
if complexity, ok := charComplexities[val]; ok {
validChars += complexity.ValidChars
requiredList = append(requiredList, complexity)
}
}
if len(requiredList) == 0 {
// No valid character classes found; use all classes as default
for _, complex := range charComplexities {
validChars += complex.ValidChars
requiredList = append(requiredList, complex)
for _, complexity := range charComplexities {
validChars += complexity.ValidChars
requiredList = append(requiredList, complexity)
}
}
}

View File

@ -4,13 +4,11 @@
package pwn
import (
"math/rand"
"net/http"
"os"
"strings"
"testing"
"time"
"github.com/h2non/gock"
"github.com/stretchr/testify/assert"
)
@ -18,92 +16,35 @@ var client = New(WithHTTP(&http.Client{
Timeout: time.Second * 2,
}))
func TestMain(m *testing.M) {
rand.Seed(time.Now().Unix())
os.Exit(m.Run())
}
func TestPassword(t *testing.T) {
// Check input error
_, err := client.CheckPassword("", false)
defer gock.Off()
count, err := client.CheckPassword("", false)
assert.ErrorIs(t, err, ErrEmptyPassword, "blank input should return ErrEmptyPassword")
assert.Equal(t, -1, count)
// Should fail
fail := "password1234"
count, err := client.CheckPassword(fail, false)
assert.NotEmpty(t, count, "%s should fail as a password", fail)
gock.New("https://api.pwnedpasswords.com").Get("/range/5c1d8").Times(1).Reply(200).BodyString("EAF2F254732680E8AC339B84F3266ECCBB5:1\r\nFC446EB88938834178CB9322C1EE273C2A7:2")
count, err = client.CheckPassword("pwned", false)
assert.NoError(t, err)
assert.Equal(t, 1, count)
// Should fail (with padding)
failPad := "administrator"
count, err = client.CheckPassword(failPad, true)
assert.NotEmpty(t, count, "%s should fail as a password", failPad)
gock.New("https://api.pwnedpasswords.com").Get("/range/ba189").Times(1).Reply(200).BodyString("FD4CB34F0378BCB15D23F6FFD28F0775C9E:3\r\nFDF342FCD8C3611DAE4D76E8A992A3E4169:4")
count, err = client.CheckPassword("notpwned", false)
assert.NoError(t, err)
assert.Equal(t, 0, count)
// Checking for a "good" password isn't going to be perfect, but we can give it a good try
// with hopefully minimal error. Try five times?
assert.Condition(t, func() bool {
for i := 0; i <= 5; i++ {
count, err = client.CheckPassword(testPassword(), false)
assert.NoError(t, err)
if count == 0 {
return true
}
}
return false
}, "no generated passwords passed. there is a chance this is a fluke")
gock.New("https://api.pwnedpasswords.com").Get("/range/a1733").Times(1).Reply(200).BodyString("C4CE0F1F0062B27B9E2F41AF0C08218017C:1\r\nFC446EB88938834178CB9322C1EE273C2A7:2\r\nFE81480327C992FE62065A827429DD1318B:0")
count, err = client.CheckPassword("paddedpwned", true)
assert.NoError(t, err)
assert.Equal(t, 1, count)
// Again, but with padded responses
assert.Condition(t, func() bool {
for i := 0; i <= 5; i++ {
count, err = client.CheckPassword(testPassword(), true)
assert.NoError(t, err)
if count == 0 {
return true
}
}
return false
}, "no generated passwords passed. there is a chance this is a fluke")
}
// Credit to https://golangbyexample.com/generate-random-password-golang/
// DO NOT USE THIS FOR AN ACTUAL PASSWORD GENERATOR
var (
lowerCharSet = "abcdedfghijklmnopqrst"
upperCharSet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
specialCharSet = "!@#$%&*"
numberSet = "0123456789"
allCharSet = lowerCharSet + upperCharSet + specialCharSet + numberSet
)
func testPassword() string {
var password strings.Builder
// Set special character
for i := 0; i < 5; i++ {
random := rand.Intn(len(specialCharSet))
password.WriteString(string(specialCharSet[random]))
}
// Set numeric
for i := 0; i < 5; i++ {
random := rand.Intn(len(numberSet))
password.WriteString(string(numberSet[random]))
}
// Set uppercase
for i := 0; i < 5; i++ {
random := rand.Intn(len(upperCharSet))
password.WriteString(string(upperCharSet[random]))
}
for i := 0; i < 5; i++ {
random := rand.Intn(len(allCharSet))
password.WriteString(string(allCharSet[random]))
}
inRune := []rune(password.String())
rand.Shuffle(len(inRune), func(i, j int) {
inRune[i], inRune[j] = inRune[j], inRune[i]
})
return string(inRune)
gock.New("https://api.pwnedpasswords.com").Get("/range/5617b").Times(1).Reply(200).BodyString("FD4CB34F0378BCB15D23F6FFD28F0775C9E:3\r\nFDF342FCD8C3611DAE4D76E8A992A3E4169:4\r\nFE81480327C992FE62065A827429DD1318B:0")
count, err = client.CheckPassword("paddednotpwned", true)
assert.NoError(t, err)
assert.Equal(t, 0, count)
gock.New("https://api.pwnedpasswords.com").Get("/range/79082").Times(1).Reply(200).BodyString("FDF342FCD8C3611DAE4D76E8A992A3E4169:4\r\nFE81480327C992FE62065A827429DD1318B:0\r\nAFEF386F56EB0B4BE314E07696E5E6E6536:0")
count, err = client.CheckPassword("paddednotpwnedzero", true)
assert.NoError(t, err)
assert.Equal(t, 0, count)
}

View File

@ -307,10 +307,10 @@ func ParseTreeLine(objectFormat ObjectFormat, rd *bufio.Reader, modeBuf, fnameBu
// Deal with the binary hash
idx = 0
len := objectFormat.FullLength() / 2
for idx < len {
length := objectFormat.FullLength() / 2
for idx < length {
var read int
read, err = rd.Read(shaBuf[idx:len])
read, err = rd.Read(shaBuf[idx:length])
n += read
if err != nil {
return mode, fname, sha, n, err

View File

@ -132,7 +132,7 @@ func (r *BlameReader) Close() error {
// CreateBlameReader creates reader for given repository, commit and file
func CreateBlameReader(ctx context.Context, objectFormat ObjectFormat, repoPath string, commit *Commit, file string, bypassBlameIgnore bool) (*BlameReader, error) {
var ignoreRevsFile *string
if CheckGitVersionAtLeast("2.23") == nil && !bypassBlameIgnore {
if DefaultFeatures().CheckVersionAtLeast("2.23") && !bypassBlameIgnore {
ignoreRevsFile = tryCreateBlameIgnoreRevsFile(commit)
}

View File

@ -423,7 +423,7 @@ func (c *Commit) GetSubModule(entryname string) (*SubModule, error) {
// GetBranchName gets the closest branch name (as returned by 'git name-rev --name-only')
func (c *Commit) GetBranchName() (string, error) {
cmd := NewCommand(c.repo.Ctx, "name-rev")
if CheckGitVersionAtLeast("2.13.0") == nil {
if DefaultFeatures().CheckVersionAtLeast("2.13.0") {
cmd.AddArguments("--exclude", "refs/tags/*")
}
cmd.AddArguments("--name-only", "--no-undefined").AddDynamicArguments(c.ID.String())

View File

@ -29,7 +29,7 @@ func (tes Entries) GetCommitsInfo(ctx context.Context, commit *Commit, treePath
var revs map[string]*Commit
if commit.repo.LastCommitCache != nil {
var unHitPaths []string
revs, unHitPaths, err = getLastCommitForPathsByCache(ctx, commit.ID.String(), treePath, entryPaths, commit.repo.LastCommitCache)
revs, unHitPaths, err = getLastCommitForPathsByCache(commit.ID.String(), treePath, entryPaths, commit.repo.LastCommitCache)
if err != nil {
return nil, nil, err
}
@ -97,7 +97,7 @@ func (tes Entries) GetCommitsInfo(ctx context.Context, commit *Commit, treePath
return commitsInfo, treeCommit, nil
}
func getLastCommitForPathsByCache(ctx context.Context, commitID, treePath string, paths []string, cache *LastCommitCache) (map[string]*Commit, []string, error) {
func getLastCommitForPathsByCache(commitID, treePath string, paths []string, cache *LastCommitCache) (map[string]*Commit, []string, error) {
var unHitEntryPaths []string
results := make(map[string]*Commit)
for _, p := range paths {

View File

@ -49,9 +49,8 @@ readLoop:
if len(line) > 0 && line[0] == ' ' {
_, _ = signatureSB.Write(line[1:])
continue
} else {
pgpsig = false
}
pgpsig = false
}
if !message {

View File

@ -22,42 +22,63 @@ import (
"github.com/hashicorp/go-version"
)
// RequiredVersion is the minimum Git version required
const RequiredVersion = "2.0.0"
const RequiredVersion = "2.0.0" // the minimum Git version required
type Features struct {
gitVersion *version.Version
UsingGogit bool
SupportProcReceive bool // >= 2.29
SupportHashSha256 bool // >= 2.42, SHA-256 repositories no longer an experimental curiosity
SupportedObjectFormats []ObjectFormat // sha1, sha256
}
var (
// GitExecutable is the command name of git
// Could be updated to an absolute path while initialization
GitExecutable = "git"
// DefaultContext is the default context to run git commands in, must be initialized by git.InitXxx
DefaultContext context.Context
DefaultFeatures struct {
GitVersion *version.Version
SupportProcReceive bool // >= 2.29
SupportHashSha256 bool // >= 2.42, SHA-256 repositories no longer an experimental curiosity
}
GitExecutable = "git" // the command name of git, will be updated to an absolute path during initialization
DefaultContext context.Context // the default context to run git commands in, must be initialized by git.InitXxx
defaultFeatures *Features
)
// loadGitVersion tries to get the current git version and stores it into a global variable
func loadGitVersion() error {
// doesn't need RWMutex because it's executed by Init()
if DefaultFeatures.GitVersion != nil {
return nil
}
func (f *Features) CheckVersionAtLeast(atLeast string) bool {
return f.gitVersion.Compare(version.Must(version.NewVersion(atLeast))) >= 0
}
// VersionInfo returns git version information
func (f *Features) VersionInfo() string {
return f.gitVersion.Original()
}
func DefaultFeatures() *Features {
if defaultFeatures == nil {
if !setting.IsProd || setting.IsInTesting {
log.Warn("git.DefaultFeatures is called before git.InitXxx, initializing with default values")
}
if err := InitSimple(context.Background()); err != nil {
log.Fatal("git.InitSimple failed: %v", err)
}
}
return defaultFeatures
}
func loadGitVersionFeatures() (*Features, error) {
stdout, _, runErr := NewCommand(DefaultContext, "version").RunStdString(nil)
if runErr != nil {
return runErr
return nil, runErr
}
ver, err := parseGitVersionLine(strings.TrimSpace(stdout))
if err == nil {
DefaultFeatures.GitVersion = ver
if err != nil {
return nil, err
}
return err
features := &Features{gitVersion: ver, UsingGogit: isGogit}
features.SupportProcReceive = features.CheckVersionAtLeast("2.29")
features.SupportHashSha256 = features.CheckVersionAtLeast("2.42") && !isGogit
features.SupportedObjectFormats = []ObjectFormat{Sha1ObjectFormat}
if features.SupportHashSha256 {
features.SupportedObjectFormats = append(features.SupportedObjectFormats, Sha256ObjectFormat)
}
return features, nil
}
func parseGitVersionLine(s string) (*version.Version, error) {
@ -85,56 +106,24 @@ func SetExecutablePath(path string) error {
return fmt.Errorf("git not found: %w", err)
}
GitExecutable = absPath
return nil
}
if err = loadGitVersion(); err != nil {
return fmt.Errorf("unable to load git version: %w", err)
}
versionRequired, err := version.NewVersion(RequiredVersion)
if err != nil {
return err
}
if DefaultFeatures.GitVersion.LessThan(versionRequired) {
func ensureGitVersion() error {
if !DefaultFeatures().CheckVersionAtLeast(RequiredVersion) {
moreHint := "get git: https://git-scm.com/download/"
if runtime.GOOS == "linux" {
// there are a lot of CentOS/RHEL users using old git, so we add a special hint for them
if _, err = os.Stat("/etc/redhat-release"); err == nil {
if _, err := os.Stat("/etc/redhat-release"); err == nil {
// ius.io is the recommended official(git-scm.com) method to install git
moreHint = "get git: https://git-scm.com/download/linux and https://ius.io"
}
}
return fmt.Errorf("installed git version %q is not supported, Gitea requires git version >= %q, %s", DefaultFeatures.GitVersion.Original(), RequiredVersion, moreHint)
return fmt.Errorf("installed git version %q is not supported, Gitea requires git version >= %q, %s", DefaultFeatures().gitVersion.Original(), RequiredVersion, moreHint)
}
if err = checkGitVersionCompatibility(DefaultFeatures.GitVersion); err != nil {
return fmt.Errorf("installed git version %s has a known compatibility issue with Gitea: %w, please upgrade (or downgrade) git", DefaultFeatures.GitVersion.String(), err)
}
return nil
}
// VersionInfo returns git version information
func VersionInfo() string {
if DefaultFeatures.GitVersion == nil {
return "(git not found)"
}
format := "%s"
args := []any{DefaultFeatures.GitVersion.Original()}
// Since git wire protocol has been released from git v2.18
if setting.Git.EnableAutoGitWireProtocol && CheckGitVersionAtLeast("2.18") == nil {
format += ", Wire Protocol %s Enabled"
args = append(args, "Version 2") // for focus color
}
return fmt.Sprintf(format, args...)
}
func checkInit() error {
if setting.Git.HomePath == "" {
return errors.New("unable to init Git's HomeDir, incorrect initialization of the setting and git modules")
}
if DefaultContext != nil {
log.Warn("git module has been initialized already, duplicate init may work but it's better to fix it")
if err := checkGitVersionCompatibility(DefaultFeatures().gitVersion); err != nil {
return fmt.Errorf("installed git version %s has a known compatibility issue with Gitea: %w, please upgrade (or downgrade) git", DefaultFeatures().gitVersion.String(), err)
}
return nil
}
@ -154,8 +143,12 @@ func HomeDir() string {
// InitSimple initializes git module with a very simple step, no config changes, no global command arguments.
// This method doesn't change anything to filesystem. At the moment, it is only used by some Gitea sub-commands.
func InitSimple(ctx context.Context) error {
if err := checkInit(); err != nil {
return err
if setting.Git.HomePath == "" {
return errors.New("unable to init Git's HomeDir, incorrect initialization of the setting and git modules")
}
if DefaultContext != nil && (!setting.IsProd || setting.IsInTesting) {
log.Warn("git module has been initialized already, duplicate init may work but it's better to fix it")
}
DefaultContext = ctx
@ -165,7 +158,24 @@ func InitSimple(ctx context.Context) error {
defaultCommandExecutionTimeout = time.Duration(setting.Git.Timeout.Default) * time.Second
}
return SetExecutablePath(setting.Git.Path)
if err := SetExecutablePath(setting.Git.Path); err != nil {
return err
}
var err error
defaultFeatures, err = loadGitVersionFeatures()
if err != nil {
return err
}
if err = ensureGitVersion(); err != nil {
return err
}
// when git works with gnupg (commit signing), there should be a stable home for gnupg commands
if _, ok := os.LookupEnv("GNUPGHOME"); !ok {
_ = os.Setenv("GNUPGHOME", filepath.Join(HomeDir(), ".gnupg"))
}
return nil
}
// InitFull initializes git module with version check and change global variables, sync gitconfig.
@ -175,30 +185,18 @@ func InitFull(ctx context.Context) (err error) {
return err
}
// when git works with gnupg (commit signing), there should be a stable home for gnupg commands
if _, ok := os.LookupEnv("GNUPGHOME"); !ok {
_ = os.Setenv("GNUPGHOME", filepath.Join(HomeDir(), ".gnupg"))
}
// Since git wire protocol has been released from git v2.18
if setting.Git.EnableAutoGitWireProtocol && CheckGitVersionAtLeast("2.18") == nil {
if setting.Git.EnableAutoGitWireProtocol && DefaultFeatures().CheckVersionAtLeast("2.18") {
globalCommandArgs = append(globalCommandArgs, "-c", "protocol.version=2")
}
// Explicitly disable credential helper, otherwise Git credentials might leak
if CheckGitVersionAtLeast("2.9") == nil {
if DefaultFeatures().CheckVersionAtLeast("2.9") {
globalCommandArgs = append(globalCommandArgs, "-c", "credential.helper=")
}
DefaultFeatures.SupportProcReceive = CheckGitVersionAtLeast("2.29") == nil
DefaultFeatures.SupportHashSha256 = CheckGitVersionAtLeast("2.42") == nil && !isGogit
if DefaultFeatures.SupportHashSha256 {
SupportedObjectFormats = append(SupportedObjectFormats, Sha256ObjectFormat)
} else {
log.Warn("sha256 hash support is disabled - requires Git >= 2.42. Gogit is currently unsupported")
}
if setting.LFS.StartServer {
if CheckGitVersionAtLeast("2.1.2") != nil {
if !DefaultFeatures().CheckVersionAtLeast("2.1.2") {
return errors.New("LFS server support requires Git >= 2.1.2")
}
globalCommandArgs = append(globalCommandArgs, "-c", "filter.lfs.required=", "-c", "filter.lfs.smudge=", "-c", "filter.lfs.clean=")
@ -238,13 +236,13 @@ func syncGitConfig() (err error) {
return err
}
if CheckGitVersionAtLeast("2.10") == nil {
if DefaultFeatures().CheckVersionAtLeast("2.10") {
if err := configSet("receive.advertisePushOptions", "true"); err != nil {
return err
}
}
if CheckGitVersionAtLeast("2.18") == nil {
if DefaultFeatures().CheckVersionAtLeast("2.18") {
if err := configSet("core.commitGraph", "true"); err != nil {
return err
}
@ -256,7 +254,7 @@ func syncGitConfig() (err error) {
}
}
if DefaultFeatures.SupportProcReceive {
if DefaultFeatures().SupportProcReceive {
// set support for AGit flow
if err := configAddNonExist("receive.procReceiveRefs", "refs/for"); err != nil {
return err
@ -294,7 +292,7 @@ func syncGitConfig() (err error) {
}
// By default partial clones are disabled, enable them from git v2.22
if !setting.Git.DisablePartialClone && CheckGitVersionAtLeast("2.22") == nil {
if !setting.Git.DisablePartialClone && DefaultFeatures().CheckVersionAtLeast("2.22") {
if err = configSet("uploadpack.allowfilter", "true"); err != nil {
return err
}
@ -309,21 +307,6 @@ func syncGitConfig() (err error) {
return err
}
// CheckGitVersionAtLeast check git version is at least the constraint version
func CheckGitVersionAtLeast(atLeast string) error {
if DefaultFeatures.GitVersion == nil {
panic("git module is not initialized") // it shouldn't happen
}
atLeastVersion, err := version.NewVersion(atLeast)
if err != nil {
return err
}
if DefaultFeatures.GitVersion.Compare(atLeastVersion) < 0 {
return fmt.Errorf("installed git binary version %s is not at least %s", DefaultFeatures.GitVersion.Original(), atLeast)
}
return nil
}
func checkGitVersionCompatibility(gitVer *version.Version) error {
badVersions := []struct {
Version *version.Version

View File

@ -29,6 +29,7 @@ type GrepOptions struct {
ContextLineNumber int
IsFuzzy bool
MaxLineLength int // the maximum length of a line to parse, exceeding chars will be truncated
PathspecList []string
}
func GrepSearch(ctx context.Context, repo *Repository, search string, opts GrepOptions) ([]*GrepResult, error) {
@ -62,6 +63,7 @@ func GrepSearch(ctx context.Context, repo *Repository, search string, opts GrepO
cmd.AddOptionValues("-e", strings.TrimLeft(search, "-"))
}
cmd.AddDynamicArguments(util.IfZero(opts.RefName, "HEAD"))
cmd.AddDashesAndList(opts.PathspecList...)
opts.MaxResultLimit = util.IfZero(opts.MaxResultLimit, 50)
stderr := bytes.Buffer{}
err = cmd.Run(&RunOpts{

View File

@ -31,6 +31,26 @@ func TestGrepSearch(t *testing.T) {
},
}, res)
res, err = GrepSearch(context.Background(), repo, "void", GrepOptions{PathspecList: []string{":(glob)java-hello/*"}})
assert.NoError(t, err)
assert.Equal(t, []*GrepResult{
{
Filename: "java-hello/main.java",
LineNumbers: []int{3},
LineCodes: []string{" public static void main(String[] args)"},
},
}, res)
res, err = GrepSearch(context.Background(), repo, "void", GrepOptions{PathspecList: []string{":(glob,exclude)java-hello/*"}})
assert.NoError(t, err)
assert.Equal(t, []*GrepResult{
{
Filename: "main.vendor.java",
LineNumbers: []int{3},
LineCodes: []string{" public static void main(String[] args)"},
},
}, res)
res, err = GrepSearch(context.Background(), repo, "void", GrepOptions{MaxResultLimit: 1})
assert.NoError(t, err)
assert.Equal(t, []*GrepResult{

View File

@ -33,7 +33,6 @@ type ObjectFormat interface {
ComputeHash(t ObjectType, content []byte) ObjectID
}
/* SHA1 Type */
type Sha1ObjectFormatImpl struct{}
var (
@ -70,14 +69,10 @@ func (h Sha1ObjectFormatImpl) ComputeHash(t ObjectType, content []byte) ObjectID
_, _ = hasher.Write([]byte(" "))
_, _ = hasher.Write([]byte(strconv.FormatInt(int64(len(content)), 10)))
_, _ = hasher.Write([]byte{0})
// HashSum generates a SHA1 for the provided hash
var sha1 Sha1Hash
copy(sha1[:], hasher.Sum(nil))
return &sha1
_, _ = hasher.Write(content)
return h.MustID(hasher.Sum(nil))
}
/* SHA256 Type */
type Sha256ObjectFormatImpl struct{}
var (
@ -116,11 +111,8 @@ func (h Sha256ObjectFormatImpl) ComputeHash(t ObjectType, content []byte) Object
_, _ = hasher.Write([]byte(" "))
_, _ = hasher.Write([]byte(strconv.FormatInt(int64(len(content)), 10)))
_, _ = hasher.Write([]byte{0})
// HashSum generates a SHA256 for the provided hash
var sha256 Sha1Hash
copy(sha256[:], hasher.Sum(nil))
return &sha256
_, _ = hasher.Write(content)
return h.MustID(hasher.Sum(nil))
}
var (
@ -128,12 +120,8 @@ var (
Sha256ObjectFormat ObjectFormat = Sha256ObjectFormatImpl{}
)
var SupportedObjectFormats = []ObjectFormat{
Sha1ObjectFormat,
}
func ObjectFormatFromName(name string) ObjectFormat {
for _, objectFormat := range SupportedObjectFormats {
for _, objectFormat := range DefaultFeatures().SupportedObjectFormats {
if name == objectFormat.Name() {
return objectFormat
}

View File

@ -16,7 +16,6 @@ type ObjectID interface {
Type() ObjectFormat
}
/* SHA1 */
type Sha1Hash [20]byte
func (h *Sha1Hash) String() string {
@ -40,7 +39,6 @@ func MustIDFromString(hexHash string) ObjectID {
return id
}
/* SHA256 */
type Sha256Hash [32]byte
func (h *Sha256Hash) String() string {
@ -54,10 +52,9 @@ func (h *Sha256Hash) IsZero() bool {
func (h *Sha256Hash) RawValue() []byte { return h[:] }
func (*Sha256Hash) Type() ObjectFormat { return Sha256ObjectFormat }
/* utility */
func NewIDFromString(hexHash string) (ObjectID, error) {
var theObjectFormat ObjectFormat
for _, objectFormat := range SupportedObjectFormats {
for _, objectFormat := range DefaultFeatures().SupportedObjectFormats {
if len(hexHash) == objectFormat.FullLength() {
theObjectFormat = objectFormat
break

View File

@ -18,4 +18,8 @@ func TestIsValidSHAPattern(t *testing.T) {
assert.False(t, h.IsValid("abc"))
assert.False(t, h.IsValid("123g"))
assert.False(t, h.IsValid("some random text"))
assert.Equal(t, "e69de29bb2d1d6434b8b29ae775ad8c2e48c5391", ComputeBlobHash(Sha1ObjectFormat, nil).String())
assert.Equal(t, "2e65efe2a145dda7ee51d1741299f848e5bf752e", ComputeBlobHash(Sha1ObjectFormat, []byte("a")).String())
assert.Equal(t, "473a0f4c3be8a93681a267e3b1e9a7dcda1185436fe141f7749120a303721813", ComputeBlobHash(Sha256ObjectFormat, nil).String())
assert.Equal(t, "eb337bcee2061c5313c9a1392116b6c76039e9e30d71467ae359b36277e17dc7", ComputeBlobHash(Sha256ObjectFormat, []byte("a")).String())
}

View File

@ -18,7 +18,7 @@ import (
)
// ParseTreeEntries parses the output of a `git ls-tree -l` command.
func ParseTreeEntries(h ObjectFormat, data []byte) ([]*TreeEntry, error) {
func ParseTreeEntries(data []byte) ([]*TreeEntry, error) {
return parseTreeEntries(data, nil)
}

View File

@ -67,7 +67,7 @@ func TestParseTreeEntries(t *testing.T) {
}
for _, testCase := range testCases {
entries, err := ParseTreeEntries(Sha1ObjectFormat, []byte(testCase.Input))
entries, err := ParseTreeEntries([]byte(testCase.Input))
assert.NoError(t, err)
if len(entries) > 1 {
fmt.Println(testCase.Expected[0].ID)

View File

@ -17,13 +17,13 @@ import (
)
// ParseTreeEntries parses the output of a `git ls-tree -l` command.
func ParseTreeEntries(objectFormat ObjectFormat, data []byte) ([]*TreeEntry, error) {
return parseTreeEntries(objectFormat, data, nil)
func ParseTreeEntries(data []byte) ([]*TreeEntry, error) {
return parseTreeEntries(data, nil)
}
var sepSpace = []byte{' '}
func parseTreeEntries(objectFormat ObjectFormat, data []byte, ptree *Tree) ([]*TreeEntry, error) {
func parseTreeEntries(data []byte, ptree *Tree) ([]*TreeEntry, error) {
var err error
entries := make([]*TreeEntry, 0, bytes.Count(data, []byte{'\n'})+1)
for pos := 0; pos < len(data); {

View File

@ -12,8 +12,6 @@ import (
)
func TestParseTreeEntriesLong(t *testing.T) {
objectFormat := Sha1ObjectFormat
testCases := []struct {
Input string
Expected []*TreeEntry
@ -56,7 +54,7 @@ func TestParseTreeEntriesLong(t *testing.T) {
},
}
for _, testCase := range testCases {
entries, err := ParseTreeEntries(objectFormat, []byte(testCase.Input))
entries, err := ParseTreeEntries([]byte(testCase.Input))
assert.NoError(t, err)
assert.Len(t, entries, len(testCase.Expected))
for i, entry := range entries {
@ -66,8 +64,6 @@ func TestParseTreeEntriesLong(t *testing.T) {
}
func TestParseTreeEntriesShort(t *testing.T) {
objectFormat := Sha1ObjectFormat
testCases := []struct {
Input string
Expected []*TreeEntry
@ -91,7 +87,7 @@ func TestParseTreeEntriesShort(t *testing.T) {
},
}
for _, testCase := range testCases {
entries, err := ParseTreeEntries(objectFormat, []byte(testCase.Input))
entries, err := ParseTreeEntries([]byte(testCase.Input))
assert.NoError(t, err)
assert.Len(t, entries, len(testCase.Expected))
for i, entry := range entries {
@ -102,7 +98,7 @@ func TestParseTreeEntriesShort(t *testing.T) {
func TestParseTreeEntriesInvalid(t *testing.T) {
// there was a panic: "runtime error: slice bounds out of range" when the input was invalid: #20315
entries, err := ParseTreeEntries(Sha1ObjectFormat, []byte("100644 blob ea0d83c9081af9500ac9f804101b3fd0a5c293af"))
entries, err := ParseTreeEntries([]byte("100644 blob ea0d83c9081af9500ac9f804101b3fd0a5c293af"))
assert.Error(t, err)
assert.Len(t, entries, 0)
}

View File

@ -0,0 +1,32 @@
// Copyright 2024 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package pipeline
import (
"fmt"
"time"
"code.gitea.io/gitea/modules/git"
)
// LFSResult represents commits found using a provided pointer file hash
type LFSResult struct {
Name string
SHA string
Summary string
When time.Time
ParentHashes []git.ObjectID
BranchName string
FullCommitName string
}
type lfsResultSlice []*LFSResult
func (a lfsResultSlice) Len() int { return len(a) }
func (a lfsResultSlice) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
func (a lfsResultSlice) Less(i, j int) bool { return a[j].When.After(a[i].When) }
func lfsError(msg string, err error) error {
return fmt.Errorf("LFS error occurred, %s: err: %w", msg, err)
}

View File

@ -7,12 +7,10 @@ package pipeline
import (
"bufio"
"fmt"
"io"
"sort"
"strings"
"sync"
"time"
"code.gitea.io/gitea/modules/git"
@ -21,23 +19,6 @@ import (
"github.com/go-git/go-git/v5/plumbing/object"
)
// LFSResult represents commits found using a provided pointer file hash
type LFSResult struct {
Name string
SHA string
Summary string
When time.Time
ParentHashes []git.ObjectID
BranchName string
FullCommitName string
}
type lfsResultSlice []*LFSResult
func (a lfsResultSlice) Len() int { return len(a) }
func (a lfsResultSlice) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
func (a lfsResultSlice) Less(i, j int) bool { return a[j].When.After(a[i].When) }
// FindLFSFile finds commits that contain a provided pointer file hash
func FindLFSFile(repo *git.Repository, objectID git.ObjectID) ([]*LFSResult, error) {
resultsMap := map[string]*LFSResult{}
@ -51,7 +32,7 @@ func FindLFSFile(repo *git.Repository, objectID git.ObjectID) ([]*LFSResult, err
All: true,
})
if err != nil {
return nil, fmt.Errorf("Failed to get GoGit CommitsIter. Error: %w", err)
return nil, lfsError("failed to get GoGit CommitsIter", err)
}
err = commitsIter.ForEach(func(gitCommit *object.Commit) error {
@ -85,7 +66,7 @@ func FindLFSFile(repo *git.Repository, objectID git.ObjectID) ([]*LFSResult, err
return nil
})
if err != nil && err != io.EOF {
return nil, fmt.Errorf("Failure in CommitIter.ForEach: %w", err)
return nil, lfsError("failure in CommitIter.ForEach", err)
}
for _, result := range resultsMap {
@ -156,7 +137,7 @@ func FindLFSFile(repo *git.Repository, objectID git.ObjectID) ([]*LFSResult, err
select {
case err, has := <-errChan:
if has {
return nil, fmt.Errorf("Unable to obtain name for LFS files. Error: %w", err)
return nil, lfsError("unable to obtain name for LFS files", err)
}
default:
}

View File

@ -8,33 +8,14 @@ package pipeline
import (
"bufio"
"bytes"
"fmt"
"io"
"sort"
"strings"
"sync"
"time"
"code.gitea.io/gitea/modules/git"
)
// LFSResult represents commits found using a provided pointer file hash
type LFSResult struct {
Name string
SHA string
Summary string
When time.Time
ParentIDs []git.ObjectID
BranchName string
FullCommitName string
}
type lfsResultSlice []*LFSResult
func (a lfsResultSlice) Len() int { return len(a) }
func (a lfsResultSlice) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
func (a lfsResultSlice) Less(i, j int) bool { return a[j].When.After(a[i].When) }
// FindLFSFile finds commits that contain a provided pointer file hash
func FindLFSFile(repo *git.Repository, objectID git.ObjectID) ([]*LFSResult, error) {
resultsMap := map[string]*LFSResult{}
@ -137,11 +118,11 @@ func FindLFSFile(repo *git.Repository, objectID git.ObjectID) ([]*LFSResult, err
n += int64(count)
if bytes.Equal(binObjectID, objectID.RawValue()) {
result := LFSResult{
Name: curPath + string(fname),
SHA: curCommit.ID.String(),
Summary: strings.Split(strings.TrimSpace(curCommit.CommitMessage), "\n")[0],
When: curCommit.Author.When,
ParentIDs: curCommit.Parents,
Name: curPath + string(fname),
SHA: curCommit.ID.String(),
Summary: strings.Split(strings.TrimSpace(curCommit.CommitMessage), "\n")[0],
When: curCommit.Author.When,
ParentHashes: curCommit.Parents,
}
resultsMap[curCommit.ID.String()+":"+curPath+string(fname)] = &result
} else if string(mode) == git.EntryModeTree.String() {
@ -183,7 +164,7 @@ func FindLFSFile(repo *git.Repository, objectID git.ObjectID) ([]*LFSResult, err
for _, result := range resultsMap {
hasParent := false
for _, parentID := range result.ParentIDs {
for _, parentID := range result.ParentHashes {
if _, hasParent = resultsMap[parentID.String()+":"+result.Name]; hasParent {
break
}
@ -232,7 +213,6 @@ func FindLFSFile(repo *git.Repository, objectID git.ObjectID) ([]*LFSResult, err
errChan <- err
break
}
}
}()
@ -241,7 +221,7 @@ func FindLFSFile(repo *git.Repository, objectID git.ObjectID) ([]*LFSResult, err
select {
case err, has := <-errChan:
if has {
return nil, fmt.Errorf("Unable to obtain name for LFS files. Error: %w", err)
return nil, lfsError("unable to obtain name for LFS files", err)
}
default:
}

View File

@ -184,7 +184,7 @@ func (ref RefName) RefGroup() string {
}
// RefType returns the simple ref type of the reference, e.g. branch, tag
// It's differrent from RefGroup, which is using the name of the directory under .git/refs
// It's different from RefGroup, which is using the name of the directory under .git/refs
// Here we using branch but not heads, using tag but not tags
func (ref RefName) RefType() string {
var refType string

View File

@ -12,7 +12,7 @@ import (
// GetRemoteAddress returns remote url of git repository in the repoPath with special remote name
func GetRemoteAddress(ctx context.Context, repoPath, remoteName string) (string, error) {
var cmd *Command
if CheckGitVersionAtLeast("2.7") == nil {
if DefaultFeatures().CheckVersionAtLeast("2.7") {
cmd = NewCommand(ctx, "remote", "get-url").AddDynamicArguments(remoteName)
} else {
cmd = NewCommand(ctx, "config", "--get").AddDynamicArguments("remote." + remoteName + ".url")

View File

@ -7,7 +7,6 @@ package git
import (
"bytes"
"context"
"errors"
"fmt"
"io"
"net/url"
@ -63,32 +62,6 @@ func IsRepoURLAccessible(ctx context.Context, url string) bool {
return err == nil
}
// GetObjectFormatOfRepo returns the hash type of repository at a given path
func GetObjectFormatOfRepo(ctx context.Context, repoPath string) (ObjectFormat, error) {
var stdout, stderr strings.Builder
err := NewCommand(ctx, "hash-object", "--stdin").Run(&RunOpts{
Dir: repoPath,
Stdout: &stdout,
Stderr: &stderr,
Stdin: &strings.Reader{},
})
if err != nil {
return nil, err
}
if stderr.Len() > 0 {
return nil, errors.New(stderr.String())
}
h, err := NewIDFromString(strings.TrimRight(stdout.String(), "\n"))
if err != nil {
return nil, err
}
return h.Type(), nil
}
// InitRepository initializes a new Git repository.
func InitRepository(ctx context.Context, repoPath string, bare bool, objectFormatName string) error {
err := os.MkdirAll(repoPath, os.ModePerm)
@ -101,7 +74,7 @@ func InitRepository(ctx context.Context, repoPath string, bare bool, objectForma
if !IsValidObjectFormat(objectFormatName) {
return fmt.Errorf("invalid object format: %s", objectFormatName)
}
if DefaultFeatures.SupportHashSha256 {
if DefaultFeatures().SupportHashSha256 {
cmd.AddOptionValues("--object-format", objectFormatName)
}

View File

@ -1,6 +0,0 @@
// Copyright 2021 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package git
var isGogit bool

View File

@ -22,9 +22,7 @@ import (
"github.com/go-git/go-git/v5/storage/filesystem"
)
func init() {
isGogit = true
}
const isGogit = true
// Repository represents a Git repository.
type Repository struct {

View File

@ -15,9 +15,7 @@ import (
"code.gitea.io/gitea/modules/util"
)
func init() {
isGogit = false
}
const isGogit = false
// Repository represents a Git repository.
type Repository struct {

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