Zettat123 0359746abe feat(actions)!: improve support for reusable workflows (#37478)
## 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>
2026-05-30 08:31:14 +02:00

Gitea

繁體中文 | 简体中文

Purpose

The goal of this project is to make the easiest, fastest, and most painless way of setting up a self-hosted Git service.

As Gitea is written in Go, it works across all the platforms and architectures that are supported by Go, including Linux, macOS, and Windows on x86, amd64, ARM and PowerPC architectures. This project has been forked from Gogs since November of 2016, but a lot has changed.

For online demonstrations, you can visit demo.gitea.com.

For accessing free Gitea service (with a limited number of repositories), you can visit gitea.com.

To quickly deploy your own dedicated Gitea instance on Gitea Cloud, you can start a free trial at cloud.gitea.com.

Documentation

You can find comprehensive documentation on our official documentation website.

It includes installation, administration, usage, development, contributing guides, and more to help you get started and explore all features effectively.

If you have any suggestions or would like to contribute to it, you can visit the documentation repository

Building

From the root of the source tree, run:

TAGS="bindata" make build

The build target is split into two sub-targets:

Internet connectivity is required to download the go and npm modules. When building from the official source tarballs which include pre-built frontend files, the frontend target will not be triggered, making it possible to build without Node.js.

More info: https://docs.gitea.com/installation/install-from-source

Using

After building, a binary file named gitea will be generated in the root of the source tree by default. To run it, use:

./gitea web

Note

If you're interested in using our APIs, we have experimental support with documentation.

Contributing

Expected workflow is: Fork -> Patch -> Push -> Pull Request

Note

  1. YOU MUST READ THE CONTRIBUTORS GUIDE BEFORE STARTING TO WORK ON A PULL REQUEST.
  2. If you have found a vulnerability in the project, please write privately to security@gitea.io. Thanks!

Translating

Crowdin

Translations are done through Crowdin. If you want to translate to a new language, ask one of the managers in the Crowdin project to add a new language there.

You can also just create an issue for adding a language or ask on Discord on the #translation channel. If you need context or find some translation issues, you can leave a comment on the string or ask on Discord. For general translation questions there is a section in the docs. Currently a bit empty, but we hope to fill it as questions pop up.

Get more information from documentation.

Official and Third-Party Projects

We provide an official go-sdk, a CLI tool called tea and an action runner for Gitea Action.

We maintain a list of Gitea-related projects at gitea/awesome-gitea, where you can discover more third-party projects, including SDKs, plugins, themes, and more.

Communication

If you have questions that are not covered by the documentation, you can get in contact with us on our Discord server or create a post in the discourse forum.

Authors

Backers

Thank you to all our backers! 🙏 [Become a backer]

Sponsors

Support this project by becoming a sponsor. Your logo will show up here with a link to your website. [Become a sponsor]

FAQ

How do you pronounce Gitea?

Gitea is pronounced /ɡɪti:/ as in "gi-tea" with a hard g.

Why is this not hosted on a Gitea instance?

We're working on it.

Where can I find the security patches?

In the release log or the change log, search for the keyword SECURITY to find the security patches.

License

This project is licensed under the MIT License. See the LICENSE file for the full license text.

Further information

Looking for an overview of the interface? Check it out!

Login/Register Page

Login Register

User Dashboard

Home Issues Pull Requests Milestones

User Profile

Profile

Explore

Repos Users Orgs

Repository

Home Commits Branches Labels Milestones Releases Tags

Repository Issue

List Issue

Repository Pull Requests

List Pull Request File Commits

Repository Actions

List Details

Repository Activity

Activity Contributors Code Frequency Recent Commits

Organization

Home

Description
Git with a cup of tea! Painless self-hosted all-in-one software development service, including Git hosting, code review, team collaboration, package registry and CI/CD
Readme MIT 1.1 GiB
v1.24.5 Latest
2025-08-13 10:59:29 -05:00
Languages
Go 78%
Handlebars 12.3%
TypeScript 4.6%
CSS 2%
JavaScript 1.4%
Other 1.6%