Backport #40376 by @bircni
Plain repository creation marked a new repository as ready before its
git data, hooks and initial commit existed, and auto-init cloned the new
repository to build its initial commit on top of whatever it already
contained.
- Auto-init builds the initial commit in a freshly initialized temp
repository instead of a clone
- New repositories are inserted as being created and marked ready once
initialized, as fork, template generation, adoption and migrations
already do
---------
Co-authored-by: bircni <bircni@icloud.com>
Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
Co-authored-by: silverwind <me@silverwind.io>
Backport https://github.com/go-gitea/gitea/pull/39993
Gitea accepted unlimited wrong TOTP passcodes, so anyone holding an
account's password could enumerate the 6-digit code in minutes. This
allows 5 failed attempts per account, then refuses TOTP until 15 minutes
after the last one.
- The count lives in the cache, and the global lock spans the check,
validation and counting, so new sessions and concurrent requests cannot
widen it. With Redis, both are shared across instances
- Applies to every TOTP check: the web 2FA page, account recovery and
Basic auth with `X-Gitea-OTP` (API, git, packages)
- Only wrong or replayed passcodes count, server errors do not
- Scratch codes and WebAuthn stay usable as the recovery path while
locked
- Failures log `Failed authentication attempt for <user> from <ip>`,
which the fail2ban filter already matches
Co-authored-by: Sandiyo Christan <55909152+sandiyochristan@users.noreply.github.com>
Co-authored-by: silverwind <me@silverwind.io>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
Backport https://github.com/go-gitea/gitea/pull/40322
Several API and background paths change repositories without writing the
audit event the web UI writes for the same change. This records the
existing actions on those paths, and webhook, secret and OAuth2
application events now also keep the impersonator.
Conflicts resolved for release/v28:
- The web project close/reopen handler uses
`NotFoundOrServerError`/`ServerError`, as `ServerErrorAuto` does not
exist on this branch.
- The repository webhook delete API keeps its documented 404 response.
- The notifier test keeps the release branch layout with the new cases
appended.
Signed-off-by: bircni <bircni@icloud.com>
Co-authored-by: silverwind <me@silverwind.io>
Co-authored-by: delvh <dev.lh@web.de>
Backport https://github.com/go-gitea/gitea/pull/40377
The web repo search response embedded the whole commit status model
although the dashboard only uses its state and target URL. It now
returns just those two fields.
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
Backport https://github.com/go-gitea/gitea/pull/40381
The API accepted a new name for an organization's Owners team. The owner
team is looked up by its name, so the organization had no owner team
afterwards and its owners lost access to it.
The API now rejects the rename, as the web UI already does.
Fixes#40380
Backport https://github.com/go-gitea/gitea/pull/40192
The repository issue search JSON route sits behind the issues reader
check only, and the milestone page is open to anyone who can read either
issues or pull requests, since the issue routes have to tolerate pull
request permissions. Neither handler narrows the issue type to what the
viewer may read: the search route takes `type=pulls` straight from the
query or lists both types when it is absent, and the milestone page
always lists both. A team member granted only the Issues unit on a
private repository can therefore fetch every pull request's title and
body as JSON and see pull requests on milestone pages, while a
pull-requests-only reader sees issues there. I noticed it while
comparing these routes with the API `ListIssues` handler and the web
issue suggestions endpoint, which both already narrow the type. The
narrowing now lives in one small helper used by all three handlers, with
the search route answering 404 for a requested type the viewer cannot
read, like the API does. A unit test covers both handlers with an
issues-only permission.
Co-authored-by: Basavaraj S m <basavaraj@digiscrypt.com>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
Backport https://github.com/go-gitea/gitea/pull/39991
Changing a pull mirror address with an empty password field carried the
stored credentials over to the new address. The password is write-only,
so a repo admin who did not set up the mirror could send the owner's
token to a host they control, or pull another repository on the same
host that the token can read.
Stored credentials are now reused only when the address is unchanged,
like a changed username already drops the stored password. The API
cannot change the address and push mirrors never reuse credentials, so
both are unaffected.
Co-authored-by: Basavaraj S m <basavaraj@digiscrypt.com>
Co-authored-by: silverwind <me@silverwind.io>
Backport of the `GetAffectedFiles` fix from main (#40326) to v28.
`git diff --name-only` C-quotes paths containing characters such as `"`
or non-ASCII bytes, so they never matched protected file patterns. Use
`diff-tree -r -z` and split on NUL. Renames now report both old and new
paths.
Assisted-by: Codet:claude
Backport https://github.com/go-gitea/gitea/pull/40042
`GET /users/{username}/orgs/{org}/permissions` returned a user's team
roles to anyone who could see the org, revealing concealed members and
their roles. Now only the user, unrestricted org members and site admins
get the real answer, everyone else gets the non-member response:
- Outsiders get no roles, for public members too.
- Restricted members only get their own roles.
- Public-only tokens get none, and site admins need an `all`-scoped
token.
v28 lacks the doer token helpers from
https://github.com/go-gitea/gitea/pull/39690, so the check reads
`ctx.PublicOnly` and the request's token scope instead.
Assisted-by: Claude Code:claude-opus-5-5
Co-authored-by: Basavaraj S m <basavaraj@digiscrypt.com>
Backport #40363 by @lazerg
The container registry rejected image names with `__` or runs of `-`
(like `a__b` or `a--b`) with `NAME_INVALID`, because the name check
still used the distribution-spec v1.0 grammar. This updates the pattern
to the v1.1 grammar, which docker and podman already accept.
Fixes: https://github.com/go-gitea/gitea/issues/40360
Assisted-by: Claude Code:claude-opus-5-5
Signed-off-by: wxiaoguang <wxiaoguang@gmail.com>
Co-authored-by: Lazizbek Ergashev <lazerg2@gmail.com>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
Backport #40349 by @silverwind
Dropdowns initialized without an options object shared the default
Fomantic templates, so the ARIA patch kept wrapping `templates.menu` on
the defaults and retained every dropdown ever created. This grows memory
on the Actions run list, which re-renders its dropdowns on each refresh.
Each dropdown now gets its own templates copy, which the ARIA patch
modifies in place.
Fixes: https://github.com/go-gitea/gitea/issues/40347
Assisted-by: Claude Code:claude-opus-5-5
Co-authored-by: silverwind <me@silverwind.io>
Backport #40334 by @SudhanshuMatrix
Markdown renders `[X]` as a checked task like `[x]`, but parts of the
frontend only recognize lowercase `x`.
- Clicking a `[X]` checkbox now unchecks it instead of failing.
- Pressing Enter on a `- [X]` line in the editor continues the list with
`- [ ] ` instead of dropping the checkbox.
Assisted-by: Claude Code:claude-opus-5-5
Co-authored-by: Shudhanshu Singh <sudhanshuwriterblc@gmail.com>
Co-authored-by: silverwind <me@silverwind.io>
Backport https://github.com/go-gitea/gitea/pull/40131
Several code paths skipped checks that their siblings already perform.
- Code comment replies are rejected when they target a review of another
pull request or another user's pending review
- OAuth2 refuses tokens for users who can't sign in, and introspection
reports their tokens and already used refresh tokens as inactive
- AGit proc-receive runs the same pull request permission and wiki
checks as pre-receive
- Repository transfer drops the repository's owner-level scoped workflow
source registrations, and registrations whose source the owner no longer
owns are ignored
- The web editor's base branch copy into a fork and the fork's upstream
divergence info require read access to the base repository
- LFS downloads require sign-in under strict `REQUIRE_SIGNIN_VIEW`, like
git smart HTTP
- Unknown AGit target branches are reported as an unexpected ref again
Assisted-by: Claude:claude-opus-5-5
Backport https://github.com/go-gitea/gitea/pull/40261
The issue reference popup showed its labels without any spacing, and the
other label lists each used their own gap, with wrapped rows spaced
differently from columns.
`.labels-list` is now a wrapping flex list with `--gap-inline` by
default, giving the popup, issue sidebar and project cards equal gaps in
both directions. Lists inline with text, in issue list titles and
timeline events, stay inline so their labels still wrap one by one.
<img width="600" alt="Issue reference popup, issue sidebar and issue
list labels, before and after"
src="https://github.com/user-attachments/assets/fc4f0b9e-2b9d-4060-a2fb-c1bd3b7391db"
/>
Assisted-by: Claude Code:claude-opus-5-5
Backport #40315 by @GiteaBot
This PR contains the following updates:
| Package | Type | Update | Change |
|---|---|---|---|
| [go](https://go.dev/)
([source](https://redirect.github.com/golang/go)) | toolchain | patch |
`1.27.3` → `1.27.4` |
---
### Configuration
📅 **Schedule**: (UTC)
- Branch creation
- At any time (no schedule defined)
- Automerge
- At any time (no schedule defined)
🚦 **Automerge**: Disabled by config. Please merge this manually once you
are satisfied.
♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the
rebase/retry checkbox.
🔕 **Ignore**: Close this PR and you won't be reminded about this update
again.
---
- [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check
this box
---
This PR has been generated by [Mend Renovate
CLI](https://redirect.github.com/renovatebot/renovate).
<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0NC4yMTAuMCIsInVwZGF0ZWRJblZlciI6IjQ0LjIxMC4wIiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6WyJkZXBlbmRlbmNpZXMiXX0=-->
Backport #40291 by @lunny
`PUT/DELETE /repos/{owner}/{repo}/issues/{index}/lock` passed
`ctx.ContextUser` as the doer of `LockIssue` / `UnlockIssue`. In the
repo routes that is the owner of the repository, so on a repository of
an organization the lock and unlock timeline comments were created by
the organization instead of the user who did it. The web handler already
uses the signed-in user; this uses `ctx.Doer` as well.
Adds a subtest `DoerOnOrganizationRepo` to the existing
`TestAPILockIssue`: a member of an organization locks and unlocks an
issue of an organization repository, and the comments must be posted by
that member.
Found while testing audit logging of the issue lock events downstream.
_Authored by Codet (Claude)._
Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
When a file, README or wiki page is rendered as markup, the HTML is read
through a 32 KiB buffer to escape invisible and ambiguous characters. A
multi-byte character cut by that buffer right after a tag was shown as
broken characters, e.g. `<p>보기</p>` became `<p>���기</p>`. Such a part is
now kept for the next read. Two related cases are fixed as well:
- Invalid bytes right before a tag are marked as broken instead of
passing through raw as part of the tag.
- A BOM split across reads is kept instead of being escaped as
invisible.
To reproduce, view a Markdown file with 32734 `A` characters, a blank
line and `보기`, which puts `보` across the first 32 KiB of the rendered
HTML:
[split-rune-after-tag.md](https://github.com/user-attachments/files/34361104/split-rune-after-tag.md)
https://github.com/go-gitea/gitea/pull/39937 replaces this reader with a
single in-memory pass. This small fix can be backported to the release
branches.
Assisted-by: Claude Code:claude-opus-5-5
----
| Before (2ed6a6f61b) | After
(2a1d09755f) |
| --- | --- |
|

|

|
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
Update clippie to 4.3.1, which fixes copy buttons in browsers that have
`navigator.clipboard.write` but no `ClipboardItem`, such as Pale Moon.
Text is now copied through `writeText`, with a copy event as fallback.
The same update is part of https://github.com/go-gitea/gitea/pull/40292
on main.
Fixes: https://github.com/go-gitea/gitea/issues/40287
Assisted-by: Claude Code:claude-opus-5-5
Backport #40053 by @silverwind
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>
Co-authored-by: silverwind <me@silverwind.io>
Backport #40260 by @lazerg
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: Lazizbek Ergashev <lazerg2@gmail.com>
Co-authored-by: silverwind <me@silverwind.io>
Backport #40120 by @silverwind
Several code paths skipped checks their siblings perform, or cleaned up
more than they validated.
- Official team review requests now count, and removing one no longer
marks an unrelated review official
- Release edits only delete files of validated attachments
- Rejected container uploads no longer delete an existing blob
- Attachment removal only removes the uploader's own pending uploads
- OpenID sign-in checks the allow and block lists against the normalized
identifier
- HTTP git access is rejected while a repository is being created, like
SSH
Signed-off-by: silverwind <me@silverwind.io>
Co-authored-by: silverwind <me@silverwind.io>
Co-authored-by: delvh <dev.lh@web.de>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
Backport #40102 by @Zettat123
The post-receive hook syncs pushed branches to the database, but
`is_empty` and the default branch of an empty repository were only
updated later by the `push_update` queue. Until then the API treated the
repository as empty (branch list `null`, `GET /branches/{branch}` 500),
and the queue overwrote the default branch chosen by the hook or set via
the API.
`SyncBranchesToDB` now initializes an empty repository and repairs a
default branch missing in git in its locked transaction, so the state is
final when `git push` returns. The push queue and web file edits retry
it while the repository is still empty.
- The default branch is the configured one if it exists, else `main`,
else `master`, else the first branch by name, like GitLab. HEAD follows
it.
- A first push of several branches no longer depends on push order. The
push that initializes a repository still prints no pull request hints,
like GitHub.
---------
Co-authored-by: Zettat123 <zettat123@gmail.com>
Co-authored-by: silverwind <me@silverwind.io>
Backport https://github.com/go-gitea/gitea/pull/40110
The post-receive hook wrote each push's new commit into the branch
table. Each push runs its own hook after the ref is updated, so with
pushes in close succession, like CI pushing back or a quick force-push,
a slower first hook can finish last. The table then keeps the older
commit, or marks a re-created branch as deleted.
- The sync reads each pushed branch's state from git under a repo-scoped
lock
- Deletions go through the same sync, so a re-created branch stays
active
- A branch that fails to sync is logged and skipped instead of aborting
the batch
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
Co-authored-by: Giteabot <teabot@gitea.io>
Backport #40252 by @silverwind
The `alpine:3.24` base image lags behind fixes published to the Alpine
repository.
Both images now run `apk upgrade` before `apk add`. Packages from `apk
add` are already current, so this only affects the preinstalled base
packages.
_Written by Claude (Opus 5.5)._
Co-authored-by: silverwind <me@silverwind.io>
Backport #40237 by @Shadow0Bit
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).
Co-authored-by: rafał przypek <58443512+Shadow0Bit@users.noreply.github.com>
Backport #40207 by @silverwind
The issue reference popup built its `/info` request from the raw link
path, so a link ending in `/owner/repo/issues/N` queried an unrelated
location.
It now builds the request from the owner, repo, type and index parsed
from the link, with `parseIssueHref` anchored to the pathname under
`appSubUrl`.
Co-authored-by: silverwind <me@silverwind.io>
Backport #40126 by @silverwind
The job emitter resolves a dependency chain in several rounds in memory,
but a job's `if:` reads its needs' results from the database, where a
need skipped or failed earlier in the same pass was still blocked. A job
with `if: always() && needs.build.result == 'skipped'` was therefore
skipped instead of started.
Finished statuses are now persisted at the end of each round, which also
replaces the separate handling of skipped and failed reusable workflow
callers.
Co-authored-by: silverwind <me@silverwind.io>
On release/v28, `PATCH /repos/{owner}/{repo}/milestones/{id}` with
`"due_on": null`, the documented way to remove a deadline, returns HTTP
500. The backport https://github.com/go-gitea/gitea/pull/39921 changed
`EditMilestoneOption.Deadline` to `optional.Option[*string]`, which
decodes `null` as a slice holding a nil pointer, and the go-chi/binding
validator panics on that element (`reflect: call of
reflect.Value.Interface on zero Value`).
The field has no binding rules, so tag it `form:"-"` to skip validation.
main is unaffected since https://github.com/go-gitea/gitea/pull/39528
moved the binding into Gitea.
Backport #40166 by @perfectra1n
Concurrent `notification-service` workers can deadlock in the
transaction for-loop.
The transaction is useless, so it is removed to avoid deadlock.
Co-authored-by: Jon Fuller <jonfuller2012@gmail.com>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
Backport #40167 by @perfectra1n
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: Jon Fuller <jonfuller2012@gmail.com>
Co-authored-by: silverwind <me@silverwind.io>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
Backport https://github.com/go-gitea/gitea/pull/40127
The starred and watched repository API lists converted repositories
without loading their attributes, so `language` was always empty. They
are now loaded in one batch, owners included.
Three of these handlers also continued after an internal error and wrote
a second response body, they now return.
Backport #40130 by @bircni
Requiring branches to be up to date reruns the full CI matrix on every
waiting PR after each merge, which saturates our 20 concurrent jobs. A
merge queue still tests against the latest `main`, but once per batch.
This runs the PR workflows on `merge_group` and reports `giteabot/lgtm`
on queue commits, since GiteaBot only sets it on PR heads. Mergers queue
PRs with "Merge when ready" instead of `reviewed/wait-merge`, so
giteabot no longer updates branches. Nothing changes until the
`merge-queue` ruleset is enabled and "Require branches to be up to date"
is turned off. Backport to `release/v28` before the ruleset covers it.
Co-authored-by: bircni <bircni@icloud.com>
Co-authored-by: silverwind <me@silverwind.io>
Backport #40125 by @silverwind
A failed contributor stats generation never released its lock, so after
the cached error expired, the contributors and code frequency pages kept
saying stats are being generated until a restart. A generation
outlasting the 5 second wait also leaked its goroutine on an unread
channel.
The lock is now claimed atomically and released together with the
completion signal when generation ends, and a cache miss after the wait
counts as still generating.
Co-authored-by: silverwind <me@silverwind.io>
Backport #40060 by @soujasK
Fixes https://github.com/go-gitea/gitea/issues/40056
The admin web UI lists every account type except organizations, but
`gitea admin user list` and `GET /api/v1/admin/users` only returned
individual users. That hid bots created for CI, even though the CLI and
the admin API can both create and manage them.
- The admin web UI, the admin API and the CLI share one type list:
individual, reserved, bot and remote accounts.
- `gitea admin user list` (and `--admin`) gains a `Type` column showing
`User`, `Bot`, `Reserved` or `Remote`.
Signed-off-by: Soujas K <kudchadkarsoujas@gmail.com>
Co-authored-by: soujasK <121026960+soujasK@users.noreply.github.com>
Co-authored-by: silverwind <me@silverwind.io>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
Backport https://github.com/go-gitea/gitea/pull/40121
With `[oauth2_client].ACCOUNT_LINKING = auto`, the link account sign-up
form linked the external identity to an existing account matching the
submitted user name or email and signed in as it. Automatic linking now
only happens when the existing user matches the external identity,
otherwise the linking login page asks for the account's password.
`release/v28` lacks `TestOAuth2AvatarFromPicture`, so only the new test
is added.
Co-authored-by: bircni <bircni@icloud.com>
Co-authored-by: Giteabot <teabot@gitea.io>
Backport #39930 by @lunny
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: Lunny Xiao <xiaolunwen@gmail.com>
Co-authored-by: silverwind <me@silverwind.io>
Backport #40114 by @silverwind
The repository issue and pull request lists filter `access` by
`repo_id`, which no index covers, so every load scans the whole table.
Issue counts on larger repositories merge three single-column indices,
and the API pull request list loads the latest reviews with `id IN
(SELECT max(id) ... GROUP BY ...)`, which MySQL runs as a scan of every
review, about 1.1s on
https://gitea.com/api/v1/repos/gitea/gitea-mcp/pulls?limit=1.
- Index `access.repo_id`
- Index `team_repo.repo_id`
- Replace the single `repo_id`, `is_closed` and `is_pull` indices with
one `issue` index on `(repo_id, is_closed, is_pull)`
- Join the latest review ids instead of `id IN (subquery)`
Median times in ms on MySQL 8.4 with tables sized like gitea.com (1M
access rows, 500k issues, 200k reviews), for a copy of
https://gitea.com/gitea/gitea-mcp and a repository with 9.7k issues:
| Page | Before | After |
|---|---|---|
| `/{owner}/{repo}/issues` | 107 | 40 |
| `/{owner}/{repo}/pulls` | 106 | 32 |
| `/{owner}/{repo}/pulls?state=closed` | 153 | 35 |
| `/{owner}/{repo}/issues/{index}` | 141 | 60 |
| `/{owner}/{repo}/issues`, 9.7k issues | 303 | 53 |
| `/api/v1/repos/{owner}/{repo}/pulls?limit=50` | 180 | 46 |
| `/api/v1/repos/{owner}/{repo}/pulls?limit=1` | 137 | 16 |
| `/api/v1/repos/{owner}/{repo}/issues`, 9.7k issues | 248 | 43 |
Co-authored-by: silverwind <me@silverwind.io>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
Backport #40058 by @silverwind
A review's text is stored on both the review and its timeline comment,
but editing it in the web UI or through the issue comment API only
updated the comment. The reviews API kept returning the old body
afterwards.
Extracted out of https://github.com/go-gitea/gitea/pull/39865.
*Written by Claude.*
Co-authored-by: silverwind <me@silverwind.io>
Backport #40016 by @basavaraj-sm05
Project board cards list the pull requests that reference their issue,
but loaded them without checking the viewer's access. A private pull
request mentioning a public issue showed its title, number and state on
that issue's board to anyone who can view the board, anonymous visitors
included.
Repository and organization boards now skip linked pull requests in
repositories where the viewer cannot read pull requests, matching how
the issue page already hides such references.
Co-authored-by: Basavaraj S m <basavaraj@digiscrypt.com>
Co-authored-by: silverwind <me@silverwind.io>
Co-authored-by: bircni <bircni@icloud.com>
Backport https://github.com/go-gitea/gitea/pull/39945
API tokens and Actions task tokens could see data beyond their scope
through user-scoped API routes and web profile pages.
- Actions task tokens authenticate as a shared system user with a
negative ID, which org, project and SSH/GPG key filters treated as "no
owner filter". These filters now check `!= 0`, so system users own
nothing. The `/api/v1/user` routes except `GET /api/v1/user` only accept
individual and bot accounts, and repo search no longer skips access
checks for the owner.
- `/{username}` only accepts tokens for RSS/Atom feeds. HTML profile and
org pages render as anonymous for token requests.
- User and org feeds require `read:user` or `read:organization` from
tokens, the same way repo feeds require `read:repository`.
`release/v28` lacks https://github.com/go-gitea/gitea/pull/39967, so
`/{username}` enables basic auth only for feed requests through a
middleware. The profile page token tests from
https://github.com/go-gitea/gitea/pull/39853 are folded into
`TestFeedUser`, because profile pages no longer accept tokens.
Co-authored-by: bircni <bircni@icloud.com>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
Co-authored-by: Giteabot <teabot@gitea.io>
Backport https://github.com/go-gitea/gitea/pull/40106
Repository-level and instance-level runners still picked up waiting jobs
of repositories with Actions disabled.
https://github.com/go-gitea/gitea/pull/30331 only covered owner-level
runners, by filtering them out in SQL.
Pickup now checks the Actions unit of each job it is about to claim, for
every runner scope, and cancels the job instead when Actions is
disabled, also honoring `DISABLED_REPO_UNITS`. Disabling Actions
therefore cancels its queued jobs once a matching runner polls, instead
of leaving them waiting until `ABANDONED_JOB_TIMEOUT`.
Co-authored-by: silverwind <me@silverwind.io>
Backport #40118 by @lazerg
The approver limit was checked before writing each `Reviewed-by:` line
but compared with `>`, so the default merge message got one more trailer
than `DEFAULT_MERGE_MESSAGE_MAX_APPROVERS` allows (2 with a limit of 1,
11 with the default 10). It now stops once the limit is reached.
Fixes https://github.com/go-gitea/gitea/issues/40116
Assisted-by: Claude Code:claude-opus-5-5
Co-authored-by: Lazizbek Ergashev <lazerg2@gmail.com>
Backport #40099 by @silverwind
Runs triggered by pull request reviews took their ref and commit from
the review's `commit_id` instead of the pull request. They now use the
pull request head like other pull request events, and their commit
status is set on the commit that ran.
Co-authored-by: silverwind <me@silverwind.io>
Backport #40104 by @0xJacky
Remove the `body {margin: 0; padding: 0}` reset from
https://github.com/go-gitea/gitea/pull/38396, which left HTML mails
flush against the edge in Apple Mail and Thunderbird. The devtest
preview stops injecting its own padding, so it matches delivered mails.
These clients render the mail as a document and apply the default 8px
body margin again, as with GitHub and GitLab notifications. Webmail
clients replace `<body>` and keep their own inset.
Fixes: https://github.com/go-gitea/gitea/issues/40103
Assisted-by: Codex:GPT-6.1, Claude:Opus 5.5
Co-authored-by: Jacky <jacky-943572677@qq.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: silverwind <me@silverwind.io>
Backport #40001 by @silverwind
The dashboard counts ran queries whose cost grew with the whole instance
instead of the viewing user. On https://gitea.com/pulls the two review
counts alone take about 1.4s per page load.
- Check the owner of the already joined repository with `EXISTS` instead
of listing every public repository and public user
- Hide superseded review requests with `NOT EXISTS` instead of grouping
every review on the instance
- Skip the review counts on `/issues`, which never shows them
- Index `team_user.uid` for permission and team lookups by user
- Fix indices for table `watch`, `package_property` and `action_run`,
fix#40090
Median page times in ms, before → after, on a synthetic dataset sized
like gitea.com (175k users, 40k repos, 120k issues, 1M comments):
| Page | SQLite | PostgreSQL 17 | MySQL 8.4 | MariaDB 13 |
|---|---|---|---|---|
| `/pulls` | 901 → 56 | 330 → 156 | 189 → 124 | 192 → 218 |
| `/pulls?type=review_requested` | 1797 → 66 | 557 → 254 | 307 → 245 |
604 → 499 |
| `/pulls?type=reviewed_by` | 1646 → 118 | 537 → 316 | 515 → 265 | 528 →
682 |
| `/pulls?type=mentioned` | 1403 → 46 | 426 → 119 | 165 → 116 | 179 →
179 |
| `/issues` | 923 → 33 | 293 → 39 | 178 → 65 | 140 → 41 |
| `/api/v1/repos/issues/search` (anonymous) | 870 → 110 | 144 → 104 |
123 → 87 | 170 → 193 |
MariaDB checks the owner per row on long scans across all public
repositories, which makes a few pages slower there.
Co-authored-by: silverwind <me@silverwind.io>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
Backport #40095 by @hktitof
when a repository directory exists on disk without a database row, for
example after a failed delete, POST /user/repos answered 500 with an
empty message
the migrate endpoint already answers 409 for this error and the fork API
got the same treatment in https://github.com/go-gitea/gitea/pull/39909,
so the create handler now maps ErrRepoFilesAlreadyExist to 409 too. this
covers POST /user/repos, POST /orgs/{org}/repos and the admin user route
since they all go through CreateUserRepo
the integration test creates the leftover directory and asserts 409, on
master it gets 500. runs on sqlite as usual
this also touches routers/api/v1/repo/repo.go, which several open PRs
modify, but none of them changes this error mapping
Signed-off-by: wxiaoguang <wxiaoguang@gmail.com>
Signed-off-by: hktitof <hktitof@users.noreply.github.com>
Co-authored-by: Abdellatif Anaflous <62770500+hktitof@users.noreply.github.com>
Co-authored-by: hktitof <hktitof@users.noreply.github.com>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
Backport https://github.com/go-gitea/gitea/pull/39960
Locking a pull request stops users without write access from commenting,
but the review paths never checked the lock, so any signed-in user could
still post reviews, code comments and replies on a locked pull request.
The cherry-pick conflicted on the `repo-diff.ts` imports, because
`release/v28` has no `DiffFileTreeLocale`.
Co-authored-by: Basavaraj S m <basavaraj@digiscrypt.com>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
Backport https://github.com/go-gitea/gitea/pull/39432
- A `#L0` URL hash made `selectRange` index the line list at -1 and
throw inside `initRepoCodeView`, which aborted every init function after
it on the page. Line numbers below 1 now select nothing.
- The JS error filter only accepted stacks under the asset prefix, but
the vite dev server serves the sources from `/web_src/`, so dev mode
dropped every error without showing a banner. Outside production, the
filter now also accepts stacks from `/web_src/`.
Backport #40025 by @somaz94
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
Co-authored-by: somaz <112675579+somaz94@users.noreply.github.com>
Backport https://github.com/go-gitea/gitea/pull/39980
Following a bot user from its profile succeeded but answered with an
error, because the follow handler only rendered a response for
individuals and organizations.
The cherry-pick conflicted in `OwnerProfile`, which still serves the
user feeds on `release/v28`.
Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
Backport https://github.com/go-gitea/gitea/pull/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`
`release/v28` lacks two helpers this needs, so they are included:
`insertInvalidWorkflowRun`, split out of `handleInvalidWorkflows` by
https://github.com/go-gitea/gitea/pull/39480, and
`packages.NewLimitedReader` from
https://github.com/go-gitea/gitea/pull/39366.
Co-authored-by: bircni <bircni@icloud.com>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
Backport https://github.com/go-gitea/gitea/pull/39964
The repo home URL served the branch or file commit feed for RSS or Atom
`Accept` headers without the code unit check of the explicit
`/rss/branch/*` routes, exposing commit messages and authors to users
without code access.
Co-authored-by: Basavaraj S m <basavaraj@digiscrypt.com>
Backport #40055 by @myers
On SQLite, the `is_reusable_caller = false` filters (e.g. the admin job
queue page) are planned from `IDX_action_run_job_is_reusable_caller`,
which matches almost every row, so nearly the whole `action_run_job`
table is read. `ANALYZE` does not help: `sqlite_stat1` only keeps
average rows per key.
No query needs that index. `is_reusable_caller = true` is only used by
`expandedCallerCond`, always together with `repo_id` and
`concurrency_group`. Their plans use other indexes on SQLite, PostgreSQL
17 and MySQL 8.4 (PostgreSQL is slightly slower with it).
This removes the index tag. `SyncAllTables` drops the existing index on
the next start, so no migration is needed.
Job queue count on SQLite, before: a search on the `is_reusable_caller`
index; after: a `MULTI-INDEX OR` on the `status` and `pickup` indexes.
On an instance with about 7,000 jobs the admin job queue page went from
`Page: 784ms` to `39ms` (measured with an earlier revision of this PR
that gave the same plan).
Signed-off-by: Myers Carpenter <myers@maski.org>
Co-authored-by: Myers Carpenter <myers@maski.org>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
Backport https://github.com/go-gitea/gitea/pull/40046
Mermaid scales diagrams wider than the markup column down to its width,
but the iframe kept the unscaled viewBox height, leaving a large blank
area below them. The iframe now uses a CSS `aspect-ratio` capped at the
viewBox height. Diagrams that don't scale (`useMaxWidth: false`) keep
the fixed height.
The cherry-pick conflicted only on the `srcdoc` line, which uses an
`html` template on `main` but a plain string on `release/v28`.
Fixes: https://github.com/go-gitea/gitea/issues/40045
Backport https://github.com/go-gitea/gitea/pull/40050
`release/v28` is still on x/net v0.60.0, so the cherry-pick conflicted.
x/net v0.62.0 raises the minimum x/crypto, x/sync, x/sys, x/text and
x/tools versions, which `go get` and `make tidy` bump to what `main`
already uses.
Co-authored-by: Giteabot <teabot@gitea.io>
Backport #39973 by @Hello-Liar
The file view, blame and web editor read `.editorconfig` from the
default branch, so branch-specific settings like tab width were ignored.
The file view's middleware ran before the ref was resolved, and blame
never loaded it.
- `GetEditorconfig` reads the current commit, falling back to the
default branch only where no ref is resolved
- `Home` and `RefBlame` load the editorconfig after ref resolution
Fixes: https://github.com/go-gitea/gitea/issues/27413
Signed-off-by: silverwind <me@silverwind.io>
Co-authored-by: Hello-Liar <80651389+Hello-Liar@users.noreply.github.com>
Co-authored-by: silverwind <me@silverwind.io>
Backport #40017 by @lunny
OneDev 16.8 moved the server version endpoint from
`/~api/version/server` to `/~api/server/version`. Both are tried, the
new one first, and both errors are reported when neither works.
Signed-off-by: wxiaoguang <wxiaoguang@gmail.com>
Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
Co-authored-by: silverwind <me@silverwind.io>
Backport #39855 by @basavaraj-sm05
Legacy (v1 to v3) artifact uploads stored the request's
`Content-Encoding` header in the column that v4 artifacts read as their
`Content-Type`.
- Store only the `gzip` marker on legacy uploads, the only encoding
their clients send
- Pick the PDF and audio/video serve headers only for content types that
`mime.ParseMediaType` accepts
Co-authored-by: Basavaraj S m <basavaraj@digiscrypt.com>
Co-authored-by: silverwind <me@silverwind.io>
Backport #39958 by @SHIVANSHGARG07
The project milestone filter listed every milestone of the repo, or of
all accessible org repos for org projects, including ones with no issue
in the project. That made the dropdown noisy and unhelpful.
Both repo and org projects now list only milestones that have at least
one issue linked to the project, via a new `ProjectID` option on
`FindMilestoneOptions`.
Fixes: https://github.com/go-gitea/gitea/issues/39150
Co-authored-by: Shivansh Garg <shivanshgarg587@gmail.com>
Co-authored-by: silverwind <me@silverwind.io>
Backport #39966 by @silverwind
Each `release-create-tag` run created a deployment record, which makes
GitHub show a useless "This branch has not been deployed" box on every
PR:
<img width="819" height="113" alt="image"
src="https://github.com/user-attachments/assets/129c8348-1d70-46b9-8996-8872c84a11f2"
/>
With `deployment: false`, the `release-signing` approval and branch
policy still apply.
Co-authored-by: silverwind <me@silverwind.io>
Backport of https://github.com/go-gitea/gitea/pull/39934 to release/v28.
Runner token verification (PBKDF2) dominated CPU on instances with many
runners. Successful verifications are now cached in a dedicated LRU.
Conflict resolved by keeping v28's connect v1 interceptor and adding
only the cache.
_Backport prepared with Codet._
Co-authored-by: silverwind <me@silverwind.io>
The Packages row in the team settings read "Manage repository
packages.", but packages belong to the owner, so a team's Packages
permission applies to every package of the organization, regardless of
the team's repositories. Reword it to say so. The docs get the same
clarification in https://gitea.com/gitea/docs/pulls/605.
Co-authored-by: silverwind <me@silverwind.io>
`actions/upload-artifact` v4 and later send an absolute `expires_at`
computed with the runner's clock, which Gitea stored unchecked. A runner
clock running behind made artifacts expire at the next cleanup, and
workflows could keep artifacts longer than `ARTIFACT_RETENTION_DAYS`.
- Requested expiries are bounded by Gitea's clock, at least 1 day and at
most `ARTIFACT_RETENTION_DAYS` when it is not `0`. Longer
`retention-days` requests now get the instance limit.
- `github.retention_days` now carries `ARTIFACT_RETENTION_DAYS`, so
upload actions cap `retention-days` themselves and log a warning, like
on GitHub.
Co-authored-by: bircni <bircni@icloud.com>
Backport https://github.com/go-gitea/gitea/pull/39947
PRs targeting `release/v28` run this branch's `giteabot.yml`, and
`v1.3.1` runs the merge queue when such a PR merges, so the branch needs
the same pin. `giteabot-backport.yml` gets it too to keep the branches
in sync.
Backport #39873 by @nazem-droubi
Fixes#39651
When an org-owned repo has a repo label and an org label with the same
name, `POST`/`PUT /repos/{owner}/{repo}/issues/{index}/labels` with
label names attached both of them.
With this change the repo label is used when the names collide, and org
labels are only looked up for the names that didn't match a repo label.
Names that only exist at the org level still resolve to the org label as
before. I documented the behavior on `IssueLabelsOption.Labels` and
regenerated the swagger files.
Picking the repo label seemed the least surprising choice since it's the
more specific one, but I'm happy to change it (for example to return a
422 on ambiguous names) if you'd prefer that.
Tests: added `TestAPIAddIssueLabelsWithSharedRepoAndOrgLabelName`, which
covers both POST and PUT. It fails on `main` (3 labels attached instead
of 2) and passes with this change. I ran the existing add/replace label
integration tests locally on sqlite, plus `go vet` and gofmt.
AI disclosure: the code and test in this PR were written primarily by an
AI coding agent working on my behalf. I'm happy to walk through it or
revise anything during review.
Signed-off-by: Nazem <214302554+nazem-droubi@users.noreply.github.com>
Co-authored-by: Nazem <nazem98@gmail.com>
Co-authored-by: Nazem <214302554+nazem-droubi@users.noreply.github.com>
Co-authored-by: silverwind <me@silverwind.io>
Backport #39944 by @basavaraj-sm05
The tags feed (`tags.rss` / `tags.atom`) lives in the tags route group,
which only requires code read access, yet it lists every published
release next to the plain tags and includes each release's title and
rendered note. The releases page and `releases.rss` require releases
read access, and the tags page only shows tag names to users without it,
so the feed is the one place that leaks. A team member granted Code but
not Releases on a private repo, or anyone on a public repo whose
Releases unit is disabled, can read all release notes this way. I
noticed it while comparing the feed routes with the tags template. When
the doer cannot read releases, the feed now lists releases as plain
tags, linking to `/src/tag/` like the tags page does.
Co-authored-by: Basavaraj S m <basavaraj@digiscrypt.com>
Backport #39888 by @yuhongwei380
For repos with many issues, the GitHub API only allows cursor-based
pagination instead of page-based pagination after a certain page.
A full migration of such repos failed with a 422 response.
Now, we dynamically switch how we migrate based on the response from the
GitHub API.
Fixes#39882
Assisted-by: Codex:GPT-6
Signed-off-by: Phoenix <44333391+yuhongwei380@users.noreply.github.com>
Co-authored-by: Phoenix <44333391+yuhongwei380@users.noreply.github.com>
Co-authored-by: delvh <dev.lh@web.de>
Co-authored-by: silverwind <me@silverwind.io>
Backport #39885 by @basavaraj-sm05
Several `/repos/{owner}/{repo}/issues/{index}/...` API endpoints load
the issue by index without checking
`CanReadIssuesOrPulls(issue.IsPull)`, unlike `GetIssue`,
`ListIssueComments` and `GetIssueReactions`. The route group's
`mustEnableIssuesOrPulls` passes when the caller can read either unit,
so someone who can read issues but not pull requests (a team with only
the Issues unit, or per-unit anonymous access on a public repo) can read
a pull request's whole conversation through `/timeline`, plus its
labels, subscribers, attachments and tracked times, and can subscribe to
it. The reverse holds for issues.
These handlers now return 404 in that case, like their siblings.
Co-authored-by: Basavaraj S m <basavaraj@digiscrypt.com>
Co-authored-by: silverwind <me@silverwind.io>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
Backport #39364 by @shoemoney
Sorting by an exclusive label scope joined `issue_label`, returning one
row per label. Issues with several labels were listed repeatedly and
pushed others off the page, and `IssueIDs` returned inflated totals.
The sort key now comes from a correlated subquery, so each issue yields
one row.
Fixes https://github.com/go-gitea/gitea/issues/35711
This base-branch update was prepared with AI assistance.
Co-authored-by: Jeremy Schoemaker <jeremy@shoemoney.com>
Co-authored-by: silverwind <me@silverwind.io>
Backport #39926 by @fixfon
Fixes https://github.com/go-gitea/gitea/issues/39925
RFC 6749 §2.3.1 has clients form-urlencode the client id and secret
before building the HTTP Basic header. `openid-client` with
`client_secret_basic` does this and sends `-` as `%2D` and `_` as `%5F`.
The token and introspection endpoints used the raw header values, so
these clients failed with `invalid_client`. Both endpoints now decode
the values with `url.QueryUnescape` before the client lookup, the secret
check and the body consistency check, and reject a value that does not
decode. Plain HTTP Basic parsing in `httpauth` is unchanged, since the
encoding only applies to OAuth client authentication.
Clients that don't encode are unaffected, since no client id or secret
Gitea has ever issued contains `+` or `%`.
Co-authored-by: fixfon <12512757+fixfon@users.noreply.github.com>
Co-authored-by: silverwind <me@silverwind.io>
Backport #39838 by @silverwind
When `navigator.clipboard.readText()` runs before the page's copy has
landed, Firefox shows its "Paste" prompt, which cannot be interacted
with when headless. Avoid that and and use
`dom.events.testing.asyncClipboard` which is a pref meant for testing
that disabes this prompt.
Fixes: https://github.com/go-gitea/gitea/actions/runs/39113819632/job/117635434106
Co-authored-by: silverwind <me@silverwind.io>
Backport https://github.com/go-gitea/gitea/pull/39869
`PATCH /repos/{owner}/{repo}/milestones/{id}` always overwrote the due
date with `due_on`, so a request that only changed other fields, such as
`{"state": "closed"}`, silently removed it.
The due date is now kept when `due_on` is omitted, and `"due_on": null`
or `"due_on": ""` remove it.
Only the milestone fix is backported. The issue and pull request
deadline changes of https://github.com/go-gitea/gitea/pull/39869 build
on https://github.com/go-gitea/gitea/pull/38677, which isn't on v28.
Backport #39631 by @stackedbyaradhya
Release webhook notifications never mention attached files, although the
payload carries them.
The summary shared by all webhook providers now appends an asset count
like `(assets: 2)` for created and updated releases.
Closes https://github.com/go-gitea/gitea/issues/39630
Co-authored-by: Aradhya Jain <aradhyaj736@gmail.com>
Co-authored-by: silverwind <me@silverwind.io>
Backport #39782 by @basavaraj-sm05
The RubyGems compact index (the shared `/versions` file and per-package
`info/<name>` files) is line-based.
https://github.com/go-gitea/gitea/pull/38061 rejected line breaks in the
gem name, but the platform, dependency names and version requirements
from the gemspec still accepted them, letting an uploader forge index
lines for bundler clients.
The parser now rejects a line break in any of those fields. The Marshal
based endpoints are length prefixed and unaffected.
Co-authored-by: Basavaraj S m <basavaraj@digiscrypt.com>
Co-authored-by: silverwind <me@silverwind.io>
Backport #39861 by @silverwind
Hovering a button in a primary or red button group showed a grey frame,
because the generic group hover border applied to colored groups too.
Green groups had no colors at all.
Colored groups now let the hover background fill the border, and green
groups get the same colors as primary and red. The devtest page shows
all three.
<img width="569" height="304" alt="Hovered buttons in uncolored,
primary, red and green button groups, before and after"
src="https://github.com/user-attachments/assets/e0fb6b16-f1f1-459b-9848-9386cd9453c9"
/>
Extracted from https://github.com/go-gitea/gitea/pull/38404
Co-authored-by: silverwind <me@silverwind.io>
Backport #39887 by @silverwind
Code comments next to a diff hunk could show one line too high in the
conversation view vs. in the code view that showed them on the correct
line.
- Treat the hunk end in `CutDiffAroundLine` as exclusive, so the line
after a hunk falls back to the unchanged-line context
- Don't count `\ No newline at end of file` markers as lines when
cutting the hunk
- Share the unchanged-line fallback with migrated review comments
Co-authored-by: silverwind <me@silverwind.io>
Backport #39890 by @SHIVANSHGARG07
strings.Split("", ",") returns []string{""} (length 1), not an empty
slice, so the previous len(splitted) > 0 guard was always true and never
skipped the label ID lookup, even when the labels query param was
absent. Check the raw trimmed param for emptiness before splitting,
mirroring the pattern already used elsewhere in this file.
Fixes: https://github.com/go-gitea/gitea/issues/39889
Co-authored-by: Shivansh Garg <shivanshgarg587@gmail.com>
Backport https://github.com/go-gitea/gitea/pull/39839 by @silverwind
Several handlers and model helpers skipped checks that their siblings
already perform.
- Only match principal keys when looking up SSH certificate principals
- Return no attachments for an unsaved issue instead of every issue-less
one
- Reject issue and comment attachments when adding release attachments
- Share one permission check for editing, deleting and reacting to issue
content and for comment attachments between the web UI and the API,
refusing them on locked issues for users who can't write
- Reject issue edits, deletion and label changes in archived
repositories via the API
- Apply cross-origin protection to the repository topics endpoint
- Return 404 for the repositories tab of individual users and respect
profile visibility for the heatmap
* Fixes: https://github.com/go-gitea/gitea/issues/39226
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
Co-authored-by: bircni <bircni@icloud.com>
Backport #39652 by @Ubayed-Bin-Sufian
Users with "Only Email on Mention" can now still receive email for the
events they picked in a custom repository watch, covering issues, pull
requests and releases. The setting is renamed to "Only Email on Mention
and Custom Watches" to make this explicit, matching GitHub's
"Participating, @mentions and custom".
"All activity" watches don't bypass the setting, because they are also
created automatically by `AUTO_WATCH_NEW_REPOS` for repository creators
and team members. To keep picking every event distinct from "All
activity", the custom watch dialog now stores a new `WatchModeCustom`.
Existing custom watches keep working without a migration.
Addresses: https://github.com/openSUSE/openSUSE-git/issues/183
Ref: https://github.com/go-gitea/gitea/issues/35492
Co-authored-by: Ubayed Bin Sufian <ubayedbinsufian@gmail.com>
Co-authored-by: bircni <bircni@icloud.com>
Backport #39833 by @basavaraj-sm05
Incoming email reply tokens stay valid for a year and are verified with
`user.Rands`, which is not rotated when an account is deactivated or
prohibited from signing in. A suspended user could therefore keep
commenting on public repos by replying to old notifications.
`DecodeToken` now rejects tokens of organizations, inactive users and
users prohibited from signing in, which covers every incoming mail
handler.
Co-authored-by: Basavaraj S m <basavaraj@digiscrypt.com>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
Backport #39831 by @lunny
When pushing the merge commit to the base repo fails (e.g.
non-fast-forward), the merge intent recorded by
https://github.com/go-gitea/gitea/pull/39442 is left behind.
`merged_commit_id` then points to a commit that does not exist in the
base repo, and `git branch --contains` fails with `no such commit`, so
the PR can never be checked or merged again.
- Clear the recorded merge intent if the push fails and the commit is
not on the base branch
- `IsCommitInBranch` now returns false for a missing commit, so
already-stuck PRs recover on the next check
Fixes: https://github.com/go-gitea/gitea/issues/39824
Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
Co-authored-by: silverwind <me@silverwind.io>
Backport #39818 by @SHIVANSHGARG07
parseProtobufBody read the full Twirp request body via io.ReadAll with
no size limit, allowing an authenticated runner token holder to force
unbounded memory allocation. Cap it at 1 MiB via io.LimitReader,
matching the existing pattern in job_summary.go.
Fixes https://github.com/go-gitea/gitea/issues/39814
Co-authored-by: Shivansh Garg <shivanshgarg587@gmail.com>
Backport #39785 by @bircni
The [Gitea VS Code extension](https://gitea.com/gitea/gitea-vscode)
currently signs in through the builtin `tea` OAuth2 application. Gitea
keeps one grant per user and application, so anyone who has already
signed in with the tea CLI gets `a grant exists with different scope`
when the extension requests its own scopes, and sign-in fails
(gitea/gitea-vscode#24).
This adds a dedicated builtin application for the extension, following
the same mechanism as the existing CLI entries:
| | |
|---|---|
| client ID | `75a9ec3e-42b5-40cb-9144-9ea96ecd56a6` |
| config name | `gitea-vscode` |
| display name | `gitea-vscode` |
| redirect URIs | `http://127.0.0.1`, `https://127.0.0.1` (loopback, any
port) |
It is enabled by default via `[oauth2].DEFAULT_APPLICATIONS`. Instances
that set that option explicitly need to add `gitea-vscode` to use it.
The extension will use this client on Gitea >= 28.2.0 and keep falling
back to `tea` on older servers, so this should be backported to v28.
Co-authored-by: bircni <bircni@icloud.com>
Backport #39807 by @gomitrah
With "Autodetect manual merge" enabled, an empty pull request (one with
no commits of its own, for example opened to discuss a branch) was
closed as manually merged as soon as it was checked. Its head commit is
already an ancestor of the base branch, so the detection took the
"fast-forwarded" path and recorded the head itself as the merge commit,
even though nothing was merged.
Detection now skips a PR whose head commit is its merge base, the same
condition Gitea already uses to show a PR as "already included in the
target branch". Real manual merges are still detected, including when
the base branch and the PR branch are pushed together.
The merge base is refreshed on recheck, so a fast-forward manual merge
whose merge base was already refreshed to the head is not detected
either. This only misses a detection and never closes a PR wrongly;
telling the two apart would need a value stored at PR creation.
Fixes https://github.com/go-gitea/gitea/issues/31947
Co-authored-by: Mitrahsoft <bala.c@mitrahsoft.in>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
Backport #39740 by @Zettat123
Cancelling running schedule runs has not worked since
https://github.com/go-gitea/gitea/pull/35767: callers pass a branch name
like `main`, while schedule runs store the full ref like
`refs/heads/main`. Disabling Actions, archiving the repository or
changing the default branch left them running.
Fixing the ref alone would also cancel them on every push to the default
branch, which GitHub does not do, and whenever the Actions setting is
saved, so those paths now only replace the schedules.
Changing or renaming the default branch deleted the schedules without
registering the new branch's ones
(https://github.com/go-gitea/gitea/pull/28691), so they stopped until
the next push, and the API path kept the old ones. Both now switch the
schedules to the new default branch, since scheduled workflows only run
on the default branch.
Only the push case was verified on GitHub, as its scheduled workflows
have rarely been triggering lately.
Co-authored-by: Zettat123 <zettat123@gmail.com>
Backport #39781 by @SudhanshuMatrix
## What
`parseGitDiffTreeLine` (`services/gitdiff/git_diff_tree.go`) read
`BasePath`/`HeadPath` straight from `git diff-tree --raw` output without
undoing git's C-quoting, unlike its sibling `parseLsTreeLine`
(`modules/git/parse.go`), which already does this with
`strconv.Unquote`.
This fix applies the same unquoting to both paths in the diff-tree
parser.
## Why
With the default `core.quotePath=true`, git C-quotes **any path
containing a non-ASCII byte** — not just tabs/newlines/backslashes. That
means any file with a CJK, Cyrillic, accented-Latin, or emoji name gets
octal-escaped, e.g.:
```
:100644 100644 b6fc4c6... 04fea06... M "\346\227\245\346\234\254\350\252\236.txt"
```
(`日本語.txt`, confirmed against real `git diff-tree --raw` output)
`GetDiffTree` backs the file-tree sidebar on the commit, compare, and
pull request diff pages (`routers/web/repo/commit.go`, `compare.go`,
`pull.go`). Without unquoting, any such file shows its mangled, escaped
name instead of the real one, and the wrong path can throw off
jump-to-file and viewed-file-state behavior that key off the path.
Co-authored-by: Shudhanshu Singh <sudhanshuwriterblc@gmail.com>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
Backport #39747 by @AliceLafox
* Fixes#39746
* Fixes#35505
The click handlers were bound only to the first `.reference-list-menu`
(branches), so clicking a tag did nothing. Bind them to the items of
both lists.
Co-authored-by: Alisa Lafoks <alice@lafox.net>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
Backport #39681 by @silverwind
Gitea changed the `dist.tarball` it advertises for already published
versions twice:
| Gitea | `dist.tarball` path of `@scope/name@1.0.0` |
|---|---|
| 1.27 | `%40scope%2Fname/-/1.0.0/name-1.0.0.tgz` |
| 28.0, https://github.com/go-gitea/gitea/pull/39061 |
`@scope%2Fname/-/1.0.0/name-1.0.0.tgz` |
| 28.1, https://github.com/go-gitea/gitea/pull/39434 |
`@scope/name/-/name-1.0.0.tgz` |
pnpm 11.5.2+ verifies the tarball URLs pinned in its lockfile against
the registry metadata, so frozen installs of lockfiles written against
1.27 fail with `ERR_PNPM_TARBALL_URL_MISMATCH`.
- Versions uploaded before this PR get their 1.27 URL back.
- New versions store their canonical tarball path at upload, so later
URL changes can't reach published versions. The host still follows the
request.
Lockfiles written against 28.0 for scoped packages, or by pnpm 12 with
`@scope:registry` against 28.1, need those pinned `tarball:` entries
removed, as 1.27 lockfiles of the same versions need the other URL.
Signed-off-by: silverwind <me@silverwind.io>
Co-authored-by: silverwind <me@silverwind.io>
Backport #39721 by @bircni
Fixes a few Actions bugs where user input or nondeterminism caused
failures:
- The job log view indexed task steps with the client-supplied cursor
step without a bounds check, so an out-of-range value panicked and
returned a 500.
- Workflow activity type filters (`types:`) were compiled with
`glob.MustCompile`, so an invalid pattern in a workflow file panicked
during event detection. Invalid patterns now simply don't match.
- Listing workflow runs with an unknown `actor` returned a 500; it now
returns 404.
- The v4 artifact `ListArtifacts` response was built by ranging over a
map, so its order changed between calls. It now follows database order.
- The error from marshalling a workflow job when inserting run jobs was
silently ignored.
Co-authored-by: bircni <bircni@icloud.com>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
Backport #39728 by @silverwind
Since https://github.com/go-gitea/gitea/pull/39703, Gitea fails to start
when its gitconfig holds a `gc.reflogExpire` other than `90` (e.g.
`30.days`), because `git config --unset-all` exits 5 when no value
matches. Value patterns were also unanchored regexps, so `90` also
removed `90.days`.
- Match values exactly in `configUnsetAll` and `configAddNonExist`
- Treat "nothing to unset" as success
- Use `--replace-all` in `configSet` so a key with multiple values no
longer fails startup
Co-authored-by: silverwind <me@silverwind.io>
Backport #39706 by @benv666
Fixes#39702
**Root Cause:**
Cancelling a reusable workflow caller wrote it `cancelled` right away,
even while a child was still `cancelling`. When the runner acknowledged,
the caller did not change, so the run was never refreshed and stayed
`cancelling`.
SQLite hid this because the child is cancelled a second time, which
re-aggregates the caller, while MySQL reports no affected rows for that
unchanged update.
**Changes:**
- A caller now takes its status only from its children: it stays
`cancelling` until its last child finishes, and its final status then
refreshes the run.
- Cancelling a run whose jobs are all done only settles the run, which
did not wake the runs waiting for its concurrency group. It now does, so
force-cancelling an already stuck run also frees them.
NOTE: Code was AI-generated, but reviewed and tested by me.
Signed-off-by: BenV <165034+benv666@users.noreply.github.com>
Co-authored-by: BenV <165034+benv666@users.noreply.github.com>
Co-authored-by: Zettat123 <zettat123@gmail.com>
Backport #39703 by @silverwind
Gitea's default `gc.reflogExpire = 90` is parsed by git as
`1990-<month>-<day>`, currently `1990-10-09`, so reachable reflog
entries never expired.
Since git 2.54, auto maintenance runs its reflog-expire task in the
foreground of every push, and its trigger ignores reachability, so busy
repos rerun `git reflog expire --all` on every push without pruning
anything, stalling large repos for over a minute.
- Stop setting `gc.reflogExpire` so git's own defaults apply, and remove
the `90` written by earlier versions
- Treat the legacy `[git.reflog] EXPIRATION` as days, as documented
The next push to each repo prunes the accumulated entries once.
Fixes: https://github.com/go-gitea/gitea/issues/39693
Co-authored-by: silverwind <me@silverwind.io>
Backport https://github.com/go-gitea/gitea/pull/39695
`go.sum` conflicted on older x/net `go.mod` hashes that `release/v28`
still lists. `make tidy` resolves it to the same change as on `main`.
Backport #39498 by @SHIVANSHGARG07
The OIDC discovery document at `/.well-known/openid-configuration`
advertised `id_token` in `response_types_supported`, but
`/login/oauth/authorize` only implements the authorization code flow and
rejects any other response_type with `unsupported_response_type`. This
mismatch caused OIDC client libraries that rely on discovery to attempt
the implicit flow and fail silently.
This removes `id_token` from `response_types_supported` so discovery
matches actual server behavior, and adds an integration test asserting
`response_type=id_token` is rejected consistently.
Manually verified: rebuilt Gitea, registered an OAuth2 app, confirmed
`/.well-known/openid-configuration` no longer lists `id_token`, and
confirmed `/login/oauth/authorize?...&response_type=id_token` still
correctly returns `error=unsupported_response_type`.
Fixes#39482.
<!--
Before submitting:
- Target the `main` branch; release branches are for backports only.
- Use a Conventional Commits title, e.g. `fix(repo): handle empty branch
names`.
- Read the contributing guidelines:
https://github.com/go-gitea/gitea/blob/main/CONTRIBUTING.md
- Documentation changes go to https://gitea.com/gitea/docs
Describe your change below and link any issue it fixes.
-->
Co-authored-by: Shivansh Garg <shivanshgarg587@gmail.com>
Backport #39685 by @GiteaBot
This PR contains the following updates:
| Package | Type | Update | Change |
|---|---|---|---|
| [go](https://go.dev/)
([source](https://redirect.github.com/golang/go)) | toolchain | patch |
`1.27.1` → `1.27.2` |
---
### Configuration
📅 **Schedule**: (UTC)
- Branch creation
- At any time (no schedule defined)
- Automerge
- At any time (no schedule defined)
🚦 **Automerge**: Disabled by config. Please merge this manually once you
are satisfied.
♻ **Rebasing**: Whenever PR is behind base branch, or you tick the
rebase/retry checkbox.
🔕 **Ignore**: Close this PR and you won't be reminded about this update
again.
---
- [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check
this box
---
This PR has been generated by [Mend Renovate
CLI](https://redirect.github.com/renovatebot/renovate).
<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0NC4xMjEuNCIsInVwZGF0ZWRJblZlciI6IjQ0LjEyMS40IiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6WyJkZXBlbmRlbmNpZXMiXX0=-->
Backport #39657 by @bircni
Release notes: revert commits and the commits they revert are now left
out of the git-cliff changelog. A step before git-cliff finds commits
whose subject starts with "revert", reads the PR numbers on their revert
lines, and writes both SHAs to `.cliffignore`.
Snap: since the move from Launchpad to GitHub Actions, every build was
uploaded to `latest/edge`, including the stable-grade build that
`part-gitea-pull.sh` makes for an unreleased tag. Launchpad used to
release those builds to candidate and stable automatically. Without
that, v28.0.0 had to be promoted by hand and v28.1.0 stayed in edge.
Stable-grade snaps now go to `latest/stable` and `latest/candidate`;
main builds still go to edge. Candidate has to be updated too because
the pull script compares against it.
Signed-off-by: bircni <bircni@icloud.com>
Co-authored-by: bircni <bircni@icloud.com>
Backport #39650 by @Kshot3000
Since the Telegram webhook switched to Bot API rich messages
(https://github.com/go-gitea/gitea/pull/38298), a bare newline in
`rich_message.html` is treated as insignificant whitespace, so
multi-line messages — issue and PR bodies, comments, push commit lists —
arrive in Telegram as a single paragraph. This restores the old layout
by converting line breaks (`\n`, `\r\n`, `\r`) to `<br>` in
`createTelegramPayloadHTML`, after sanitizing, covering every Telegram
payload type at once.
Verified: the new `Line breaks are kept in rich messages` test plus the
updated Push/Issue/IssueComment/PullRequest/Review expectations fail on
unpatched code (literal `\n` in the payload) and pass with the fix; the
full `services/webhook` package passes, gofmt/vet clean.
Fixes https://github.com/go-gitea/gitea/issues/39649
---
Tips welcome: PayPal kyleblake0659@gmail.com · BTC
3GnR7TWBXAB3pPztBWpNF4LMNEX5yX8vZK
Co-authored-by: KShot <kshot9000@gmail.com>
Backport #39663 by @nschloe
Since MathML is allowed in markup (#36352, #38034, #39337), a
display-style `<math display="block">` sits flush against the text below
it: it gets no margin of its own, and markup paragraphs have
`margin-top: 0`. Display math rendered by KaTeX gets 16px above and
below.
This adds `math[display="block"]` to the markup block elements that get
`margin-top: 0; margin-bottom: 16px`, like `p`, `pre` and `table`.
To test, view a Markdown file containing
```markdown
Text before.
<math display="block">
<mi>x</mi><mo>=</mo><mn>1</mn>
</math>
Text after.
```
Before, the equation has 16px above and 0px below; after, 16px on both
sides.
Before:
<img width="1544" height="238" alt="before"
src="https://github.com/user-attachments/assets/318238d9-018c-4945-974c-91bd1b282ff2"
/>
After:
<img width="1544" height="283" alt="after"
src="https://github.com/user-attachments/assets/9afde2be-b5ed-4624-a33f-4933e7fae79b"
/>
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-authored-by: Nico Schlömer <nschloe@users.noreply.github.com>
Co-authored-by: silverwind <me@silverwind.io>
Backport #39611 by @Kshot3000
* Fixes#39606
* Fixes#39329
`GetLatestCommitStatusForRepoCommitIDs` built one `OR` condition per
commit SHA. Rendering a commit list of more than ~1000 commits (for
example a large pull request, via `processGitCommits`) therefore failed
on SQLite with `SQL logic error: Expression tree is too large (maximum
depth 1000)`.
The max-index lookup now queries SHAs in chunks of 500 with `IN`, and
the follow-up status fetch runs in chunks of 100 `(index, sha)` pairs,
so the expression depth stays bounded regardless of the commit count.
Results are unchanged.
Verified with a new regression test that calls the function with 2001
SHAs: it fails with the reported error on `main` and passes with this
change. `go test ./models/git/` passes.
—
Fix offered freely; tips welcome: PayPal kyleblake0659@gmail.com · BTC
3GnR7TWBXAB3pPztBWpNF4LMNEX5yX8vZK
Co-authored-by: KShot <kshot9000@gmail.com>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
Backport #39613 by @dziulatex
Fixes#39598
When the base branch has "Block merge if the pull request is outdated"
enabled, an AGit pull request that fell behind could never be unblocked:
merging the base branch into the topic and pushing it again to the same
`refs/for/<branch>/<topic>` left the PR "blocked because it's outdated"
forever.
The outdated block reads the stored `commits_behind`. Pushing a branch
refreshes it for GitHub-flow PRs (`AddTestPullRequestTask`), but the
AGit update path in `services/agit` moved `refs/pull/N/head` without
recomputing it, so the value only changed when the base branch was
pushed, which is the event that makes a PR behind again.
The AGit update path now calls `syncCommitDivergence` in
`UpdateRefForAgit`, the same as AGit PR creation (`NewPullRequest`)
already does.
Signed-off-by: dziulatex <paweldziurasoftware@yahoo.com>
Co-authored-by: dziulatex <38464243+dziulatex@users.noreply.github.com>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
Backport #39612
* Fix#39610
* Regression of #39262
Also, the old code is very fragile: `#branch_target` is from translation
string, so refactored it together
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
Co-authored-by: silverwind <me@silverwind.io>
Backport #39589 by @bircni
When the job emitter itself finishes the last jobs of a called workflow
(e.g. skipped by `if:`), `UpdateRunJob` cascades the caller to done in
the database only. The pass kept the caller unfinished in memory and
nothing re-emitted the run, so jobs that `needs:` the caller stayed
`Pending` and the caller's commit status stayed "In progress".
The pass now reloads such callers so their commit statuses close, and
re-emits the run so their dependents are resolved in the next pass. They
are not resolved in the same pass because their `if:` and `concurrency:`
read the caller from the database, where it is not finished until the
pass writes the children.
* Fixes https://github.com/go-gitea/gitea/issues/39587
* Fixes https://github.com/go-gitea/gitea/issues/39586
Co-authored-by: bircni <bircni@icloud.com>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
Backport https://github.com/go-gitea/gitea/pull/39603 by @silverwind
Uses `FetchRemoteCommit`, as v28 has no `FetchRemoteTempCommit`, so no
`--no-write-fetch-head` is involved.
Reverts the backport https://github.com/go-gitea/gitea/pull/39585 before
v28.0.1 ships. The change stays on main for v29.
gitea-runner v4.1.0 recognizes a rejected registration only by the old
`Unknown`-coded `rpc error: code = Unauthenticated desc = unregistered
runner` error. With the new `Unauthenticated` reply, an ephemeral runner
keeps its spent registration file and fails on every restart instead of
registering again. The runner fix is in
https://gitea.com/gitea/runner/pulls/1287, so a patch release shouldn't
change runner behavior before that fix has shipped.
Written by Claude Code.
Backport #39436 by @breken-ai
The `org` render meta is lower-cased (`Repository.composeCommonMetas`
sets `metas["org"] = strings.ToLower(repo.OwnerName)`), but
`mentionProcessor` compares it with the org part of the mention exactly
as typed, while the team part is lower-cased before its lookup. So in a
repository of the org `MyOrg`, `@MyOrg/developers` stays plain text,
although `ResolveIssueMentionsByVisibility` lower-cases the name and
still notifies that team.
This compares the org part case-insensitively and adds a render test for
team mentions.
The code is the same on `release/v1.27`, so it could be backported.
### Verification
- `go test ./modules/markup/ -run TestRender_TeamMention -count=1`: the
`@Org1/Developers` case renders as plain text on current main and as the
team link with this change; `go test ./modules/markup/...` passes.
- `golangci-lint run ./modules/markup/` (v2.13.2): 0 issues.
### AI assistance
This contribution was prepared with AI assistance. The behavior, the
metas and mention-resolution code paths, the patch and the test were
reviewed manually.
> Built by breken, your AI support engineer - breken.ai - this one's on
us.
Co-authored-by: breken <support@brekfuz.com>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
Backport #39577Fixes#39572
The shared user cards template calls the User-only `IsTypeBot` method.
The profile organizations tab passed `*organization.Organization` values
to that template, so `/{username}?tab=organizations` returned a 500
error.
Organizations are now converted to Users before rendering.
Co-authored-by: Zettat123 <zettat123@gmail.com>
Backport #39551 by @bircni
Allow bot accounts to use the API when a legacy password-change flag is
set, since bots cannot complete the interactive password-change flow.
Preserve password-change enforcement for human accounts and restrictions
for inactive or prohibited accounts.
Fix https://github.com/go-gitea/gitea/issues/39542
Co-authored-by: bircni <bircni@icloud.com>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
Co-authored-by: silverwind <me@silverwind.io>
Backport #39546 by @silverwind
`pull_request_review` runs on fork PRs, which includes all backport PRs,
get a read-only token and no secrets, so giteabot cannot write lgtm
labels and statuses there. A no-op `giteabot-review` workflow now
triggers giteabot through `workflow_run`, which gets both. This allows
retiring the legacy fly.io webhook bot.
Part of https://github.com/go-gitea/giteabot/issues/15
---
This PR was written by Claude.
Co-authored-by: silverwind <me@silverwind.io>
Backport #39512
MSSQL's default READ COMMITTED makes reads wait on writers, so the
runner pickup deadlocks with concurrent claims, flaking
`TestCreateTaskForRunnerConcurrentClaim`.
- Enable `READ_COMMITTED_SNAPSHOT` on MSSQL so it reads like PostgreSQL
and MySQL
- Read the pickup cursor before claiming, a lost claim could skip
waiting jobs
- Add tests that fail without consistent READ COMMITTED
Performance: Writes on MSSQL now also store the previous row version in
tempdb, the same versioning cost PostgreSQL and MySQL always pay, and
Azure SQL enables it by default. Reads no longer block on writers, and a
32-runner pickup stress test ran 2.5x faster with it.
Signed-off-by: wxiaoguang <wxiaoguang@gmail.com>
Co-authored-by: silverwind <me@silverwind.io>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
Backport #39491 by @Copilot
On Linux and ChromeOS, Chromium resolves the `math` font family to Latin
Modern Math, which neither installs, so MathML renders with a text font
and brackets and large operators don't stretch, see
https://issues.chromium.org/issues/40069293. The new `--fonts-math`
variable keeps `math` first, so browsers that always resolve it keep
their font. Only Chromium falls through to the math fonts Linux and
ChromeOS install by default:
- `STIX Two Math`: Fedora, and `fonts-stix` on Ubuntu 26.04
- `DejaVu Math TeX Gyre`: Debian 13 and openSUSE
- `Noto Sans Math`: Fedora and ChromeOS, last because Debian and Ubuntu
ship an older version without a `MATH` table
Math fonts also have smaller x-heights than UI fonts, so MathML rendered
smaller than KaTeX and the surrounding text in every browser, see
https://github.com/w3c/mathml-core/issues/41. `font-size-adjust:
ex-height 0.52` scales whichever math font is used to KaTeX's x-height.
KaTeX output is unchanged.
Fixes: https://github.com/go-gitea/gitea/issues/39489

Co-authored-by: Copilot <198982749+Copilot@users.noreply.github.com>
Co-authored-by: bircni <75789103+bircni@users.noreply.github.com>
Co-authored-by: silverwind <me@silverwind.io>
Backport #39506 by @silverwind
MariaDB 11.6.2+ defaults `innodb_snapshot_isolation` to `ON`, which
fails REPEATABLE READ transactions with error 1020 when a row they write
changed after their first read. Gitea's background work like push
processing writes the same rows, so merges, issue closes and workflow
runs fail sporadically.
- Use READ COMMITTED on MySQL and MariaDB, like PostgreSQL and MSSQL
- Update xorm to v1.4.3
Replaces: https://github.com/go-gitea/gitea/pull/39494
Fixes: https://github.com/go-gitea/gitea/issues/39492
Signed-off-by: silverwind <me@silverwind.io>
Co-authored-by: silverwind <me@silverwind.io>
Backport #39531 by @CalvinTjoaquinn
## What
`BatchChecker.CheckPath` uses `time.After` inside its read loop. This
replaces it with a `time.Timer` that is stopped once the attribute
arrives.
## Why
```go
for i := 0; i < c.attributesNum; i++ {
select {
case <-time.After(5 * time.Second):
// there is no "hang" problem now. This code is just used to catch other potential problems.
return nil, reportTimeout()
case attr, ok := <-c.stdOut.ReadAttribute():
```
`time.After` has no way to be cancelled, so the timer it allocates stays
in the runtime timer heap for the full five seconds whichever case the
`select` picks. On the normal path the attribute arrives immediately and
the timer is abandoned while still pending.
The multiplier is what makes it worth changing rather than leaving as
noise. The loop runs `len(LinguistAttributes)` times, which is six, and
`CheckPath` is called once per file:
```go
// modules/git/languagestats/language_stats_get.go:95, in the loop over repository files
attrs, err := checker.CheckPath(f.Name())
// services/gitdiff/gitdiff.go:1408, in the loop over diff files
attrs, err := checker.CheckPath(diffFile.Name)
```
So a language-stats pass over a repository of N files holds up to 6N
pending five-second timers, and a large diff does the same per file. By
the comment's own account that timeout path does not fire in practice,
so every one of those timers is allocated and held for nothing.
## The change
`time.NewTimer` plus `Stop` on the paths that win, which keeps the
behaviour identical: each iteration still gets its own five-second
budget, and the timer is released as soon as the attribute or the
context arrives rather than five seconds later.
If you would rather have a single budget for the whole read, one timer
hoisted above the loop with `defer timeout.Stop()` is simpler and
stricter, since six attributes from an already running `git check-attr`
should arrive together. That changes the semantics from per-attribute to
per-call, so I left it alone and am happy to switch if you prefer it.
## Verification
```
go build ./modules/git/...
go vet ./modules/git/attribute/
go test -count=1 ./modules/git/attribute/ # 11 tests, 0 failures
golangci-lint run ./modules/git/attribute/...
gofmt -l modules/git/attribute/ # no output
```
The package's own `CheckPath` tests cover the success path, the
closed-stdout path and the context-cancelled path, which are the three
`select` arms touched here.
Found with a small AST pass over the tree looking for `time.After`
inside loop bodies. `staticcheck`'s SA1015 covers `time.Tick` and says
nothing about this shape, so no linter in the current set reports it. Of
the nine other hits in the tree the rest look deliberate or harmless,
and `modules/queue/workergroup.go` already guards against exactly this
by only creating a debounce timer when none is pending, so I only
changed this one.
<sub>Disclosure per the AI Contribution Policy: I used an AI tool to
help find this and to draft the description. The counts above are
`len(LinguistAttributes)` and the two call sites cited, so they can be
checked directly.</sub>
Signed-off-by: Calvin Tjoaquinn <calvintjoa23@gmail.com>
Co-authored-by: Calvin Tjoaquinn <66313400+CalvinTjoaquinn@users.noreply.github.com>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
Backport #39508 by @perfectra1n
Commit status list orders only by `created_unix`/`updated_unix`, which
have 1-second resolution while CI often posts many statuses per second.
With LIMIT/OFFSET paging, databases (e.g. PostgreSQL using a Sort plan)
may order tied rows differently per page, so `GET
/repos/{owner}/{repo}/commits/{ref}/statuses` returns some statuses
twice and never returns others.
This became visible after https://github.com/go-gitea/gitea/pull/36521
made requests without `page` paginated. Clients like Renovate that page
until `X-Total-Count` can miss a context's newest status and see a stale
`pending`, blocking automerge.
Fix: add `index` (unique per commit) as a tiebreaker to the
timestamp-based orders.
Co-authored-by: Jon Fuller <jonfuller2012@gmail.com>
Co-authored-by: silverwind <me@silverwind.io>
Backport #38942 by @Harsh-128
Lets users approve an OAuth2 scope change on an existing grant instead
of failing with `a grant exists with different scope`. Fixes
https://github.com/go-gitea/gitea/issues/38940.
- Approving a different scope updates the existing grant. Issued tokens
follow immediately, since their scope is read from the grant.
- Confidential and trusted apps show the consent page when the scope set
changes, instead of silently reusing the old grant.
- An omitted `scope` reuses the existing grant's scope, like GitHub.
- The consent page lists newly added scopes.
<img width="500" alt="consent page with new scopes"
src="https://github.com/user-attachments/assets/40282353-32fe-4d87-9929-08aabbab32f1"
/>
Co-authored-by: Harsh Sharma <harshee2000@gmail.com>
Co-authored-by: bircni <bircni@icloud.com>
Co-authored-by: silverwind <me@silverwind.io>
Backport #39434 by @silverwind
Aligns the npm registry with what npm, pnpm and yarn expect:
1. Raise the publish body cap from
https://github.com/go-gitea/gitea/pull/37890 to 256 MiB like npmjs,
larger bodies get 413
2. Pick the tarball attachment by name, `npm publish --provenance`
failed at random
3. Store and serve `libc`, so mismatched glibc/musl optional binaries
are skipped
4. Treat root `*.gyp` files as an install script, like npm does
5. Always serve a `latest` dist-tag, yarn and pnpm fail without it
6. Take top-level metadata from `latest` and drop the per-version readme
7. Serve tarballs at the npmjs path `/<name>/-/<file>`, former URLs keep
working
8. Add ETag revalidation for metadata, `npm ping` and `npm whoami`
Tested with npm 12.1, pnpm 12.4, yarn 1.22 and yarn 4.18.
Co-authored-by: silverwind <me@silverwind.io>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
Backport #39501 by @silverwind
Several handlers skipped checks that their sibling routes or settings
already enforce. This brings them in line.
- Push mirror API honors `DISABLE_NEW_PUSH` and checks the caller's
permission
- Media API serves small files with the usual content headers
- Issue attachment API ignores comment attachments
- Push-to-create respects `FORCE_PRIVATE`
- Profile feeds and follow actions respect `ENABLE_FEED` and owner
visibility
- Tag delete route refuses release tags
- Refresh token grant only accepts refresh tokens
- Gitea migrations bound the source's page size
Co-authored-by: silverwind <me@silverwind.io>
Co-authored-by: bircni <bircni@icloud.com>
description:Track a Gitea release (for release managers).
title:"Release Gitea "
body:
- type:markdown
attributes:
value:|
Follow the [release management guide](https://github.com/go-gitea/gitea/blob/main/docs/release-management.md).
Set the issue title and milestone to the version being released. Replace the examples below and mark inapplicable tasks as such.
CI signs the tag, generates release notes, and publishes binaries and containers. Track verification here; no manual changelog PR or release upload is needed.
- type:input
id:version
attributes:
label:Version
placeholder:"28.0.1"
validations:
required:true
- type:input
id:branch
attributes:
label:Release branch
placeholder:"release/v28"
validations:
required:true
- type:textarea
id:checklist
attributes:
label:Release checklist
description:Keep workflow runs, release URLs, and follow-up PRs alongside the relevant tasks.
value:|
### Preparation
- [ ] Resolve release blockers and confirm milestone issues and PRs are resolved or deferred.
- [ ] Confirm required backports are merged and release branch CI passes.
- [ ] For a new release line, create the release branch and tag its fork point on main with the next version's -dev tag.
### Release
- [ ] Run https://github.com/go-gitea/gitea/actions/workflows/release-create-tag.yml on the release branch with the selected version and obtain maintainer approval.
- [ ] Confirm https://github.com/go-gitea/gitea/actions/workflows/release-tag-version.yml succeeds for the new tag (binaries and containers).
- [ ] Verify the public GitHub release, generated notes, binary attachments, and signatures at https://github.com/go-gitea/gitea/releases.
- [ ] Verify binaries and signatures at https://dl.gitea.com/gitea/ for this version.
- [ ] Verify versioned regular and rootless images on Docker Hub and GHCR, and smoke-test the release.
### Follow-up
- [ ] Verify the automated https://dl.gitea.com/gitea/version.json update, where applicable to this release line.
- [ ] Verify automated Helm chart and Terraform provider update PRs and follow up if needed.
- [ ] Check Homebrew and Snap availability; record any outstanding packaging follow-up.
- [ ] Confirm documentation reflects the release, where applicable.
- [ ] Confirm and merge the release blog post, if planned: https://gitea.com/gitea/blog.
- [ ] Announce the release in Discord #announcements.
validations:
required:true
- type:textarea
id:notes
attributes:
label:Blockers and notes
description:Link outstanding work or release-specific checks using full URLs. Do not include undisclosed security details.
@@ -169,7 +169,7 @@ In the PR title, describe the problem you are fixing, not how you are fixing it.
Use the first comment as a summary of your PR. \
In the PR summary, you can describe exactly how you are fixing this problem.
PR titles must follow the [Conventional Commits](https://www.conventionalcommits.org/) format, because PRs are squash-merged and the PR title becomes the resulting commit message:
PR titles must follow the [Conventional Commits](https://www.conventionalcommits.org/) format, because PRs are squash-merged and the PR title becomes the resulting commit message and release notes entry:
@@ -120,7 +120,7 @@ See [app.example.ini](https://github.com/go-gitea/gitea/blob/main/custom/conf/ap
**Where can I find the security patches?**
In the [release log](https://github.com/go-gitea/gitea/releases) or the [change log](https://github.com/go-gitea/gitea/blob/main/CHANGELOG.md), search for the keyword `SECURITY` to find the security patches.
Check the [release notes](https://github.com/go-gitea/gitea/releases) and [security advisories](https://github.com/go-gitea/gitea/security/advisories) for security patches.
(more FAQs are listed in [FAQ documentation](https://docs.gitea.com/help/faq))
"licenseText":"Copyright (c) 2009, 2010, 2013-2016 by the Brotli Authors.\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n"
"licenseText":"Copyright (c) 2009 The 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"
;; Egress mode toggles between strictness of outgoing requests:
;; Lax requires addresses to be allowed only if they are in private ranges, it allows all public ones
;; Lax requires non-public targets (private, loopback, link-local, CGNAT and special-use ranges) to be allowed, it allows all public ones
;; Strict requires an explicit allow of all addresses
; EGRESS_MODE = lax
;;
@@ -551,10 +551,12 @@ INTERNAL_TOKEN =
;; a bracketed set of ports and ranges, | separated: *.mydomain.com:[80|443|3000-3010]
;; all ports: *.mydomain.com:*
;; A portless entry covers all ports in Lax mode, only 80 and 443 in Strict mode
;; Port specs apply only where the list is consulted: in Lax mode that is private, loopback and CGNAT
;; targets alone, public targets are allowed on every port whatever the list says. In Strict mode every
;; Port specs apply only where the list is consulted: in Lax mode that is non-public targets alone,
;; public targets are allowed on every port whatever the list says. In Strict mode every
;; target is checked, so ports restrict public hosts too.
;; Reserved addresses like link-local and cloud metadata are denied
;; Non-public targets need an IP or built-in entry, a host name entry alone never covers them.
;; Reserved addresses (the IPv4-embedding NAT64, Teredo and 6to4 ranges, this-network, multicast and
;; broadcast) are denied whatever the list says. To reach them configure an HTTP proxy
;; This list is enforced on direct connections only. When an HTTP proxy is configured, restricting the proxied target is the proxy server's responsibility.
@@ -74,15 +74,13 @@ Changes to Gitea must be reviewed before they are accepted, including changes fr
We require two maintainer approvals for every PR. When that is satisfied, your PR gets the `lgtm/done` label. After that, you mainly fix merge conflicts and respond to or implement maintainer requests; maintainers drive getting the PR merged.
If a PR has `lgtm/done`, no open discussions, and no merge conflicts, any maintainer may add `reviewed/wait-merge`. That puts the PR in the merge queue. PRs are merged from the queue in the order of this list:
If a PR has `lgtm/done`, no open discussions, and no merge conflicts, a merger rewrites its title and description into the final [commit message](#commit-messages) and clicks **Merge when ready**. That adds the PR to the [merge queue](https://github.com/go-gitea/gitea/queue/main), which tests it on top of the latest `main` and the PRs ahead of it, and merges it once CI passes. Edits to the title and description no longer reach the commit once the queue starts building the PR, so make them before queueing.
Gitea uses its own tool, <https://github.com/go-gitea/gitea/blob/main/.github/workflows/giteabot.yml>, to automate parts of the review process. The backporter:
Gitea uses its own tool, <https://github.com/go-gitea/gitea/blob/main/.github/workflows/giteabot.yml>, to automate parts of the review process. It:
- Counts maintainer approvals and sets the `lgtm/*` labels and the `giteabot/lgtm` status.
- Takes a PR out of the merge queue when it loses its approval.
- Creates a backport PR when needed after the initial PR merges.
- Removes the PR from the merge queue after it merges.
- Keeps the oldest branch in the merge queue up to date with merges.
### Final call
@@ -164,7 +162,7 @@ Any account with write access (including bots and TOC members) **must** use [2FA
Mergers are the maintainers who carry out the final merge of approved PRs. Their responsibilities, described throughout this guide, are:
-Merging PRs from the [merge queue](#getting-prs-merged) in order, once a PR has `lgtm/done`, no open discussions, and no merge conflicts.
-Adding PRs to the [merge queue](#getting-prs-merged) once a PR has `lgtm/done`, no open discussions, and no merge conflicts.
- Rewriting the PR title and description prior to the merge, making the [commit message](#commit-messages) clear.\
In particular, mergers should edit the PR description.\
Mergers should **not** edit the actual commit message except to remove unnecessary information. Because of that, even if users are looking at the PR, they can understand what changed.
@@ -8,10 +8,9 @@ This document describes the release cycle, backports, versioning, and the releas
We backport PRs given the following circumstances:
1.Feature freeze is active, but `<version>-rc0` has not been released yet. Here, we backport as much as possible. <!-- TODO: Is that our definition with the new backport bot? -->
2.`rc0` has been released. Here, we only backport bug- and security-fixes, and small enhancements. Large PRs such as refactors are not backported anymore. <!-- TODO: Is that our definition with the new backport bot? -->
3. We never backport new features.
4. We never backport breaking changes except when
1.We backport bug- and security-fixes and small enhancements. Large changes such as refactors are not backported.
2.We never backport new features.
3. We never backport breaking changes except when
1. The breaking change has no effect on the vast majority of users
2. The component triggering the breaking change is marked as experimental
@@ -25,6 +24,8 @@ Now, that's not a requirement anymore as our [backport bot](https://github.com/G
The `backport/manual` label signifies either that you want to backport the change yourself, or that there were conflicts when backporting, thus you **must** do it yourself.
The bot labels open PRs targeting `main` that have a `backport/<version>` label with `backport/conflict-free` when they would cherry-pick onto the latest release branch without conflicts.
### Format of backport PRs
The title of backport PRs should be
@@ -53,7 +54,6 @@ We use a release schedule so work, stabilization, and releases stay predictable.
### Cadence
- Aim for a major release about every three or four months.
- Roughly two or three months of general development, then about one month of testing and polish called the **release freeze**.
- *Starting with v1.26 the release cycle will be more predictable and follow a more regular schedule.*
### Release schedule
@@ -65,16 +65,6 @@ We will try to publish a new major version every three months:
- v1.28.0 in September 2026
- v1.29.0 in December 2026
#### How is the release handled?
- The release manager will tag the release candidate (e.g. `v1.26.0-rc0`) and publish it for testing in the **first week of the release month**.
- If there are no major issues, the release manager will check with the other maintainers and then tag the final release (e.g. `v1.26.0`) in the **one or two weeks following the release candidate**.
### Feature freeze
- Merge feature PRs before the freeze when you can.
- Feature PRs still open at the freeze move to the next milestone. Watch Discord for the freeze announcement.
- During the freeze, a **release branch** takes fixes backported from `main`. Release candidates ship for testing; the final release for that line is maintained from that branch.
### Patch releases
During a cycle we may ship patch releases for an older line. For example, if the latest release is v1.2, we can still publish v1.1.1 after v1.1.0.
@@ -99,17 +89,13 @@ be reviewed by two maintainers and must pass the automatic tests.
## Releasing Gitea
- Let MAJOR, MINOR and PATCH be Major, Minor and Patch version numbers, PATCH should be rc1, rc2, 0, 1, ...... MAJOR.MINOR will be kept the same as milestones on github or gitea in future.
- Before releasing, confirm all the version's milestone issues or PRs has been resolved. Then discuss the release on Discord channel #maintainers and get agreed with almost all the owners and mergers. Or you can declare the version and if nobody is against it in about several hours.
-If this is a big version first you have to create PR for changelog on branch `main` with PRs with label `changelog` and after it has been merged do following steps:
-Create `-dev` tag as `git tag -s -F release.notes vMAJOR.MINOR.0-dev` and push the tag as `git push origin vMAJOR.MINOR.0-dev`.
-When CI has finished building tag then you have to create a new branch named `release/vMAJOR.MINOR`
-If it is bugfix version create PR for changelog on branch `release/vMAJOR.MINOR` and wait till it is reviewed and merged.
- Add a tag as `git tag -s -F release.notes vMAJOR.MINOR.PATCH`, release.notes file could be a temporary file to only include the changelog this version which you added to `CHANGELOG.md`.
- And then push the tag as `git push origin vMAJOR.MINOR.$`. CI will automatically create a release and upload all the compiled binary. (But currently it doesn't add the release notes automatically. Maybe we should fix that.)
- If needed send a frontport PR for the changelog to branch `main` and update the version in `docs/config.yaml` to refer to the new version.
- Send PR to [blog repository](https://gitea.com/gitea/blog) announcing the release.
Track each release using the [release issue template](https://github.com/go-gitea/gitea/issues/new?template=release.yaml).
-Before releasing, confirm all the version's milestone issues or PRs have been resolved. Then discuss the release on Discord channel#maintainers and get agreed with almost all the owners and mergers. Or you can declare the version and if nobody is against it in about several hours.
-When creating a release branch, tag its fork point on `main` as the next version's `-dev` tag, e.g. `v30.0.0-dev` for `release/v29`.
-In the GitHub Actions tab, open the `release-create-tag` workflow, click "Run workflow", select the release branch and enter a version such as `28.0.1`. After maintainer approval, it pushes a signed tag and CI publishes the release with generated notes.
-Optionally send a PR to the [blog repository](https://gitea.com/gitea/blog) announcing the release.
- Verify all release assets were correctly published through CI on dl.gitea.com and GitHub releases. Once ACKed:
-bump the version of https://dl.gitea.com/gitea/version.json
-verify the automated update of https://dl.gitea.com/gitea/version.json, where applicable to the release line
- merge the blog post PR
- announce the release in discord `#announcements`
WorkflowIDstring`xorm:"index"`// the name of workflow file
Indexint64`xorm:"index unique(repo_index)"`// a unique number for each run of a repository
WorkflowIDstring`xorm:"index"`// the name of workflow file
Indexint64`xorm:"unique(repo_index)"`// a unique number for each run of a repository
TriggerUserIDint64`xorm:"index"`
TriggerUser*user_model.User`xorm:"-"`
ScheduleIDint64
Refstring`xorm:"index"`// the commit/tag/… that caused the run
IsRefDeletedbool`xorm:"-"`
CommitSHAstring
Refstring`xorm:"index"`// the commit/tag/… that caused the run
IsRefDeletedbool`xorm:"-"`
CommitSHAstring`xorm:"index"`
IsForkPullRequestbool// If this is triggered by a PR from a forked repository or an untrusted user, we need to check if it is approved and limit permissions when running the workflow.
NeedApprovalbool// may need approval if it's a fork pull request
returnbuilder.Eq{"owner_id":0}.Or(builder.Expr("EXISTS (SELECT 1 FROM repository WHERE repository.id = action_scoped_workflow_source.source_repo_id AND repository.owner_id = action_scoped_workflow_source.owner_id)"))
}
// GetEffectiveScopedWorkflowSources returns the scoped-workflow sources effective for a repo owned by repoOwnerID:
// the owner's own sources plus instance-level (owner_id=0) sources.
{OwnerID:3,SourceRepoID:300,WorkflowConfigs:map[string]*ScopedWorkflowConfig{"c.yml":{Required:true,Patterns:[]string{"p"}}}},// a different owner's source
ctx,cancel:=context.WithTimeout(ctx,5*time.Second)// ALTER waits for all other connections to close
defercancel()
if_,err:=engine.Context(ctx).Exec("IF (SELECT is_read_committed_snapshot_on FROM sys.databases WHERE database_id = DB_ID()) = 0 ALTER DATABASE CURRENT SET READ_COMMITTED_SNAPSHOT ON");err!=nil{
log.Error("Unable to set READ_COMMITTED_SNAPSHOT=ON: %v",err)
// if the review is approved or rejected, it should not be shown in the review requested list
And(builder.NotExists(builder.Select("1").From("review as r").
Where(builder.Expr("r.issue_id = review.issue_id AND r.reviewer_id = review.reviewer_id AND r.reviewer_team_id = review.reviewer_team_id AND r.id > review.id").
// Get latest review of each reviewer, sorted in order they were made. Joined because MySQL scans all reviews for "id IN (subquery)", xorm aliases the subquery "review".
// updateReviewerOfficial keeps the official flag only on the reviewer's latest approval, rejection or review request, and only if the reviewer is official
iferr:=sess.SQL("SELECT * FROM review WHERE issue_id = ? AND reviewer_team_id > 0 AND type = ?",issue.ID,ReviewTypeRequest).Find(&teamReviewRequests);err!=nil{
assert.NoError(t,repo_model.WatchRepoWithOptions(t.Context(),user,repo,repo_model.WatchOptions{Mode:repo_model.WatchModeNormal,WatchPullRequests:true}))// custom watches were stored like this before WatchModeCustom
// "_" shouldn't appear in domain but can appear in hostname, since we can't stop site admins from doing so, just accept it
"root@local_host":true,
"root@localhost":true,
"root@LOCALHOST":true,
"user@[192.168.1.2]":true,
"user@[IPv6:FFff::1]":true,
"abc@gmail.com":true,
"abc@gmail.com.":false,
"abc@gmail.com-":false,
"abc@gmail.com\n":false,
"abc@gmail..com":false,
"abc@gmail com":false,
"abc@gmail*com":false,
"Foo <foo@bar.com>":false,
"abc@gmail.com (x)":false,
"jürgen@example.com":false,
"a@foo_bar.com":false,
"jürgen@example.com":false,// utf8 address is not supported yet
}
fortc,isValid:=rangecases{
t.Run(tc,func(t*testing.T){
Some files were not shown because too many files have changed in this diff
Show More
Reference in New Issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.