Skip to content

feat(actions)!: improve support for reusable workflows - #37478

Merged
silverwind merged 83 commits into
go-gitea:mainfrom
Zettat123:support-reusable-workflow
May 30, 2026
Merged

feat(actions)!: improve support for reusable workflows#37478
silverwind merged 83 commits into
go-gitea:mainfrom
Zettat123:support-reusable-workflow

Conversation

@Zettat123

@Zettat123 Zettat123 commented Apr 29, 2026

Copy link
Copy Markdown
Contributor

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

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

image image

References


Replace #36388

@GiteaBot GiteaBot added the lgtm/need 2 This PR needs two approvals by maintainers to be considered for merging. label Apr 29, 2026
@Zettat123
Zettat123 force-pushed the support-reusable-workflow branch 14 times, most recently from ceb3282 to 44a71d4 Compare May 6, 2026 04:05
@Zettat123
Zettat123 force-pushed the support-reusable-workflow branch 3 times, most recently from 7a7f54f to a8ba9e3 Compare May 7, 2026 02:18
@lunny lunny added the docs-update-needed The document needs to be updated synchronously label May 7, 2026
@Zettat123
Zettat123 force-pushed the support-reusable-workflow branch from a8ba9e3 to e23763d Compare May 7, 2026 05:25
@github-actions github-actions Bot removed the docs-update-needed The document needs to be updated synchronously label May 7, 2026
@silverwind silverwind added the topic/gitea-actions related to the actions of Gitea label May 7, 2026
@Zettat123
Zettat123 force-pushed the support-reusable-workflow branch 6 times, most recently from 707610e to 22c59d2 Compare May 8, 2026 04:00
@Zettat123 Zettat123 changed the title WIP: Improve support for reusable workflows feat(actions): improve support for reusable workflows May 8, 2026
silverwind added a commit that referenced this pull request May 29, 2026
…#37894) (#37899)

Backport #37894 by @Zettat123

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.


https://github.com/go-gitea/gitea/blob/428ee9fcce7928bf5405900345d43e9ba1b01564/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: Zettat123 <zettat123@gmail.com>
Co-authored-by: silverwind <me@silverwind.io>
Co-authored-by: Claude (Opus 4.8) <noreply@anthropic.com>
@Zettat123

Copy link
Copy Markdown
Contributor Author

@silverwind @bircni @lunny UI updated. Please review again.

Zettat123 and others added 2 commits May 29, 2026 14:17
… helper

Clarify the CanReadWorkflowCrossRepo `run.Repo.IsPrivate` guard: the real
reason is that the owner-level collaborative-owner grant would otherwise let
a public caller expose a private reusable workflow's content in a public run,
not GitHub parity (GitHub gates on the target repo).

Add an integration test that isolates the gate: a public caller is denied a
private target even with a collaborative-owner grant.

Make createRepoWorkflowFile take the caller's existing token instead of
logging in on every call, avoiding repeated bcrypt password verification.

Tighten verbose comments across the branch's tests.

Co-Authored-By: Claude (Opus 4.8) <noreply@anthropic.com>
@GiteaBot GiteaBot added lgtm/need 1 This PR needs approval from one additional maintainer to be merged. and removed lgtm/need 2 This PR needs two approvals by maintainers to be considered for merging. labels May 29, 2026
@silverwind

Copy link
Copy Markdown
Member

Checking CI failure

@silverwind

Copy link
Copy Markdown
Member

CI failures are unrelated.

@Zettat123

Copy link
Copy Markdown
Contributor Author

Seems like an ES service issue, should we rerun the failed tests?

@silverwind

silverwind commented May 29, 2026

Copy link
Copy Markdown
Member

I'll make a new PR to fix them. Re-run here is likely to suceed.

@silverwind

Copy link
Copy Markdown
Member

ES fixes are on #37906.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

lgtm/done This PR has enough approvals to get merged. There are no important open reservations anymore. pr/breaking Merging this PR means builds will break. Needs a description what exactly breaks, and how to fix it! topic/gitea-actions related to the actions of Gitea type/feature Completely new functionality. Can only be merged if feature freeze is not active.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants