5578 Commits

Author SHA1 Message Date
wxiaoguang
772f365254 refactor: use RunWithStderr for git commands (#40295)
If the stderr output is not handled, then it needs to use RunWithStderr
to make sure the git error message is included in the returned error.
Otherwise, when the git command fails, the error log won't show useful
information.

Ref:

* #39795 : no useful information in log messages
*
https://github.com/go-gitea/gitea/pull/40160#pullrequestreview-5752720866
2026-11-09 17:59:52 +00:00
bircni
e0b2f3425e fix(actions): run pull_request workflows on the merge commit (#40076)
`pull_request` workflow runs checked out the PR head, so a PR could pass
CI and still break the base branch once merged.

Gitea now maintains `refs/pull/<index>/merge`, a test merge of the head
into the base branch, for open pull requests. It is updated on creation
and mergeability checks and removed on close or merge.

- `pull_request` runs read their workflows from the test merge and
expose it as `github.ref`, `github.sha` and
`github.event.pull_request.merge_commit_sha`. Commit statuses, the API's
`head_sha`, `workflow_run` payloads and `paths` filters stay on the
head.
- Runs fall back to the head when the merge conflicts, the pull request
is closed or git is older than 2.40.
- Hidden refs keep each run's test merge (`refs/gitea/run/<id>`) and
merged commits (`refs/gitea/pull/<index>/merged`) from `git gc`, for
reruns and after the base branch is deleted or force-pushed.

Fixes: https://github.com/go-gitea/gitea/issues/27039
Fixes: https://github.com/go-gitea/gitea/issues/13134
Fixes: https://github.com/go-gitea/gitea/issues/30972
Docs: https://gitea.com/gitea/docs/pulls/617

---------

Co-authored-by: silverwind <me@silverwind.io>
2026-11-09 12:42:40 +00:00
Shudhanshu Singh
7b1cde99d0 perf(charset): skip plain ASCII text when escaping control characters (#39937)
Every line of file, blame, diff and code preview views goes through
`EscapeControlHTML`, which streamed it through a 32 KiB read buffer and
copied every tag and text part. Views render the `EscapeStatus` before
the content, so every caller holds the complete HTML and streaming can't
help. It is now escaped in one pass over the string and returned
unchanged when nothing needs escaping.

- Skip text of printable ASCII, tabs and newlines, such lines return
immediately
- Render markup and wiki pages into a buffer instead of a pipe and
goroutine, and remove `EscapeControlReader`
- Analyze long text parts in windows overlapping by the detection
context, which bounds memory without changing results
- Escape invalid bytes before a tag, they were moved into the tag part
unescaped and could hide a `<math>` tag

| | before | after |
|---|---|---|
| ASCII line | 5.1 µs, 59 allocs | 0.08 µs, 1 alloc |
| line with one `é` | 3.9 µs, 30 allocs | 0.29 µs, 3 allocs |
| 150 KB document | 2.5 ms, 5.6 MB | 0.27 ms, 0.6 KB |

---------

Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
Co-authored-by: silverwind <me@silverwind.io>
2026-11-09 03:42:30 +00:00
Lunny Xiao
1554b6c939 feat!: remove repository adopt feature (#40181)
Remove the "adopt unadopted repositories" feature. Adopting assumes a
fixed repository storage path on disk, which makes the storage path hard
to change. It is mostly used once for migrations, and the [Gitea
importer](https://gitea.com/gitea/importer) covers that after the
repositories are moved out of the repository root. The docs are updated
in https://gitea.com/gitea/docs/pulls/639.

- Remove the admin and user adopt pages, the `/admin/unadopted` API
endpoints and the adopt notifier hook
- Remove the `ALLOW_ADOPTION_OF_UNADOPTED_REPOSITORIES` and
`ALLOW_DELETION_OF_UNADOPTED_REPOSITORIES` settings
- The user "Repositories" settings page only lists the user's
repositories
- Repository files without a database record must now be removed from
disk by the administrator

Assisted-by: Codet:claude

---------

Co-authored-by: silverwind <me@silverwind.io>
2026-11-08 18:38:23 +00:00
wxiaoguang
3699309edd feat: support jpeg-xl (jxl) (#40283)
Major browsers (Chrome/Firefox/Safari) all support it now,
https://developer.chrome.com/blog/jpeg-xl-in-chrome

* Fix #16629
2026-11-08 15:24:46 +00:00
silverwind
cd92c6a008 fix: paste copied code as text, not as a markdown table (#40053)
Copying lines from a diff, file view, blame, code search or code preview
and pasting them into a comment on Gitea or GitHub produced a markdown
table with escaped pipes and stripped indentation. Both use
`@github/paste-markdown`, which converts copied HTML tables unless they
carry `data-paste-markdown-skip`, as GitHub's own code tables do.
Gitea's code tables now set it too.

The test is a bit more complicated because of a upstream bug which
causes `paste-markdown` to insert pasted content twice, once
https://github.com/github/paste-markdown/pull/128 is merged and
released, the negative assertion could be removed.

---------

Signed-off-by: silverwind <me@silverwind.io>
2026-11-08 09:01:50 +00:00
silverwind
51879941dc enhance: improve commit and compare link rendering (#40154)
Commit, compare and SHA links render the SHA in code with the rest of
the URL after it, and links to other repositories get an `owner/repo@`
prefix like references do.

- Abbreviated SHAs, branch compares and `<url>` autolinks now render as
commit links
- Pull request commit URLs no longer break into an issue reference plus
stray text
- Only routes that take a SHA are shortened, so file and API URLs stay
plain

Replaces https://github.com/go-gitea/gitea/pull/36725

<img width="620" alt="Commit links before and after"
src="https://github.com/user-attachments/assets/5919c8a0-94e3-4148-ad11-6944bf790572"
/>
2026-11-07 22:43:07 +00:00
William Desportes
87a703819b fix(queue): bump levelqueue to v0.5.0 and remove workarounds (#40219)
levelqueue v0.5.1 fixes this upstream
(https://gitea.com/lunny/levelqueue/pulls/8), so this now only bumps the
dependency.

A push wrote "high" before the payload, so an interrupted push left an
id counted with no key. `LPop` then returned `ErrNotFound` without
advancing "low" and the wrapper retried forever: nothing popped, no
worker started, later items unreachable. All were only fixable by
clearing the queue, losing the backlog:
- https://github.com/go-gitea/gitea/issues/32006 — mail, 0 workers
- https://github.com/go-gitea/gitea/issues/28919 — mirror, "already in
queue"
- https://github.com/go-gitea/gitea/issues/33862 — archives hanging
- https://github.com/go-gitea/gitea/issues/33882 — self-healing request

v0.5.1 writes counter and payload in one batch, moves the counters past
missing keys, and repairs leftover unique-queue set entries, so affected
instances recover on their next pop.

No test: the behaviour lives in the dependency, which covers it in its
own `recover_test.go`.

---------

Signed-off-by: wxiaoguang <wxiaoguang@gmail.com>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
2026-11-07 22:26:53 +00:00
Lazizbek Ergashev
884884308d fix(pull): don't add a timeline entry for pending API reviews (#40260)
Pending reviews created through the API went through `SubmitReview`,
which added a timeline entry and sent notifications before the review
was submitted, so submitting it later showed the review twice.

- Pending reviews skip the timeline entry and notifications until
submitted, like on GitHub
- `CreatePullReview` rejects comments without a `path` or a positive
line with 422, like GitHub
- Already duplicated reviews stay as they are

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

Assisted-by: Claude Code:claude-opus-5-5

---------

Co-authored-by: silverwind <me@silverwind.io>
2026-11-07 14:19:50 +00:00
Mitrahsoft
3aca9c8fb7 enhance(actions): create commit status for workflow_dispatch runs (#39961)
Runs triggered by `workflow_dispatch` never created a commit status, so
the commit showed no sign that a workflow ran on it.

- Post the status on the run's commit, e.g. `ci / e2e
(workflow_dispatch)`. `schedule` runs stay unchanged.
- These statuses don't count for pull requests. They don't show in a
PR's checks and can't satisfy or fail its required checks, even through
broad globs like `ci / e2e*`.

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

---------

Co-authored-by: silverwind <me@silverwind.io>
2026-11-07 12:55:19 +00:00
wxiaoguang
a165fdb63c refactor: lazy init global regexp variables (#40269)
Gitea binary is an all-in-one program.

It doesn't make sense to compile dozens or even hundreds of regexps for
git hook sub commands.
2026-11-07 11:56:56 +00:00
silverwind
baccc2d7cd fix: truncate strings on character boundaries (#40267)
Byte slicing like `t.Description[:255]` can split a multi-byte character
and store invalid UTF-8. Team descriptions were also cut to 255 bytes
although their `MaxSize(255)` validation allows 255 characters.

Team descriptions now truncate by runes. Signup user agents, Actions log
lines and access log request IDs use `util.TruncateStringBytes`, which
now returns short strings untouched.

---------

Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2026-11-07 11:15:28 +00:00
Michael Lopez
5d9bfa1e14 feat(packages): add private Terraform module registry (#38040)
Adds a Terraform module registry package type implementing the [module
registry
protocol](https://developer.hashicorp.com/terraform/internals/module-registry-protocol),
so `terraform init` and Terragrunt `tfr://` can resolve modules from
Gitea:

```hcl
module "vpc" {
  source  = "gitea.example.com/owner/vpc/aws"
  version = "~> 1.0"
}
```

- Modules are uploaded with `PUT
/api/packages/-/terraform/modules/{owner}/{name}/{provider}/{version}`
as a `.tar.gz` with the module at its root, stored verbatim and
immutable.
- `X-Terraform-Get` is a short-lived signed URL because Terraform sends
no credentials when downloading the archive.
- The package page shows install snippets, README, the root module's
inputs, outputs and providers, and `modules/*` submodules.
- Metadata is read by a small in-tree HCL scanner instead of
`hashicorp/hcl/v2`, which would add 5 modules and ~1.4 MB to the binary.

Docs: https://gitea.com/gitea/docs/pulls/433

---------

Signed-off-by: Michael Lopez <mickael.lopez@gmail.com>
Co-authored-by: TheFox0x7 <thefox0x7@gmail.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: silverwind <me@silverwind.io>
2026-11-07 10:45:05 +00:00
Wei-Lun Li
7efb5c055f fix(markup): recognize issue references next to CJK punctuation (#40097)
Issue references next to non-ASCII characters, common in Chinese and
Japanese text, are ignored: `修复#1`, `(#2)` or `Closes #3,` create no
link or cross reference.

Like on GitHub, any non-ASCII character may now precede `#123`, `!123`
or `owner/repo#123`, and anything but a word character may follow it.
Dead trailing-space handling in the reference and mention search is
removed.

I used Claude Code to write this change.

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: silverwind <me@silverwind.io>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2026-11-07 10:14:47 +00:00
Mitrahsoft
b6c291f87a fix(api): honor branch protection force push and allowlist options on create and edit (#39990)
The branch protection API handled push and force push options
inconsistently. Create dropped force push unless push was enabled, and
edit ignored allowlist fields unless their parent was set to true in the
same request.

- Create treats force push independently of push, like edit and the web
UI. Enforcement is unchanged.
- Edit applies `enable_push_whitelist`, `enable_force_push_allowlist`
and both deploy key flags against the rule's resulting state, like the
deletion fields. `{"enable_push_whitelist": false}` now disables the
whitelist instead of being ignored.
- Documents that `enable_force_push_allowlist` requires
`enable_force_push` on create.

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

---------

Co-authored-by: silverwind <me@silverwind.io>
2026-11-07 09:34:21 +00:00
Alan Hsu
df4544a58b fix(web): handle TypeCastError when building form validation messages (#40212)
Fixes https://github.com/go-gitea/gitea/issues/40210

---------

Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2026-11-06 23:27:06 +00:00
silverwind
ede9ec3e10 fix: stop discarding file close and test setup errors (#39987)
- Fix
https://github.com/go-gitea/gitea/security/quality/rules/go%2Funhandled-writable-file-close,
ignored close errors hide failed flushes, which could lose rotated logs
and truncate authorized_keys
- Fix `TestProjects` fixture reset, from
https://github.com/go-gitea/gitea/security/quality/ai-findings,
`TruncateBeans` rejected the table names and the ignored error let the
test run against fixture data
2026-11-06 20:45:17 +00:00
silverwind
7e18e81c7d refactor: remove duplicated and dead Go code (#40244)
Pure refactors with no behavior change, mostly reusing existing helpers
and dropping duplicated or dead code. Net −222 lines.

- Reuse existing helpers instead of inlined copies: `getIssueIndex`,
`NewLabel`, `ToCommitUser`, `GetPackageFileDescriptors`,
`util.SplitTrimSpace`
- Merge copy-pasted blocks in review comment deletion, project deletion
and the pre/post-receive hook templates
- Drop dead code: an error `toStringKeys` never returned, impossible
`bytes.Buffer` write errors, redundant nil-map branches, a `base64`
wrapper
- Use stdlib where it fits: `strings.Cut`, `bytes.IndexAny`,
`cmp.Compare`, `min`/`max`, `slices.Concat`, map lookups instead of key
scans
2026-11-06 11:59:49 +00:00
Shivansh Garg
a5201dc427 feat(release): allow setting a release as the latest (#40214)
Gitea picks the latest release by commit date, while GitHub keeps an
explicit pointer, so repositories migrated from GitHub could show a
different latest release than their source. Fixes
https://github.com/go-gitea/gitea/issues/35273.

- Add a "Set as Latest Release" checkbox and GitHub's `make_latest` API
option. Without them, the newest stable release by commit date stays the
latest.
- Migrations from GitHub and Gitea carry over the source's latest
release.
- Migrated releases are dated by their commit like native ones, and
equally dated ones keep the source's order.

<img width="355" height="122" alt="Set as Latest Release checkbox"
src="https://github.com/user-attachments/assets/d35f5324-7ae0-4e9f-b73c-d3c90496fb00"
/>

---------

Co-authored-by: silverwind <me@silverwind.io>
2026-11-06 08:23:13 +00:00
silverwind
87ebf3b1ba feat(auth)!: remove support for obsolete OpenID 2.0 draft (#40231)
Remove OpenID 2.0 authentication. The spec is an obsolete draft, major
providers dropped it years ago, and the code keeps needing security
fixes like https://github.com/go-gitea/gitea/pull/39642. OpenID Connect
and OAuth2 are unaffected. Docs: https://gitea.com/gitea/docs/pulls/633.

- The `[openid]` settings, OpenID sign-in, sign-up and account
association are gone
- A migration drops the `user_open_id` table with all user OpenID URIs
- Accounts registered via OpenID have a random password and regain
access via password reset

Fixes: https://github.com/go-gitea/gitea/issues/1310
Fixes: https://github.com/go-gitea/gitea/issues/3521
2026-11-06 07:21:19 +00:00
wxiaoguang
fd98ab5472 enhance(codeowners): support section / glob / file view display / skip review request (#40243)
Document: https://gitea.com/gitea/docs/pulls/634 ([doc PR
preview](955ae7d75c/docs/usage/repository/code-owners.md))

1. If the pattern starts with `*` or contains `/*`, use our glob package
to parse it as glob to regexp
* Make it easier to use. Otherwise it's really ugly to keep writing a
lot of backslash escapes
2. Add GitLab-style "section" support
   * Fix #28926

```codeowners
[Section] @user
*.js
```

3. Add our annotation support, at the moment only need to support
review-request=true/false
    * Fix #40241

```codeowners
## review-request=false # this is global

*.js $user ## review-request=true # this is line-level

[Section] @user ## review-request=true # this is section-level
*.md
```

4. Add GitHub/GitLab-style "show codeowner when viewing a file"
    * Fix #28137
2026-11-06 07:19:51 +00:00
Andrew Barnes
4a9d49bb46 fix(dump): --file extension is ignored when --type is not set (#40235)
`gitea dump -f backup.tar.gz` without `--type` wrote a zip archive under
that name. Detecting the type from the file name was requested in
https://github.com/go-gitea/gitea/issues/24622 and intended in
https://github.com/go-gitea/gitea/pull/30240, but the check read the
still-empty result instead of `--file`, so every name fell back to zip.

A supported extension now selects the type, other names like `backup` or
`gitea.bak` still default to zip. An explicit `--type` still wins, and
its help text now mentions the detection.

AI disclosure: written with Claude Code (claude-opus-5-5).

---------

Signed-off-by: silverwind <me@silverwind.io>
Co-authored-by: silverwind <me@silverwind.io>
2026-11-05 18:30:31 +00:00
silverwind
b7c1fb2a39 enhance: enable DEFAULT_DELETE_BRANCH_AFTER_MERGE by default for new repos (#39975)
Switch the `DEFAULT_DELETE_BRANCH_AFTER_MERGE` default from
https://github.com/go-gitea/gitea/pull/36917 to `true`, saving users a
click on merge for the most common action that deletes the PR branch on
merge.

Docs: https://gitea.com/gitea/docs/pulls/608
2026-11-05 18:26:32 +00:00
rafał przypek
3b9b8a8976 fix(packages): return empty Chef dependencies instead of null (#40237)
Fixes #40230

Cookbooks without dependencies are served with `"dependencies": null`
from the universe and version metadata endpoints. This happens because
`omitempty` drops the empty map when the metadata is stored. Chef
clients iterate over this value and Policyfile resolution crashes.

Supermarket returns `{}` for these cookbooks, Gitea now does too. The
fix checks whether dependencies are `nil` while building response,
returns an empty map if true. This way cookbooks that are already stored
are covered without a re-upload.

Tested with the Chef integration test and `chef-cli install`.

Assisted by Claude Code (claude-opus-5-5).
2026-11-05 15:19:09 +00:00
silverwind
e87ac3a0f4 chore(deps): update go.yaml.in/yaml/v4 to v4.0.0 (#40222)
Update go-yaml from the rc.6 pseudo-version to the stable v4.0.0
release, and actionslib to v1.5.2, which does the same in
https://gitea.com/gitea/actionslib/pulls/32. The bump also brings in
actionslib v1.5.1.

v4 double-quotes the `on` key like yaml.v3 did, so one jobparser fixture
changes. Runner counterpart: https://gitea.com/gitea/runner/pulls/1381.

Fixes: https://github.com/go-gitea/gitea/issues/40145
2026-11-05 07:25:10 +00:00
Shivansh Garg
be297b7e05 fix(webhook): fire repository event on repository transfer (#40200)
Transferring a repository fired no `repository` webhook. It now sends a
`transferred` action shaped like GitHub's, with the previous owner in
`changes.owner.from.user` or `changes.owner.from.organization`. Like
GitHub, it goes to the new owner's webhooks, plus the repository's own
and system webhooks.

- Chat webhooks render "Repository transferred from <owner>".
- Actions workflows are unaffected, no trigger matches `repository`
events.

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

---------

Co-authored-by: silverwind <me@silverwind.io>
2026-11-04 17:25:51 +00:00
Myers Carpenter
58279e39fd fix(actions): match pull_request unlabeled on label removal (#40215)
Fixes https://github.com/go-gitea/gitea/issues/34317

Removing a label from a pull request still started workflows with
`types: [labeled]` and never matched `types: [unlabeled]`.
https://github.com/go-gitea/gitea/pull/34316 derived
`labeled`/`unlabeled` from the added and removed labels for issues only,
while pull requests kept mapping every `label_updated` to `labeled`.
Both events now share one conversion, so they cannot drift apart again.

Two other label changes also triggered the wrong workflows:

- Clearing all labels started no `unlabeled` workflow, because the
Actions notifier ignored it
- Replacing labels reported every old label as removed, so a replace
that kept a label also matched `unlabeled`

AI disclosure: written with Claude Code (claude-opus-5-5), session
https://claude.ai/code/session_01Kw9ySGNd4ynmyX9GcVdUfw

---------

Co-authored-by: silverwind <me@silverwind.io>
2026-11-04 17:24:33 +00:00
Nico Schlömer
ab295e62e4 fix(markup): make heading anchors match GitHub for whitespace and combining marks (#40195)
Heading anchors now keep the same characters as GitHub: letters, marks,
decimal and letter numbers, connector punctuation and alphabetic
symbols, with ASCII spaces turned into `-`. The rule follows
[github-slugger](https://github.com/Flet/github-slugger), whose fixtures
are generated from real GitHub renders.

- Other whitespace, including newlines in multi-line headings, is
dropped instead of becoming `-`, so `1<em space>ab` gets `#1ab`
- Combining marks are kept, so `हिन्दी` no longer becomes `हनद`
- Other numbers like `²` and `①` are dropped

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

This PR was written with Claude Code.

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: silverwind <me@silverwind.io>
2026-11-04 05:51:12 +00:00
wxiaoguang
d919301d36 refactor: remove UnmarshalHandleDoubleEncode patch and fix repo unit TODO (#39998)
Remove the `UnmarshalHandleDoubleEncode` runtime workaround for an old
xorm bug, and normalize legacy double-encoded JSON in `repo_unit.config`
and `login_source.cfg` with a migration instead.

- Config `FromDB` no longer fails on corrupted values. A broken auth
source is deactivated, so admins can still fix it in the admin panel
- Remove `ProjectsConfig.GetProjectsMode`, `FromDB` already defaults
`ProjectsMode`

Actually it doesn't need so many changes, just because AI thinks it
should handle "corrupted database value" for auth sources.

---------

Signed-off-by: wxiaoguang <wxiaoguang@gmail.com>
Co-authored-by: silverwind <me@silverwind.io>
2026-11-04 05:28:49 +00:00
Alan Hsu
666e6e2d17 fix(web): allow clearing the full name in profile settings (#40186)
Clearing "Full Name" in the profile settings shows success but keeps the
old value: since #31959 it is only updated when non-empty, because the
input is disabled (not submitted) when `change_full_name` is disabled.

Use `*string` for the field, so a missing field keeps the value and an
empty one clears it. With `change_full_name` disabled, any submitted
value (including empty) is now rejected. Not `optional.Option[string]`,
because `MaxSize` would count slice elements instead of characters.

Fixes #40185

---
AI disclosure: written with Claude Code (claude-opus-5-5) and tested
locally.

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
Co-authored-by: silverwind <me@silverwind.io>
2026-11-04 01:42:41 +00:00
Gaurav Dubey
f26a314636 fix(api): keep wiki page name when editing with an empty title (#40153)
Match `PATCH /repos/{owner}/{repo}/wiki/page/{pageName}` document "leave
empty to keep unchanged"

Fixes #39179

---------

Co-authored-by: silverwind <me@silverwind.io>
2026-11-03 16:20:39 +00:00
Jon Fuller
5c68ba3e0a fix(repo): avoid deadlock when updating language stats concurrently (#40167)
The `repo_stats_update` queue only deduplicates waiting items, so
several workers can index the same repository at once, then
`UpdateLanguageStats` can lead to transaction deadlock.

Use a global lock to avoid concurrent updates, and also helps
https://github.com/go-gitea/gitea/pull/39342 to avoid duplicate updates.

---------

Co-authored-by: silverwind <me@silverwind.io>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2026-11-03 16:18:27 +00:00
silverwind
5c723ee0fd refactor(markdown): remove goldmark-highlighting (#39751)
Render fenced code blocks with Gitea's own code block renderer instead
of `goldmark-highlighting`, using the managed lexer lookup from
`modules/highlight`. Indented and fenced blocks now share one rendering
path.

Rendered output is unchanged. The trailing newline is stripped on copy
in the frontend since https://github.com/go-gitea/gitea/pull/39755.

---------

Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2026-11-03 12:25:31 +00:00
bircni
d3021b69ee enhance: replace tea CLI with gt (#40036)
tea has been replaced by [gitea-cli](https://gitea.com/gitea/cli)
(`gt`), which reuses tea's OAuth2 client ID.

- The repository clone panel now offers `gt repo clone owner/repo` under
a "Gitea CLI" tab.
- The built-in OAuth2 application is renamed from `tea` to `gitea-cli`.
`tea` in `[oauth2] DEFAULT_APPLICATIONS` is still accepted as an alias,
so existing configs keep working.
- Instances that already registered the app keep its stored display name
"tea".
2026-11-01 12:47:10 +00:00
Norbert Szulc
da7b81d407 feat: add commitstatus access token scope (#40144)
Add `read:commitstatus` and `write:commitstatus` token scopes, so CI and
other integrations can report commit statuses without a token that
grants full repository access.

- The commit status endpoints (`/statuses/{sha}`,
`/commits/{ref}/status` and `/commits/{ref}/statuses`) accept the new
scopes, and the repository scopes keep working as they include them
- Creating a status still requires code write permission on the
repository, the scope only narrows what the token may do
- `public-only` tokens still cannot reach private repositories
- `PathGroup` middlewares now run only for a matched path, so unrelated
methods and paths that fall back to the group are not rejected by its
scope check

Fixes: https://github.com/go-gitea/gitea/issues/32625
Ref: https://github.com/go-gitea/gitea/pull/35383
Docs: https://gitea.com/gitea/docs/pulls/622
Signed-off-by: Norbert Szulc <norbert@not7cd.net>
Co-authored-by: Aiden Scandella <git@sca.ndella.com>
Co-authored-by: silverwind <me@silverwind.io>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2026-11-01 06:27:12 +00:00
Lunny Xiao
40507491f7 perf(pull): load the repository once for all commit statuses (#39930)
Pages showing commit statuses loaded the repository of every status
separately, so a PR with ~75 statuses ran ~75 identical repository
queries per merge box render (about 3.4s in a production trace).
`statusRepoCanReadActions` only loaded the repository inside the
permission cache loader, which never runs once `RepoAssignment` has
published the permission.

- `CommitStatus.loadRepository` resolves through the request context
cache
- `statusRepoCanReadActions` loads the repository before the permission
lookup
- `RepoAssignment` publishes its repository to the context cache next to
the permission
- `GetCommitActionsStatusMap` drops its own repository map

Queries per request with 50 statuses (45 Actions, 5 external) on the
head commit, SQLite:

| Page | Repository queries | Total queries |
|---|---|---|
| PR view | 61 → 11 | 157 → 107 |
| Commit | 6 → 5 | 24 → 23 |
| Branches | 6 → 5 | 33 → 32 |
| Commits | 6 → 5 | 23 → 22 |
| Repo home | 8 → 7 | 35 → 34 |
| `/pulls` | 15 → 15 | 37 → 37 |

---------

Co-authored-by: silverwind <me@silverwind.io>
2026-10-31 17:32:03 +01:00
Phoenix
9cd06bf57f fix(migrations): wait out GitHub rate limits and tolerate failed patch downloads (#40012)
Large GitHub migrations failed once the API budget ran out. A rejected
request never updated the downloader's rate state, so go-github refused
every retry locally.

- Record the rate limit from error responses too, so the next request
waits for the reset
- Retry repository-wide comment pages like the other downloader calls
- Stop `waitAndPickClient` spinning when the rate refresh fails
- Skip reaction requests when the reaction rollup reports none
- Log a failed patch download instead of failing the migration

---------

Co-authored-by: bircni <bircni@icloud.com>
Co-authored-by: silverwind <me@silverwind.io>
Co-authored-by: Giteabot <teabot@gitea.io>
2026-10-31 17:31:51 +01:00
silverwind
fc4d490b35 fix(ssh): let pushes finish when the client disconnects early (#40105)
With the built-in SSH server, closing the client connection cancelled
the `gitea serv` process tree. go-git based clients close it right after
the push report, so post-receive was killed and branches, pull requests,
webhooks and Actions were not updated.

The command now runs under the server's hammer context like with
OpenSSH, where it ends once its pipes close or at shutdown.
2026-10-31 15:24:13 +00:00
Lunny Xiao
bd5fbcfb29 feat(migrations): add repository migration from bitbucket.org (#38607)
Adds migration from bitbucket.org as the Cloud variant of the Bitbucket
entry, in the web UI and via `POST /repos/migrate` with
`service=bitbucket`. It migrates the repository and pull requests with
their comments and reviews. Bitbucket Cloud has no releases, and
Atlassian removed its issues and wikis on 2026-08-20
(https://community.atlassian.com/forums/Bitbucket-articles/Announcing-sunset-of-Bitbucket-Issues-and-Wikis/ba-p/3193882).

- Private repositories need an API or access token, which also raises
the rate limit.
- Rate-limited requests back off and retry, Bitbucket sends no
`Retry-After`.
- Tests replay recorded responses, set `BITBUCKET_READ_TOKEN` to
re-record.

Co-authored-by: silverwind <me@silverwind.io>
2026-10-31 14:51:43 +00:00
somaz
140fac63e2 fix(repo): honor ALLOW_FORK_INTO_SAME_OWNER for organizations (#40025)
With `[repository] ALLOW_FORK_INTO_SAME_OWNER = true` a user can fork
their own repository, but an organization still cannot fork a repository
it owns. The fork button check and the owner list on the fork page
compared the organization with the repository owner directly instead of
asking `CanUserForkBetweenOwners`, and the walk over parent repositories
dropped the owning organization whenever the setting was on.
Organizations now follow the setting the same way users already do, and
nothing changes when it is off.

Fixes https://github.com/go-gitea/gitea/issues/40021
Assisted-by: Claude Code:claude-opus-5-5
2026-10-30 17:28:47 +00:00
Lunny Xiao
b0b31bc593 feat(packages): expose package file properties in the package files API (#40066)
Package files carry type specific properties like `debian.distribution`,
`debian.component`, `rpm.group` or `alpine.branch` that decide where a
file lives in a registry, but the API never returned them. A client
listing `GET /packages/{owner}/{type}/{name}/{version}/files` could not
tell which distribution or component a file belongs to, or tell apart
same-named files in different ones. Tools copying packages between
instances, like https://gitea.com/gitea/importer, need them to re-upload
a file to the same place.

This adds a `properties` map to `PackageFile`, limited to the properties
that locate a file. Internal ones like the rpm, alpine, arch and conda
metadata or the Debian control file stay hidden, as they can be many MiB
per file.

Co-authored-by: silverwind <me@silverwind.io>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2026-10-29 18:10:36 +00:00
silverwind
eb9267365d enhance(markup): align markdown rendering details with GitHub (#39955)
Fixes markdown rendering details where Gitea deviated from GitHub
unintentionally, and adds a `/devtest/markdown` page to review markdown
rendering.

- Paragraphs get the intended 1.5 line height
- Blockquotes, alerts and definition lists no longer inherit browser
default margins
- Loose task lists keep their spacing, the checkbox renders inside the
paragraph like on GitHub
- Footnote references render as `[1]` so adjacent ones stay apart
without CSS
- Code in headings, headings in summaries, nested ordered lists, tables,
`<mark>`, alert icons and `<hr>` follow GitHub

Co-authored-by: bircni <bircni@icloud.com>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2026-10-29 11:18:04 +00:00
Danny Ward
1ebeade2c1 fix(indexer): search code as case-insensitive literal substrings (#40028)
Code search now matches case-insensitive literal substrings like GitHub,
in every script. Word tokenizers can't do this: the ES pattern dropped
every non-ASCII word, and the `standard` tokenizer keeps `console.log`
as one token.

- Elasticsearch indexes positional trigrams, plus 1-2 grams for short
terms
- Bleve indexes distinct 1-3 grams as a candidate filter and verifies
candidates against the content before paging, because phrase queries
over trigrams are quadratic in repeated grams
- Snippet offsets come from the original content, so `<em>` in sources
and width-changing lowercase no longer misplace them
- `search_mode=fuzzy` requests behave like Words, the UI never offered
fuzzy for code search
- The ES code indexer test now runs in CI, it was skipped before

There are no UI changes. Both code indexes rebuild after upgrade.

Fixes: https://github.com/go-gitea/gitea/issues/40027
Fixes: https://github.com/go-gitea/gitea/issues/16158
Fixes: https://github.com/go-gitea/gitea/issues/21359

---------

Co-authored-by: silverwind <me@silverwind.io>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2026-10-28 20:38:45 +08:00
bircni
178d33ed4d fix: add missing access checks and size limits (#39942)
Several handlers and parsers skipped checks that their siblings already
perform.

- Reject issue, comment, label, milestone and release mutations in
archived repositories via the API with one guard per route group,
matching the web UI
- Hide timeline references and dependencies pointing at issues the doer
cannot read, in the web UI and the API, including pull requests of the
same repository without pull request access
- Reject workflow runs with more than `MaxJobNumPerRun` jobs, including
inline reusable workflow jobs, and show rejected pushes as invalid
workflow runs
- Bound how much of a Helm chart archive is inflated while looking for
`Chart.yaml`

---------

Co-authored-by: silverwind <me@silverwind.io>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2026-10-27 21:40:42 +01:00
leo
9e27bce945 fix(markup): keep commit title emoji inside links (#39986)
Render emoji inside the default commit-title link so the whole title
remains clickable, including emoji-only titles. Explicit links and
mentions keep their own destinations.

Fixes https://github.com/go-gitea/gitea/issues/31873
2026-10-26 15:27:42 +00:00
Giteabot
f0bb283a17 chore(deps): update dependencies (#40020)
Co-authored-by: silverwind <me@silverwind.io>
2026-10-26 14:36:25 +00:00
silverwind
8321b09912 fix(git): default to the gc maintenance strategy (#40022)
Git 2.54 made "geometric" the default auto-maintenance strategy. Pushes
wait for its foreground reflog expiry
(https://github.com/go-gitea/gitea/issues/39693), and its detached
repacks race with filesystem operations, as in
https://github.com/go-gitea/gitea/actions/runs/40236681252/job/121299686933.
Pin the pre-2.54 "gc" strategy, older git ignores it.

https://github.com/go-gitea/gitea/pull/39745 is the more complete fix
which disables the auto-maintenance.
2026-10-26 14:05:34 +00:00
silverwind
85211296dd test: speed up go tests (#39914)
- Skip race instrumentation of the transpiled SQLite engine
`modernc.org/sqlite/lib` when `GOTEST_FLAGS` contains `-race`, Gitea
code and the driver boundary stay instrumented. `models/issues` drops
from ~10s to ~5s.
- Hash OAuth2 client secrets with `bcrypt.MinCost` in tests, like user
passwords already use the `dummy` hasher. `TestOAuth2` drops from ~22s
to ~2s on the PostgreSQL job.
- Stop the Redis locker's extension loop directly on `Close` instead of
waiting for its next tick, and run the memory locker tests under
`testing/synctest`. `modules/globallock` drops from ~12s to ~4s.

Signed-off-by: wxiaoguang <wxiaoguang@gmail.com>
Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2026-10-26 11:22:44 +00:00
silverwind
8abda62312 test: consolidate Go tests (#39962)
Consolidate all Go tests. Coverage is identical to before. Go tests are
around 5% faster while being 7% smaller. No non-test code is touched.
2026-10-24 13:48:19 +00:00
fixfon
ce7364e215 fix: get valid UTF-8 for diff_hunk and composer readme (#39932)
* Fixes #39929
* Fixes #39994

Co-authored-by: silverwind <me@silverwind.io>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2026-10-24 15:17:08 +02:00