Purpose:
1. Make the whole code base have unified "item" layout
2. Clarify our "list" styles: "flex-relaxed-list", "flex-divided-list"
3. Prepare to replace legacy "ui relaxed list"
* https://github.com/go-gitea/gitea/pull/37445#discussion_r3144458865
4. Prepare for refactoring the "pull merge box", it needs the
"flex-divided-list"
* related to "Refactor pull request view (*)" like #37451
5. Fix legacy abuses of "flex-list", e.g.: repo home sidebar
When running `gitea dump` with output routed to stdout (--file -),
deprecation warnings from loadAvatarsFrom were written to stdout,
corrupting the archive stream.
Root cause: PrepareConsoleLoggerLevel (called in app.Before) sets up a
console logger via SetConsoleLogger, which used WriterConsoleOption{}
defaulting Stderr to false (i.e. stdout). This logger is installed
before the dump subcommand can redirect logging to stderr in runDump.
Fix: use WriterConsoleOption{Stderr: true} in SetConsoleLogger so all
early CLI diagnostic output goes to stderr from the start. This is
correct for all subcommands — diagnostic/log output should never pollute
stdout.
---------
Signed-off-by: wxiaoguang <wxiaoguang@gmail.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
Co-authored-by: Nicolas <bircni@icloud.com>
After the Webpack-to-Vite migration (#37002), mCaptcha stopped working
entirely on the registration page, throwing an error:
`TypeError: setting getter-only property "INPUT_NAME"`
This fix stops trying to mutate the read-only INPUT_NAME export. Instead
it probes for the Widget constructor at module.default (direct) or
module.default.default (CJS-wrapped), constructs the widget, and then
renames the hidden input element it creates to m-captcha-response which
is the field name Gitea's backend reads from the submitted form.
Generative AI was used to help with making this PR.
---------
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
Co-authored-by: Giteabot <teabot@gitea.io>
Drops `github.com/olivere/elastic/v7` (unmaintained) and replaces it
with a small in-house wrapper that speaks the Elasticsearch REST API
directly via `net/http`. The subset used by Gitea (`_cluster/health`,
`_bulk`, `_doc`, `_delete_by_query`, `_refresh`, `_search`, `HEAD`/`PUT`
index) is stable across the targeted servers, so no client library is
needed.
**Targets tested**
- Elasticsearch 7, 8, 9
- OpenSearch 1, 2, 3
**Why not `go-elasticsearch`?**
The official client enforces an `X-Elastic-Product` server-identity
check that OpenSearch deliberately fails, which would force shipping a
transport shim to defeat it. Going direct over `net/http` removes that
fight along with several MB of transitive deps (`elastic-transport-go`,
`go.opentelemetry.io/otel{,/metric,/trace}`, `auto/sdk`, `easyjson`,
`intern`, `logr`, `stdr`).
Replaces: #30755
Fixes: https://github.com/go-gitea/gitea/issues/30752
---
This PR was written with the help of Claude Opus 4.7
---------
Co-authored-by: Claude (Opus 4.7) <noreply@anthropic.com>
Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
1. Make the content area stretch the box, enabling text selection to
start over empty space.
2. Disable linter for markdown, it can never produce lint errors, this
hides the unnecessary lint gutter on markdown files.
3. Verified all languages linter enablement, all accurate.
4. Refactor `getLinterExtension` to not rely on file extensions.
5. Include jsonc/json5 extensions in regex.
---
This PR was written with the help of Claude Opus 4.7
---------
Co-authored-by: Claude (Opus 4.7) <noreply@anthropic.com>
Co-authored-by: Nicolas <bircni@icloud.com>
Clean up legacy copied&pasted code, introduce the unique "database
connection" function. Move migration testing helper function
PrepareTestEnv to a separate package.
By the way, remove "shadow connection secrets" tricks: showing
connection string on UI is useless
---------
Co-authored-by: Nicolas <bircni@icloud.com>
## Summary
This PR adds support for updating pull mirror authentication via the
repository edit API and UI.
It introduces new mirror authentication fields in _EditRepoOption_,
updates the API logic to safely handle partial credential updates, and
fixes the web settings flow so that the existing remote username is
preserved when only the password is changed.
### What changed
- added _auth_username_, _auth_password_, and _auth_token_ to
EditRepoOption
- updated the repository edit API to apply mirror auth changes via
_updateMirror_
- preserved existing username/password when only part of the auth
payload is provided
- used oauth2 as the default username when _auth_token_ is provided
- kept stored mirror URLs sanitized in DB and API responses
- updated Swagger schema for the new API fields
- added API integration tests for password-only and token-only updates
- added a web settings test to ensure username preservation on partial
updates
## Why
Some use cases require automated synchronization of pull mirrors, for
example in CI/CD pipelines or integrations with external systems.
At the same time, many organizations enforce security policies that
require periodic token rotation (e.g., monthly).
Currently, mirror credentials can only be updated via the UI, which
makes automation difficult.
## This change enables:
- automated token rotation
- avoiding manual updates via the UI
- easier integration with secret management systems
## Testing
- added integration coverage for mirror auth updates via _PATCH
/api/v1/repos/{owner}/{repo}_
- added web settings tests for password-only updates preserving the
existing username
## Result
Ability to automate auth update
<img width="2400" height="1245" alt="1"
src="https://github.com/user-attachments/assets/67fd5cca-9cb3-4536-b0e2-4d09b8ebff0f"
/>
<img width="962" height="932" alt="image"
src="https://github.com/user-attachments/assets/5d548f5d-aadf-4807-ba52-9c29df93a4cc"
/>
Generative AI was used to help with making this PR.
##
1. only trigger docker-dryrun arm64&riscv64 when dockerfile changes
2. de-duplicate "contents: read" permission for most workflows
3. merge various "lint-*" jobs into one job
4. add missing lint targets to the "lint" (all) target
1. Rename CompareInfo.MergeBase to CompareBase, it is not merge base
2. Remove unused template variables `ctx.Data["Username"]` and
`ctx.Data["Reponame"]`
3. Decouple some template variable accesses, use typed struct
---------
Co-authored-by: Nicolas <bircni@icloud.com>
Add a build-time conversion step that transforms the existing Swagger
2.0 spec into an OpenAPI 3.0 spec. The OAS3 spec is served alongside the
existing Swagger 2.0 spec, enabling API clients that require OAS3 to
generate code directly from Gitea's API.
This is not to be an answer to how gitea handles OAS3 long term,
but a way to use what we have to move a step forward.
---------
Signed-off-by: wxiaoguang <wxiaoguang@gmail.com>
Co-authored-by: Claude (Opus 4.7) <noreply@anthropic.com>
Co-authored-by: silverwind <me@silverwind.io>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
Avoid per-item DB queries in ListRuns, ListJobs, and ListActionTasks by
batch-loading trigger users, repositories, and task attributes before
the conversion loop. Remove ReferencesGitRepo from the /actions route
group since no task/run endpoints use it.
Added tests for these endpoints as well.
---------
Signed-off-by: wxiaoguang <wxiaoguang@gmail.com>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
Co-authored-by: silverwind <me@silverwind.io>
Co-authored-by: Claude (Opus 4.7) <noreply@anthropic.com>
Adds a new `DEFAULT_TITLE_SOURCE` option under
`[repository.pull-request]` with three values:
- `first-commit` (default): uses the oldest commit summary, current
behavior since v1.26
- `auto`: normalizes branch name as title for multi-commit PRs (just
like GitHub), use commit summary for single-commit PRs
Closes: #37463
Co-authored-by: silverwind <me@silverwind.io>
Co-authored-by: Claude (Opus 4.7) <noreply@anthropic.com>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
Co-authored-by: Giteabot <teabot@gitea.io>
Co-authored-by: Nicolas <bircni@icloud.com>
This fixes the scheduled action panic when an event payload is JSON
`null` by initializing the payload map before adding `schedule`. It also
adds regression coverage for the null-payload case.
Fixes#37447.
Testing:
- `go test -tags 'sqlite sqlite_unlock_notify' ./services/actions -run
'^TestWithScheduleInEventPayload$' -count=1`
- Local note: this agent ran the command as root with a temporary
`GITEA_TEST_CONF=custom/conf/app-test-root.ini` file that only set
`I_AM_BEING_UNSAFE_RUNNING_AS_ROOT = true`.
Authorship: cyphercodes; AI assistance disclosed: Hermes Agent
(GPT-5.5).
---------
Co-authored-by: cyphercodes <cyphercodes@users.noreply.github.com>
Co-authored-by: Hermes Agent (GPT-5.5) <hermes-agent@users.noreply.github.com>
Co-authored-by: Nicolas <bircni@icloud.com>
Co-authored-by: silverwind <me@silverwind.io>
Co-authored-by: Claude (Opus 4.7) <noreply@anthropic.com>
Co-authored-by: Giteabot <teabot@gitea.io>
After using CSP nonce, the "onerror" doesn't work anymore. Change it to
use a global variable to detect
Also help users like #37379 to catch errors more easily.
Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
Make the watch, star, and fork buttons in the repo header consistent for
logged-out users:
- Apply the same look to all three buttons (number labels
included), instead of only the action button being grayed.
- Clicking any of them while logged out now leads to the login page
(with a redirect back) instead of being inert.
- Split the per-button markup out of `header.tmpl` into a dedicated
`templates/repo/header/` folder (`fork.tmpl`, `star.tmpl`,
`watch.tmpl`).
---------
Co-authored-by: Claude (Opus 4.7) <noreply@anthropic.com>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
Adds a dedicated endpoint for replying to pull request review comments,
```
POST /repos/{owner}/{repo}/pulls/{index}/comments/{id}/replies
{ "body": "..." }
```
The reply is threaded under the same review as the parent comment.
Ref: https://gitea.com/gitea/gitea-mcp/issues/129
Fixes: https://github.com/go-gitea/gitea/issues/37419
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: Nicolas <bircni@icloud.com>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
- hide() also cancels the pending debounced search so a fetch scheduled
before blur/Escape/outside-click does not fire afterwards and re-show
the dropdown on a field the user has already left
- use urlQueryEscape for the {query} substitution to keep escaping
symmetric with the Go backend (matches Go's url.QueryEscape: space → +,
strict RFC 3986 for !'()*); both decoders still accept %20
Co-Authored-By: Claude (Opus 4.7) <noreply@anthropic.com>
- collapse the render/keydown/select helpers (replaceChildren with mapped
array, inline ArrowUp/Down branch, drop the move() helper)
- abort the in-flight fetch from hide() so Escape/blur/outside-click
cancel the request, and gate the post-await render on
ctrl.signal.aborted to suppress responses that settle after hide()
- rename idx → index
- restore the leading comment in web_src/css/modules/search.css that an
earlier commit on this branch dropped
Co-Authored-By: Claude (Opus 4.7) <noreply@anthropic.com>
After clicking the search result, the test now also clicks Add
Collaborator and asserts the username appears in the page body
(i.e., in the collaborator list after the redirect), proving the
chosen result drives the form submission end-to-end.
Co-Authored-By: Claude (Opus 4.7) <noreply@anthropic.com>
- attachSearchBox(el, url, parse) replaces the await-style chooseFromApi
- The component handles input update + change-event dispatch on
selection, so callers don't loop or write back the value themselves
- Each caller is now a single statement; response shape is conveyed via
the parse callback's parameter annotation (T inferred)
Co-Authored-By: Claude (Opus 4.7) <noreply@anthropic.com>
The `Repository` struct in `services/context/repo.go` embedded
`access_model.Permission` anonymously, causing all permission methods to
be promoted directly onto `Repository`. This made it unclear at call
sites whether a method belonged to `Repository` itself or to its
embedded `Permission`.
### Changes
- **`services/context/repo.go`**: Replace anonymous
`access_model.Permission` with named field `Permission
access_model.Permission`
- **49 files** updated to route permission method calls through the
named field:
```go
// Before
ctx.Repo.IsAdmin()
ctx.Repo.CanWrite(unit.TypeCode)
ctx.Repo.CanReadIssuesOrPulls(isPull)
slices.ContainsFunc(unitTypes, ctx.Repo.CanWrite)
// After
ctx.Repo.Permission.IsAdmin()
ctx.Repo.Permission.CanWrite(unit.TypeCode)
ctx.Repo.Permission.CanReadIssuesOrPulls(isPull)
slices.ContainsFunc(unitTypes, ctx.Repo.Permission.CanWrite)
```
Methods defined directly on `*Repository` (`CanWriteToBranch`,
`CanCreateBranch`, etc.) are unchanged.
---------
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: wxiaoguang <2114189+wxiaoguang@users.noreply.github.com>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
Co-authored-by: Nicolas <bircni@icloud.com>
- chooseFromApi is now generic over the response shape; each caller
declares a typed *SearchResponse, removing four `any` annotations
- e2e test prefix: rc- → repo-collab- for legibility in the test DB
- web_src/css/modules/search.css: drop the stale leading comment
Co-Authored-By: Claude (Opus 4.7) <noreply@anthropic.com>
Move web_src/js/modules/fomantic/search.ts to web_src/js/modules/search.ts
(no Fomantic dependency anymore). Replace the imperative
initSearchBox(el, opts) with chooseFromApi(el, url, parse) that returns
a Promise<SearchResult> resolving with the user's chosen item; callers
loop with `while (box.isConnected) { const pick = await ...; ... }` and
own writing back to whatever input/state they manage.
Cleanup is via a single AbortController whose signal is passed to all
listeners; the in-flight fetch has its own controller so a new keystroke
can cancel just the request without tearing down listeners.
Co-Authored-By: Claude (Opus 4.7) <noreply@anthropic.com>
Three boxes (repo/user/team) all share the same first-party module, so
one happy-path test on the user box is sufficient as a regression
gate. Drops the org/team helpers in tests/e2e/utils.ts that only those
extra tests motivated.
Co-Authored-By: Claude (Opus 4.7) <noreply@anthropic.com>
Drops the 1565-line vendored Fomantic UI search jQuery plugin in favor
of a small first-party TypeScript module covering the three call sites
(repo, user, and team autocomplete). Adds an e2e regression suite that
exercises each search box.
Also fixes input/button vertical alignment in the four forms that wrap
a search box: the fomantic-era `tw-align-middle` workaround is replaced
by `flex-text-block` on the form, which is the codebase's standard
flex helper for this layout.
Co-Authored-By: Claude (Opus 4.7) <noreply@anthropic.com>