Closes#37670.
Today, org members in Gitea only see teams they're a member of. In
larger orgs that hurts onboarding and discoverability — there's no way
to look up which team owns what without asking around. GitHub solves
this with a per-team visibility setting; this PR brings the same model
to Gitea.
## What changes
- Every team gets a `visibility` setting:
- `private` *(default)* — only team members and org owners can see the
team. Same as today's behavior.
- `limited` — listable by any member of the organization. Members and
the repos the team has access to are visible too. Non-org-members still
see nothing.
- `public` — listable by any signed-in user.
- The Owners team visibility is fixed and cannot be changed via
settings.
- Existing teams default to `private`, so this is a no-op for anyone who
doesn't change anything.
## API
- `Team`, `CreateTeamOption`, `EditTeamOption` all gain a `visibility`
field (string enum: `private` | `limited` | `public`).
- `GET /orgs/{org}/teams` and `/orgs/{org}/teams/search` now apply the
same visibility rules as the web UI:
- site admins and org owners still see every team
- other org members see their own teams plus any `limited` or `public`
team
- `private` teams are no longer leaked through these endpoints
- Swagger/OpenAPI specs regenerated.
## UI
View from admin2 (not an owner):
<img width="1669" height="726"
src="https://github.com/user-attachments/assets/daf4bccb-644b-4426-b178-71963aeaf73b"
/>
View from admin (owner):
<img width="2559" height="863"
src="https://github.com/user-attachments/assets/4f22cebc-e9df-4fd2-8ed4-724d31fadb7a"
/>
---------
Signed-off-by: bircni <bircni@icloud.com>
Co-authored-by: TheFox0x7 <thefox0x7@gmail.com>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
* fix incorrect delayWriter call (there is already a defer call)
* split HookPostReceive into small functions
* fix incorrect HookPostReceiveResult response for errors
* fix incorrect AddRepoToLicenseUpdaterQueue call
* make sure repo home and branches page can work without default branch
* make sure default branch is always synchronized between database and
git repo, and fix FIXME
Follow-up to #37987, addressing the unresolved review comments on the
org members search form.
And fix more trivial problems together (see the commit titles)
---------
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
The registry writes the stored gem name straight into its line-based
compact index, both the shared `/versions` listing (one `GEMNAME
versions md5` line per gem) and the per-package `info/{name}` file. The
parser only rejected an empty name or one containing a slash, so a
`.gem` whose gemspec `name` carries a newline was accepted and persisted
as the package name, letting an authenticated uploader forge extra lines
in the shared index and so spoof additional gem names, versions and
checksums to clients. The name is now checked against the upstream
RubyGems name pattern in the parser, which is the layer that already
validates the version.
---------
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
**Packages-index stanza injection via Debian control file**
A `.deb` whose `control` file appends extra paragraphs after a blank
line was still accepted, and `ParseControlFile` stored the whole
multi-stanza blob in `p.Control`. That blob is re-emitted verbatim into
the generated `Packages` index, so the embedded blank line splits it
into separate stanzas and an uploader can smuggle a package entry with
an attacker-chosen `Filename` into the shared index. A binary control
file only holds one stanza, so parsing now stops at the blank line that
terminates it; well-formed packages are unaffected and the new subtest
covers the trailing-stanza case.
---------
Signed-off-by: wxiaoguang <wxiaoguang@gmail.com>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
Follow
https://docs.github.com/en/enterprise-server@3.20/rest/issues/assignees?apiVersion=2022-11-28Fix#33576
And it also fixed some possible dead-lock problem.
---------
Signed-off-by: Lunny Xiao <xiaolunwen@gmail.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Nicolas <bircni@icloud.com>
Co-authored-by: Zettat123 <zettat123@gmail.com>
Parse `Co-authored-by:` trailers from commit messages and surface
contributors as an avatar stack across the commit page, commits list, PR
commits tab, latest-commit row, blame, graph, and dashboard feed.
- Up to 10 visible 20px avatars, GitHub-style overlap (6px first stride,
4px between subsequent), `+N` chip for the rest.
- Label: 1 → name; 2 → `<a> and <b>`; 3+ → `<N> people` opens a Tippy
popup with all participants.
- Names and avatars link to the repo's commits-by-author search; fall
back to profile or `mailto:`.
- Trailer parsing uses `net/mail.ParseAddress`, scans only the trailing
paragraph, filters out the commit's own author/committer.
- Drops the non-standard `Co-committed-by:` emission on squash merge and
web edits.
Devtest: `/devtest/coauthor-avatars`.
Fixes#25521
----
<img width="353" height="277" alt="image"
src="https://github.com/user-attachments/assets/72092ceb-97ca-4b09-9557-0b72d3c5458e"
/>
<img width="533" height="328"
src="https://github.com/user-attachments/assets/11d0c8f8-8b3f-4f2e-9993-879f1c06bcc5"
/>
---------
Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
Co-authored-by: silverwind <me@silverwind.io>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
Co-authored-by: Giteabot <teabot@gitea.io>
Upgrade `github.com/SaveTheRbtz/zstd-seekable-format-go/pkg` from
`v0.8.3` to `v0.10.0`:
https://github.com/SaveTheRbtz/zstd-seekable-format-go/releases/tag/pkg%2Fv0.10.0
This keeps Gitea's seekable zstd wrapper on the stable v0.10 API while
preserving the existing public `modules/zstd` API.
API migration:
- update `SeekableWriter` and `SeekableReader` internals for the
concrete `*seekable.Writer` and `*seekable.Reader` types introduced by
SaveTheRbtz/zstd-seekable-format-go#264
- update generated dependency metadata after `go mod tidy` removed the
now-unused `github.com/google/btree` transitive dependency
- no Gitea call sites needed changes because `modules/zstd` still
exposes the same constructors and interfaces
Validation:
- `go test ./modules/zstd`
- `make --always-make checks-backend`
---------
Co-authored-by: Giteabot <teabot@gitea.io>
Two test-only changes that cut the `-race` backend unit job's critical
path, with no behavior change.
- **`modules/auth/password/hash`** — `TestHashing`/`TestVectors`
exercised the CPU-bound KDFs (scrypt `N=65536`, pbkdf2, bcrypt, argon2)
serially on one core. Marking the subtests `t.Parallel()` fans them
across cores. The hasher registry they read is only mutated by the
non-parallel `Test_registerHasher`, so this is race-free.
- **`services/release`** — `TestRelease_Update`/`TestRelease_createTag`
slept `6x time.Sleep(2s)` only to cross the 1-second `CreatedUnix`
boundary. Replaced with an advancing mocked clock (`timeutil.MockSet`),
making the timestamp assertions deterministic and removing the real
waits.
---
This PR was written with the help of Claude Opus 4.8
Co-authored-by: Claude (Opus 4.8) <noreply@anthropic.com>
Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
## Summary
This PR improves reusable workflow support for Gitea Actions. The
parsing of the called workflow now happens on Gitea side, not on the
runner. When the caller becomes ready, Gitea fetches the called workflow
source, parses it, and inserts each child job into the database as a
`ActionRunJob` linked to the caller via `ParentCallJobID`. As a result,
every callee job is dispatched as its own task and its logs surface as
an independent job entry in the UI, rather than being inlined into the
caller's "Set up job" step.
This PR supports two kinds of `uses` :
- same-repo call: `uses: ./.gitea/workflows/foo.yaml`
- cross-repo call: `uses: OWNER/REPO/.gitea/workflows/foo.yaml@REF`
## **⚠️ BREAKING ⚠️**
External reusable workflows (`uses:
https://other-gitea-instance/OWNER/REPO/.gitea/workflows/test.yaml@REF`)
are no longer supported. To keep using them, clone the repositories to
the local instance.
## Main changes
### Execution model
- Each caller job carries `IsReusableCaller=true` and won't be fetched
by runners.
- `ParentCallJobID` can link a called job to its caller.
- Caller status is derived from its direct children.
### Workflow syntax
- `jobparser` now supports parsing `on: workflow_call` trigger with
`inputs:`, `outputs:`, and `secrets:` declarations.
- **Max nesting depth**: capped at `MaxReusableCallLevels = 9`, which
means a top-level caller may have at most 9 nested callers below it.
- **Cycle prevention**: at expansion time, `checkCallerChain` walks the
caller's ancestor chain via `ParentCallJobID` and rejects if the same
`uses:` string appears anywhere upstream (`reusable workflow call cycle
detected`). This catches both direct (`A -> A`) and indirect (`A -> B ->
A`) cycles.
### Cross-repo access
- To share reusable workflows from private repos, use `Collaborative
Owners` introduced by #32562
### Rerun semantics
- `expandRerunJobIDs` partitions the latest attempt's jobs into:
- a **rerun set**: jobs being rerun + downstream siblings within the
same scope.
- an **ancestor set**: reusable callers whose only *some* descendants
are being rerun (the caller itself is not).
- Cloning behavior for callers in `execRerunPlan`:
- **Caller is fully rerun** (caller's `AttemptJobID` in `rerunSet`):
none of its descendants are cloned. The caller is cloned with
`IsCallerExpanded=false`, and re-expansion (which reinserts the children
fresh) happens later when the resolver brings the caller to `Waiting`
again.
- **Caller is in ancestor set** (only some descendants rerun): the
caller is pass-through (`Status` will be updated by its fresh children).
Its non-rerun descendants are also pass-through clones (point
`SourceTaskID` at the original task). Their `ParentCallJobID` is
remapped to the new attempt's caller row.
### UI
- Job list in `RepoActionView.vue` is now tree-shaped: callers indent
their children. Callers default to collapsed.
- New caller detail page using `WorkflowGraph` to show direct children
only; the run summary's `WorkflowGraph` shows top-level callers and
their immediate descendants.
### Known trade-offs
- **Caller expansion runs inside the enclosing write transaction.**
`expandReusableWorkflowCaller` performs a git read of the called
workflow while holding the row locks that update the caller and insert
its children. This is intentional: the caller-row update and child-row
inserts must commit atomically. None of the call sites is hot (each
caller is expanded once per attempt), so the trade-off is acceptable.
- **A malformed `if:` expression on a job leaves it `Blocked`
silently.** `evaluateJobIf` now runs server-side as part of resolver
passes; deterministic expression errors (typos, undefined context
fields) are logged but do not surface in the UI. This is the same
behavior the resolver already had for concurrency-expression errors.
Distinguishing transient DB errors from user-authored expression errors
and writing the latter back as `StatusFailure` is a follow-up.
#### Screenshots
<img width="1600" alt="image"
src="https://github.com/user-attachments/assets/bfaa9b7a-07e9-4127-8de9-a81f86e82828"
/>
<img width="1600" alt="image"
src="https://github.com/user-attachments/assets/8af109b3-ef28-4b53-aaad-d4632b923224"
/>
## References
-
https://docs.github.com/en/actions/how-tos/reuse-automations/reuse-workflows
-
https://docs.github.com/en/actions/reference/workflows-and-actions/reusing-workflow-configurations
---
Replace #36388
---------
Signed-off-by: Zettat123 <zettat123@gmail.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: silverwind <me@silverwind.io>
Co-authored-by: Claude (Opus 4.7) <noreply@anthropic.com>
Gitea now only allows `workflow_dispatch.inputs`. If a workflow contains
`workflow_call.inputs`, the workflow cannot be triggered, even though
the `on:` section contains other trigger events.
428ee9fcce/modules/actions/jobparser/model.go (L402-L405)
For example, this workflow cannot be triggered due to
`workflow_call.inputs`:
```yaml
on:
push:
pull_request:
workflow_call:
inputs:
name:
type: string
```
---
This PR is extracted from #37478 for backport
---------
Co-authored-by: silverwind <me@silverwind.io>
Co-authored-by: Claude (Opus 4.8) <noreply@anthropic.com>
Co-authored-by: Giteabot <teabot@gitea.io>
- When a commit subject is a bare URL, `linkProcessor` wrapped it in its
own `<a>` to that URL. Because HTML cannot nest anchors, the wrapping
default link (the action run / commit link) was lost and the action
title became unclickable — clicking it sent the user to the URL from the
commit message instead of the action log.
- Drop `linkProcessor` from `PostProcessCommitMessageSubject` so the
whole subject stays wrapped in the default link. URLs in subjects now
render as text inside that link; URLs in commit bodies are unaffected.
Fixes#37865
---------
Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
Co-authored-by: Giteabot <teabot@gitea.io>
### Description
Replaces all remaining direct `gopkg.in/yaml.v3` imports with
`go.yaml.in/yaml/v4` across models, modules, routers, services, and
integration tests. `gopkg.in/yaml.v3` moves from a direct to an indirect
dependency in `go.mod`.
#### API compatibility
The yaml.Node type, node.Kind/node.Content traversal style
(modules/markup/markdown/convertyaml.go), and the
UnmarshalYAML(*yaml.Node) interface signature
(modules/optional/serialization.go) are all preserved in v4 — no
call-site changes were required beyond the import path.
**Related:**
- https://github.com/go-gitea/gitea/pull/36564#issuecomment-4526536805
---------
Co-authored-by: silverwind <me@silverwind.io>
Co-authored-by: Claude (Opus 4.8) <noreply@anthropic.com>