Commit Graph

21260 Commits

Author SHA1 Message Date
silverwind
9668d07f67 chore(deps): drop swagger:response duplicated by routers/api/v1/swagger
go-swagger 0.35.1 added a scan.shared-response-conflict diagnostic, and the
swagger target treats any output as an error. AccessToken and OAuth2Application
declared a response that routers/api/v1/swagger/app.go already declares under
the same name, which go-swagger dropped keep-first anyway, so the generated spec
is unchanged.

Response definitions live in routers/api/v1/swagger (130 of them, against 6 in
modules/structs), so the duplicates are removed there.

Assisted-by: Claude Code:Opus 5
2026-07-27 12:48:43 +02:00
silverwind
d525cb8f2d chore(deps): adapt to djlint 1.42 rule changes and re-tidy go.sum
djlint 1.42 counts `href` in each branch of a Go template if/else chain as a
duplicate attribute (H037), so the fork button now resolves its href into a
variable before emitting a single attribute.

H006 and H031 became opt-in in 1.42, making their `ignore` entries dead config.

Assisted-by: Claude Code:Opus 5
2026-07-27 12:36:58 +02:00
Giteabot
69390ee0a8 chore(deps): update dependencies 2026-07-27 09:59:11 +00:00
silverwind
341caf8aa7 chore(ci): fix renovate custom manager regex (#38656)
Make this regex compatible with https://github.com/uhop/node-re2 used by
renovate and which does not support lookahead.

`renovate-config-validator` which I had used earlier fails to run `re2`
on node 26 because of missing prebuilt binary and falls back to JS regex
which does support lookahead, giving incorrect validation results.

Upstream bug report:
https://github.com/renovatebot/renovate/discussions/44873
Fixes: https://github.com/go-gitea/gitea/issues/38648
2026-07-27 09:54:21 +00:00
mohammad rahimi
13d0f24423 feat: Replace SSE with WebSocket for UI notifications (#36965)
* Closes #36942
* Fixes #19265 

Replaces the SSE-based push channel (`/user/events`) with a WebSocket
endpoint (`/-/ws`).

### What changes

- **New `/-/ws` endpoint** (authenticated). One WebSocket per origin,
shared across tabs via a single `SharedWorker`.
- **Pubsub broker** (`services/pubsub`) for fan-out by topic, behind a
`Broker` interface. `MemoryBroker` is the default (single process); a
Redis backend is available for multi-process setups, configured via
`[websocket].PUBSUB_TYPE` / `PUBSUB_CONN_STR`. The internal Gitea queue
was not usable here because it has FIFO/single-consumer semantics.
- **Push-only event production.** Events are emitted by write-triggered
notifiers — `NotificationCountChange`, `PublishStopwatchesForUser`, and
the logout publisher — wired into the existing `notify.Notifier`
interface. No server-side pollers.
- **Typed pub/sub on the client.** `web_src/js/modules/worker.ts` is a
singleton transport; features subscribe per event type via
`onUserEvent('notification-count', cb)` instead of branching on
`event.data.type`.
- **Wire contract** (`UserEventType` union) is shared between the worker
and consumers via `web_src/js/types.ts`, kept in sync with
`services/websocket/events.go`.
- **Client-side periodic polling fallback** kicks in only when the
WebSocket cannot be established (e.g. proxy blocks WS, browser lacks
module-SharedWorker support).

### What's removed

- `modules/eventsource` (SSE manager, run loop, messenger).
- `/user/events` route and `tests/integration/eventsource_test.go`.
- All server-side polling for stopwatches and notification counts.

### Stopwatch multi-tab fix

The navbar stopwatch icon was previously rendered conditionally on `{{if
$activeStopwatch}}`, so tabs loaded before the timer started had no DOM
element to update. The icon and popup are now always rendered (toggled
with `tw-hidden`), and the start/stop/cancel handlers POST silently so
all open tabs reflect the change in real time.

### Deployment note

WebSocket needs the upgrade headers to pass through a reverse proxy,
e.g. for nginx:

```nginx
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
```

Without them the WebSocket cannot be established, and after 3
consecutive failed opens the shared worker signals `push-unavailable`:
the notification count and stopwatch fall back to periodic polling on
the existing `[ui.notification]` timeouts. Real-time push is lost, the
features keep working. The reverse-proxy docs need the same note (see
the `docs-update-needed` label).

---------

Co-authored-by: silverwind <me@silverwind.io>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
Co-authored-by: Epid <rexmrj@gmail.com>
2026-07-27 07:46:00 +00:00
Shudhanshu Singh
e15a7e9066 fix(actions): use base branch ref for pull_request_target context (#38636)
Fixes a bug in Actions context generation for `pull_request_target`
workflows where `github.ref` / `gitea.ref` was incorrectly populated
with `refs/heads/owner:branch` instead of `refs/heads/branch`.

### Problem Statement
In `services/actions/context.go`, when constructing the `ref` string for
`pull_request_target` events:
```go
ref = git.BranchPrefix + pullPayload.PullRequest.Base.Name

Signed-off-by: Sudhanshu Singh <sudhanshuwriterblc@gmail.com>
Signed-off-by: wxiaoguang <wxiaoguang@gmail.com>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2026-07-27 06:34:38 +00:00
Zettat123
528b1f211b fix(actions): skip already-approved runs in ApproveRuns (#38653)
The handler of `/actions/runs/{run}/approve` doesn't check if the run is
already approved. If a run is re-approved, its jobs' status will be
reset to `StatusWaiting`, causing incorrect job status.
2026-07-27 06:01:46 +00:00
roman.s
cebdc90ed9 fix(api): accept fully-qualified refs in contents API (#38650)
`GET/POST` repository contents endpoints resolve the `ref` query
parameter through `ResolveRefCommit`, which previously only accepted
short branch/tag names or commit IDs. Clients that pass fully-qualified
Git refs (GitHub-compatible), e.g. `ref=refs%2Fheads%2Fmain` or
`ref=refs%2Ftags%2Fv1.0`, received 404 "object does not exist".

This change accepts fully-qualified **`refs/heads/*`** and
**`refs/tags/*`** only, then falls back to the existing short-name and
SHA logic. Other `refs/*` prefixes (e.g. `refs/pull/`, `refs/for/`) are
rejected.

Fixes #38197

---------

Co-authored-by: roman s <roman.sukach@dust-labs.com>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2026-07-27 05:31:58 +00:00
GiteaBot
4da9b59414 [skip ci] Updated translations via Crowdin 2026-07-27 00:55:53 +00:00
Lunny Xiao
230e7bdf91 chore(build): upload release to Cloudflare R2 (#38635)
The download site’s bandwidth costs are growing rapidly, while
Cloudflare R2 does not charge egress fees. Therefore, we would like to
migrate the download site from S3 to R2.

To ensure a smooth transition, we will keep the existing S3 upload
process temporarily and remove it after the migration is complete.

The upload steps are currently duplicated in three places. They could be
consolidated into a composite action in a separate PR.
2026-07-26 17:22:25 -07:00
silverwind
e75d583212 ci: match # renovate: markers that trail the value (#38640)
The preset we extended only matches a `# renovate:` comment on the line
above the `_VERSION` assignment. Ours trails the value, like the ones in
the `Makefile`, so it never matched and the pin has sat at `43.141.5`
since https://github.com/go-gitea/gitea/pull/37050.

Co-authored-by: Claude (Opus 5) <noreply@anthropic.com>
2026-07-26 18:06:48 +00:00
wxiaoguang
a3caf21440 feat: admin impersonates a user (#38614)
* fix #3631
* fix #21599

by the way, refactored the "profile avatar card" to simplify the code.
2026-07-26 17:26:02 +00:00
wxiaoguang
470d34b1de refactor: git patch apply (#38637)
Merge duplicate code and add a unit test

There are already integration test cases in `TestEditor` ->
`WebGitCommitEmail` for these two endpoints.
2026-07-26 16:57:00 +00:00
wxiaoguang
3e6cb7c16b fix: orgmode render include path (#38642)
Co-authored-by: TheFox0x7 <thefox0x7@gmail.com>
2026-07-26 14:22:49 +00:00
bircni
1b18b25c8e fix(actions): cancel tasks immediately when the runner stopped reporting (#38616)
Fixes jobs that get stuck in `cancelling` after Gitea is restarted while
a job is running.

Reproduction:

1. Run a job with `sleep 100`
2. Stop Gitea and wait 120s (> 100s)
3. Start Gitea — the job is still `running`; cancel it, and it stays in
`cancelling`

## Cause

A cancellation is only ever delivered to a runner as the *response* to
its `UpdateTask`
RPC. A runner that has already given up on the task — it crashed, or it
failed to report
the final state while Gitea was unreachable — never calls `UpdateTask`
again, so it never
learns about the cancellation. The task then sits in `cancelling` until
`stop_zombie_tasks`
reaps it, which needs `ZOMBIE_TASK_TIMEOUT` (10m) of silence and only
runs every 5 minutes.

Cancelling actually made this worse. xorm rewrites the `updated` column
on every `UPDATE`,
even when `Cols()` restricts the update to `status`, so persisting the
`cancelling` status
reset the zombie clock. Pressing cancel pushed the cleanup a full
`ZOMBIE_TASK_TIMEOUT`
into the future instead of bringing it forward.

## Change

`StopTask` now skips the `cancelling` handshake when the task has had no
state report from
its runner for longer than `TaskReportTimeout` (1 minute) and cancels it
directly. This
joins the two existing fallbacks — runner deleted, and runner without
cancelling support —
so every cancel path (web UI, API, concurrency, rerun) is covered.

Runners report the state of a running task every few seconds, so a
minute of silence means
the runner is gone. The value is a constant rather than a setting
because it only decides
whether the runner is still reachable, not whether a task should be
killed —
`ZOMBIE_TASK_TIMEOUT` still owns that.

### Tradeoff

If a runner is alive but has been silent for over a minute and is
cancelled in that window,
it skips the graceful post-step cleanup added in #37275. No work is
lost: the runner still
learns the outcome on its next report, because `UpdateTask` returns the
task status as the
result and the runner stops there. That is the behaviour that existed
before #37275.

---------

Co-authored-by: Zettat123 <zettat123@gmail.com>
Co-authored-by: silverwind <me@silverwind.io>
2026-07-26 13:50:06 +00:00
Elisei Roca
47565ae93e fix(issues): fix label bulk-load key and reduce log noise in LoadLabel (#38632)
CommentList.loadLabels keyed the result map by label.ID but looked up by
comment.ID, so every label event fell back to individual DB queries.

This caused log spam for any comment where the label was deleted, since
ToTimelineComment calls LoadLabel unconditionally for all comment types
including those with LabelID=0.

Fix the map key, skip the query when LabelID=0, demote the now rarely
triggered orphaned-label log to Debug, and fix a typo ("Commit" ->
"Comment") in that message.

---------

Signed-off-by: wxiaoguang <wxiaoguang@gmail.com>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2026-07-26 12:31:30 +00:00
silverwind
14ca2e7526 fix(ui): avoid layout shifts in overflow-menu and repo filter (#37818)
Eliminate two layout shifts in the menu, one related to non-existant
label on page load and one to `0` value rendering.

Signed-off-by: silverwind <me@silverwind.io>
Co-authored-by: Claude (Opus 4.7) <noreply@anthropic.com>
Co-authored-by: bircni <bircni@icloud.com>
2026-07-26 10:26:52 +00:00
silverwind
b4eb8c03c4 chore: generate codemirror languages from linguist-languages package (#38624)
Replace the previous main-branch fetch with data from npm package
[`linguist-languages`](https://github.com/ikatyang-collab/linguist-languages)
and only run generate targets when actually needed. The removed
`fileFilters` were leftovers from the nolyfill removal.
2026-07-26 10:19:53 +00:00
GiteaBot
a2166293f7 [skip ci] Updated translations via Crowdin 2026-07-26 00:56:06 +00:00
bircni
396ec646f6 fix(actions): improve runner list status sorting, labels and task job links (#38586)
Several small fixes to the Actions runner management UI.

### Runner task list links to the job, not the workflow run
Relabeled the first column from "Run" to "Job"; it now shows the job ID
and links to the specific job (`/actions/runs/{runID}/jobs/{jobID}`).
Renamed locale key `task_list.run` to `task_list.job`.

### Missing "Disabled" translation
The runner list rendered a grey label via `actions.runners.disabled`,
but that key
did not exist in `locale_en-US.json`, so the raw key string leaked into
the UI.
Replaced `"actions.runners.disabled"` with `"disabled"`.

### Status column sorting ignored active vs idle
Sorting by status ordered purely on `last_online`, but the displayed
status is
computed from both `last_online` (offline) and `last_active` (idle vs
active).
As a result idle runners were interleaved with active ones. Sorting now
ranks by
the computed status (active → idle → offline). Disabled runners sink to
the bottom
of their status group (`is_disabled` as a secondary key), with
`last_online`/`id`
as stable tiebreakers so pagination stays deterministic.

### Status label colors
Active and idle both rendered green. Idle is now yellow, active green,
and
offline/unknown grey; the separate grey "Disabled" badge is unchanged.
This keeps
connectivity visible even for disabled runners (e.g. a disabled runner
still shows
whether it is idle or offline).

<img width="715" height="406" alt="image"
src="https://github.com/user-attachments/assets/9ef06aa8-a870-4de5-9d94-603a58186908"
/>

---------

Co-authored-by: Zettat123 <zettat123@gmail.com>
2026-07-25 21:31:19 +00:00
bircni
69f0a10364 fix(actions): correctness and hardening fixes (#38518)
Various fixes to actions

1. **Cap total jobs per run in reusable-workflow expansion** — only
nesting depth was capped, so fan-out + nested reusable workflows could
explode job-row inserts and exhaust the DB from a single push. Now
enforces `MaxJobNumPerRun` in the insert path.
2. **Reject rerun-failed when a run has no failed jobs** — an empty job
list meant "re-run everything", so `rerun-failed` on a green run re-ran
all jobs. Now errors (web + API).
3. **Don't adopt external commit statuses into the legacy hash** — the
pre-#35699 Context-only hash matched API-posted statuses too, collapsing
two same-named workflows into one check. Now limited to Actions-user
rows.
4. **Don't cut post-cancel cleanup short in `StopEndlessTasks`** — the
sweep force-stopped just-cancelled jobs mid-cleanup. Now targets
`StatusRunning` only; stalled cancels stay covered by `StopZombieTasks`.
5. **Avoid redundant run reload in `GenerateGiteaContext`** — resolving
`github.triggering_actor` reloaded the run already passed in. Now loads
only the trigger user via new `ActionRunAttempt.LoadTriggerUser`.

---------

Co-authored-by: Zettat123 <zettat123@gmail.com>
Co-authored-by: silverwind <me@silverwind.io>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2026-07-25 16:07:40 +00:00
silverwind
7a1941e384 chore: remove goreportcard badge (#38630)
Service is discontinued as per https://goreportcard.com/, remove the dysfunctional badge.
2026-07-25 17:39:25 +02:00
Shudhanshu Singh
fadaf36e95 fix(repo): prevent double-write redirect collisions on dependency errors, fix ui (#38627)
1. fix `AddDependency` and ` RemoveDependency` to respond correctly
2. refactor the form to use "form-fetch-action"
3. fix the issue dependency icon layout regression

---------

Signed-off-by: Sudhanshu Singh <sudhanshuwriterblc@gmail.com>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2026-07-25 20:39:36 +08:00
Giteabot
39cc4db4ba fix(deps): update module github.com/getkin/kin-openapi to v0.144.0 [security] (#38623) 2026-07-24 22:14:44 +00:00
silverwind
13406e7aa7 chore: update and relax revive naming rules (#38615)
- enable `skip-initialism-name-checks`, so names like `sessionUid` are
allowed
- replace removed `skip-package-name-checks` option with new
`package-naming` with fitting rules for gitea
- drop dead exclusion paths
2026-07-24 21:47:23 +00:00
silverwind
818da42728 ci: add missing type/refactoring label for refactor PR titles (#38611)
Add missing mapping for `refactor` type to set `type/refactoring` label automatically on PRs.
2026-07-24 21:21:46 +00:00
Giteabot
be41cff5e2 fix(deps): update dependency js-yaml to v5.2.2 [security] (#38622) 2026-07-24 23:20:03 +02:00
bircni
608c248638 docs: Update Security docs (#38422)
Signed-off-by: bircni <bircni@icloud.com>
Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
Co-authored-by: TheFox0x7 <thefox0x7@gmail.com>
2026-07-24 21:28:35 +02:00
silverwind
37e80730ec fix: abort superseded issue suggestion requests (#38620)
Fix regression from https://github.com/go-gitea/gitea/pull/38610

`perfect-debounce` allowed only one request in flight; `debounce` does
not, so a slow older request can resolve after a newer one and leave a
stale suggestion menu. Superseded requests are now aborted.
2026-07-24 21:25:38 +02:00
Luc
9ad80e1eba fix: delete repo-scoped rows of seven more tables when deleting a repository (#38534)
Fixes #38494

`DeleteRepositoryDirectly` left rows behind in seven registered tables
carrying a repo-scoped key: `action_variable`, `action_run_attempt`,
`action_tasks_version`, `renamed_branch`, `commit_status_summary`,
`commit_status_index` and `repo_transfer`. Repository IDs are `pk
autoincr` and never reissued, so the orphaned rows were unreachable, but
they accumulated forever (unbounded table growth, referential
inconsistency; not a security issue, see the issue discussion).

This adds all seven to the `deleteBeans` cascade, each placed next to
its sibling bean
(`CommitStatus`/`CommitStatusIndex`/`CommitStatusSummary`,
`Branch`/`RenamedBranch`, `Secret`/`ActionVariable`,
`ActionRun`/`ActionRunAttempt`). `repo_transfer` goes through the same
cascade rather than `DeleteRepositoryTransfer` so teardown stays one
mechanism; the existing reaper remains for the transfer flows.

The test inserts one row per previously-orphaned table (the fixture
files ask test cases to prepare their own data), deletes the repository,
and asserts each table is purged. Without the fix it fails on all seven
tables.

---------

Signed-off-by: wxiaoguang <wxiaoguang@gmail.com>
Signed-off-by: Luc <luuuc@users.noreply.github.com>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2026-07-24 17:40:39 +00:00
silverwind
66794e0549 refactor: replace debounce/throttle deps with first-party code (#38610)
Adds `web_src/js/utils/func.ts` with `debounce` and `throttle`, dropping
`throttle-debounce` and `perfect-debounce` dependencies. Both were
needed before: the former has no promise-returning debounce, which
`TextExpander` requires, and the latter no `throttle`.

Signature follows lodash and es-toolkit: `(func, wait, {leading,
trailing})` plus `cancel`, so argument order flips at the migrated call
sites.
2026-07-24 16:39:15 +00:00
mohammad rahimi
1e42317b66 feat(setting): add shared [redis] section as default for redis-backed subsystems (#38550)
Adds a shared `[redis]` config section with a single `CONN_STR` key that
acts as the default Redis connection for every redis-backed subsystem
whose own connection string is empty: `[cache].HOST`,
`[session].PROVIDER_CONFIG`, `[queue].CONN_STR` and
`[global_lock].SERVICE_CONN_STR`.

Precedence: per-subsystem value > shared `[redis].CONN_STR` > existing
built-in defaults. Fully backward compatible: when `[redis]` is not set,
every code path behaves exactly as before.

Motivation: today an admin with one Redis instance has to repeat the
same connection string in up to four places (five once WebSocket lands).
Requested by @wxiaoguang in [this review
discussion](https://github.com/go-gitea/gitea/pull/36965#discussion_r3613306976)
as a prerequisite for #36965. This follows the pattern used by GitLab
and Mastodon: one global Redis definition, per-subsystem overrides fall
back to it.

Since #12385 all identical connection strings already share one client
via `nosql.Manager`, so pointing all subsystems at `[redis].CONN_STR`
naturally converges onto a single shared connection pool.

Covered by table-driven unit tests per subsystem (fallback applies, own
value wins, absent `[redis]` = unchanged behavior). A config-cheat-sheet
update for gitea/docs will follow once this is merged.

---------

Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
Co-authored-by: TheFox0x7 <thefox0x7@gmail.com>
2026-07-24 08:11:20 +00:00
Chaehyeon Lee
5db58f930e fix(webhook): remove slack channel name check (#38608)
Users should know what they are doing, don't check everything,
especially for that we don't understand.

Fixes #23840

---------

Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2026-07-24 07:45:41 +00:00
silverwind
29b99de940 ci: derive topic labels from PR title (#38595)
Derives topic labels from the PR title scope: `enhance(actions): ...`
gets `topic/gitea-actions`. Scopes map to `topic/<scope>`, with aliases
for names that differ (`oauth` → `topic/authentication`).

Labels stay in sync with the title, while ones applied by hand are left
alone. Scopes with no matching label on the repo are ignored, so no new
labels get created.

---------

Co-authored-by: Giteabot <teabot@gitea.io>
2026-07-24 04:43:42 +00:00
Richard Mahn
0e8bafc267 fix: download dropdown menu clipped on the branches page (#38604)
Fixes #38603

Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2026-07-24 04:24:25 +00:00
silverwind
6791d5a418 enhance(actions): action view enhancements (#38594)
- avoid layout shift on actions log view page load
- retain header border when actions log is scrolled
- when copying step output, only copy with timestamp when timestamp
display is enabled (useful for example when step output is plain json
and copying with timestamp would make that json unparsable).
2026-07-24 04:17:02 +00:00
silverwind
9430e3230f enhance: keep status check list scrolled on merge box reload (#38597)
Remember the scroll offset when the merge box reloads. This is a crude
patch now, a proper fix would be a fully vue-rendered template with a
json payload from backend, which is much more work. Idiomorph was also
considered but deemed unviable.
2026-07-24 04:10:26 +00:00
silverwind
99ca4bff7d fix: make auth source group sync correctly handle team removal (#37161)
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2026-07-24 02:05:38 +00:00
Mitrahsoft
3c66ec4064 fix(oauth2): enforce mandatory 2FA policy on OAuth2 authorize/grant endpoints (#38591)
Fixes #37407 

---------

Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2026-07-24 01:39:38 +00:00
wxiaoguang
7065637e61 refactor: hide git repo path details from more packages (#38601)
Remove `RepoPath` from "models/repo" package, remove `UserPath` from
"models/user" package, use `WithRepo` for more places, fine tune tests.
2026-07-23 17:42:55 +00:00
Shudhanshu Singh
86a3048247 fix(project): prevent database mutations on invalid MoveIssues payload (#38600)
Add missing "return" after ServerError

Signed-off-by: Sudhanshu Singh <sudhanshuwriterblc@gmail.com>
2026-07-23 08:51:49 -07:00
wxiaoguang
e992b0a7cc refactor: retry file remove/rename when a file is busy and clean up os detection (#38588)
Rename functions "util.Remove" (remove.go) to "util.RemoveWithRetry"
(file_retry.go) and add comments to clarify their behaviors, also add
tests.

Refactor callers: when no concurrent access (cmd cli, migration, app
init, test), use "os.Xxx" directly.

More details are in `modules/util/file_retry.go`

By the way, clean up OS (windows) detection, make FileURLToPath test
always run
2026-07-23 14:31:29 +00:00
Mohamed Belkamel
c4fc4d363b fix(actions): make SingleWorkflow.Marshal round-trip multi-line run blocks (stop silent job stranding) (#38520)
## Problem
Jobs that call a reusable workflow (`uses:`) whose steps contain a `run:
|` block that **starts with blank lines** never start — the child jobs
stay `Blocked` forever, the run never finishes, and nothing is shown to
the user (the error is only logged at DEBUG). The reusable is valid YAML
and worked on 1.26.

## Root cause
`jobparser` serializes each expanded job via `SingleWorkflow.SetJob()`,
which uses `yaml.NewEncoder(...).SetIndent(2)`, but
`SingleWorkflow.Marshal()` used `yaml.Marshal`, whose default
indentation is **4**. Re-emitting a multi-line literal block scalar at a
different indentation makes the encoder write a wrong explicit
indentation indicator (`run: |4`) whose declared indent doesn't match
the actual content indent. The stored `workflow_payload` is then
unparseable:

```
run: |4


                while ...
```

`jobparser.Parse` / `model.ReadWorkflow` (both go.yaml.in/yaml/v4)
reject it: `did not find expected key`. This surfaces in
`services/actions/job_emitter.go` `resolve()` →
`updateConcurrencyEvaluationForJobWithNeeds` → `ParseJob`, where the
error is swallowed at `log.Debug` and the job is left `Blocked`.

Encoding at indent 4 triggers the bad indicator; indent 2 does not —
matching the value already used by `SetJob`.

## Fix
Encode `SingleWorkflow.Marshal()` with `SetIndent(2)` so both encoders
agree and the serialized single workflow round-trips. Adds a regression
test (`Parse → Marshal → Parse` on a `run:` block with leading blank
lines) that fails before the change with `did not find expected key`.

---------

Signed-off-by: quasimodo <mohamed.belkamel@intelcia.com>
Co-authored-by: quasimodo <mohamed.belkamel@intelcia.com>
Co-authored-by: Zettat123 <zettat123@gmail.com>
2026-07-23 15:42:21 +02:00
Shudhanshu Singh
6ac19f6226 fix(issue): display error toast on batch action failures instead of reloading page (#38593)
Batch operations in the issues list (labels, milestones, projects,
assignees, etc.) could fail silently because `updateIssuesMeta` caught
and suppressed fetch errors internally. The caller would then proceed to
reload the page, clearing all selected issue checkboxes and giving the
impression that the operation had succeeded.

- Remove updateIssuesMeta and use our "fetch-action" framework to handle errors and page reloading
- Refactor backend code to use ctx.JSONError

---------

Signed-off-by: Sudhanshu Singh <sudhanshuwriterblc@gmail.com>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2026-07-23 09:33:47 +00:00
Shudhanshu Singh
ee10ae168c perf(emoji): optimize FindEmojiSubmatchIndex using slice-based Trie (#38573)
This pull request optimizes `FindEmojiSubmatchIndex` in Gitea's emoji
package (`modules/emoji/emoji.go`) by replacing the
`strings.Replacer`-based search with a slice-based trie and a
constant-time starting-byte check (`isStartingByte`).

The new implementation avoids heap allocations during the search and
reduces CPU overhead when rendering Markdown, particularly for plain
text that does not contain emojis.

### Verification

Verified with unit tests:

```sh
go test -count=1 ./modules/emoji/...
```

Benchmarks:

```sh
go test -bench=. -benchmem ./modules/emoji/...
```

### Results

| Benchmark | Before | After |
| ---------- | ------ | ----- |
| `BenchmarkFindEmojiSubmatchIndex` | 168.3 ns/op, 2 allocs/op | 85.78
ns/op, 1 alloc/op |
| `BenchmarkFindEmojiSubmatchIndexNoMatch` | 239.8 ns/op, 1 alloc/op |
105.1 ns/op, 0 allocs/op |
### Benchmark Output

```text
goos: linux
goarch: amd64
pkg: gitea.dev/modules/emoji
cpu: Intel(R) Core(TM) i5-7400 CPU @ 3.00GHz

BenchmarkFindEmojiSubmatchIndex-4              13498539        85.78 ns/op      16 B/op   1 allocs/op
BenchmarkFindEmojiSubmatchIndexNoMatch-4       11220450       105.1 ns/op        0 B/op   0 allocs/op
BenchmarkFindEmojiSubmatchIndexOld-4            6569360       168.3 ns/op      48 B/op   2 allocs/op
BenchmarkFindEmojiSubmatchIndexOldNoMatch-4     5026116       239.8 ns/op      32 B/op   1 allocs/op
```

---------

Signed-off-by: Sudhanshu Singh <sudhanshuwriterblc@gmail.com>
Co-authored-by: silverwind <me@silverwind.io>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2026-07-23 08:29:28 +00:00
silverwind
acbdc44d00 test(e2e): add pull request merge box test, update AGENTS.md (#38576)
Adds browser-level coverage for the pull request merge box, which
currently had no tests. Exercises the full merge flow: open the PR,
expand the merge form, submit, and assert the merged state.

Extracted from https://github.com/go-gitea/gitea/pull/36759.

Also updated AGENTS.md with instructions for e2e tests.

---------

Signed-off-by: silverwind <me@silverwind.io>
Co-authored-by: Giteabot <teabot@gitea.io>
2026-07-23 09:29:36 +02:00
Shudhanshu Singh
560edd45e9 fix(api): align Swagger schemas for UserSettings and TopicListResponse (#38590)
Corrects the Swagger/OpenAPI schemas for `/user/settings` and
`/topics/search` to match the actual JSON objects returned by the API.

Signed-off-by: Sudhanshu Singh <sudhanshuwriterblc@gmail.com>
2026-07-23 14:49:52 +08:00
yszl666
20221e1faa fix(file-tree): handle submodule links and missing view container (#38033)
Prevent tree view navigation from intercepting submodule entries so the
browser can follow external repository links normally.

---------

Signed-off-by: wxiaoguang <wxiaoguang@gmail.com>
Co-authored-by: dzf <douzf@sparkspacetech.com>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2026-07-23 02:05:43 +00:00
wxiaoguang
1acf93d854 refactor: clean up git repo and model migration packages (#38564)
enable the golangci depguard lint rule: deny "models" and its sub
packages in "modelmigration" package.
2026-07-23 01:22:26 +00:00
GiteaBot
fa64b4627a [skip ci] Updated translations via Crowdin 2026-07-23 00:51:47 +00:00