[FEAT] Add support for dynamic matrix evaluation in Gitea Actions workflows#36564
[FEAT] Add support for dynamic matrix evaluation in Gitea Actions workflows#36564ZPascal wants to merge 12 commits intogo-gitea:mainfrom
Conversation
5c73067 to
aff60be
Compare
217663a to
bdb54c6
Compare
|
Tests are failing. And please stop force-pushing, we want to see the history of changes. |
There was a problem hiding this comment.
Pull request overview
This PR adds support for dynamic GitHub Actions-style matrix expansion in Gitea Actions by deferring matrix evaluation until upstream needs.<job>.outputs are available, and exposes related Prometheus metrics for observability.
Changes:
- Persist per-job raw
strategyYAML + anis_matrix_evaluatedflag so matrix expansion can be deferred until dependencies complete. - Re-evaluate/expand matrix jobs during the job resolution loop once
needsjobs have finished. - Add Prometheus collector + tests and an integration test demonstrating dynamic matrix expansion.
Reviewed changes
Copilot reviewed 11 out of 11 changed files in this pull request and generated 15 comments.
Show a summary per file
| File | Description |
|---|---|
| tests/integration/actions_job_test.go | Adds an integration test validating matrix expansion from a producer job’s outputs. |
| services/actions/run.go | Passes workflow content to insertion and stores raw strategy for deferred matrix evaluation. |
| services/actions/matrix.go | Implements raw strategy extraction and matrix re-evaluation/DB job creation. |
| services/actions/job_emitter.go | Hooks matrix re-evaluation into the blocked-job resolver and adds logging + job reload. |
| services/actions/matrix_metrics.go | Adds in-memory metrics tracking for re-evaluation performance. |
| services/actions/matrix_metrics_prometheus.go | Exposes the above stats via a Prometheus collector. |
| services/actions/matrix_metrics_test.go | Adds unit tests and a benchmark for the Prometheus collector. |
| routers/web/web.go | Registers the matrix metrics collector when metrics are enabled. |
| models/actions/run_job.go | Adds RawStrategy + IsMatrixEvaluated fields and a helper to insert multiple jobs. |
| models/migrations/v1_26/v326.go | Adds DB columns for raw strategy storage and matrix evaluation state. |
| models/migrations/migrations.go | Registers the new migration (v326). |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
|
|
||
| // If no new jobs were created, mark as evaluated | ||
| if len(newJobs) == 0 { | ||
| job.IsMatrixEvaluated = true |
There was a problem hiding this comment.
If no valid expanded jobs are produced (len(newJobs)==0), the code marks job.IsMatrixEvaluated in-memory only. Persist that flag (or mark the job terminal) to avoid re-running expansion every resolver iteration.
| job.IsMatrixEvaluated = true | |
| job.IsMatrixEvaluated = true | |
| if _, err := actions_model.UpdateRunJob(ctx, job, nil, "is_matrix_evaluated"); err != nil { | |
| log.Error("Failed to update job %d is_matrix_evaluated flag after empty matrix expansion: %v", job.ID, err) | |
| } |
There was a problem hiding this comment.
This looks like a design fault, parsing the whole workflow again just to set job.IsMatrixEvaluated = true
Hi @silverwind, as I've mentioned in the PR description, it is necessary to review/merge beforehand this PR. |
mode draft + temporary act dependency override via go.mod replace has been done multiple times for this to be
|
Signed-off-by: Pascal Zimmermann <pascal.zimmermann@theiotstudio.com>
bdb54c6 to
b000875
Compare
Signed-off-by: Pascal Zimmermann <pascal.zimmermann@theiotstudio.com>
|
Could you please not force push? This makes reviews harder to follow changes you make
|
Sometimes AI agents like to amend commits and force-push, so it might not be the author doing it, but I recently added instructions to AGENTS.md to not force-push, which may help. |
|
@ZPascal please also resolve the open copilot review comments above. |
I've used the rebase button of the GH UI. |
I don't like merge commits in a feature branch, and thank you for the hint, but I have not handled the rebase via an AI agent. |
|
Ok, just avoid rewriting git history after reviews have been given because reviewers need to see how their points were adressed. |
Signed-off-by: Pascal Zimmermann <pascal.zimmermann@theiotstudio.com>
Signed-off-by: Pascal Zimmermann <pascal.zimmermann@theiotstudio.com>
ChristopherHX
left a comment
There was a problem hiding this comment.
(this is my stale review that nobody has seen)
|
|
||
| // constructWorkflowWithNeeds creates a workflow YAML that includes the target job | ||
| // and stub definitions for its dependencies so the jobparser can resolve needs.*.outputs expressions | ||
| func constructWorkflowWithNeeds(job *actions_model.ActionRunJob, taskNeeds map[string]*TaskNeed) ([]byte, error) { |
There was a problem hiding this comment.
Ok, this is how you use the jobparser, this looks like a hack...
https://gitea.com/gitea/act/pulls/149#issuecomment-1079741
- The additional parsing is not something I really like...
There was a problem hiding this comment.
Idea to handle the case: The evaluation of the dynamic matrix can be performed before execution starts. @ChristopherHX, what do you think about this idea? Any other ideas?
|
|
||
| // If no new jobs were created, mark as evaluated | ||
| if len(newJobs) == 0 { | ||
| job.IsMatrixEvaluated = true |
There was a problem hiding this comment.
This looks like a design fault, parsing the whole workflow again just to set job.IsMatrixEvaluated = true
|
|
||
| // ExtractRawStrategies extracts strategy definitions from the raw workflow content | ||
| // Returns a map of jobID to strategy YAML for jobs that have matrix dependencies | ||
| func ExtractRawStrategies(content []byte) (map[string]string, error) { |
There was a problem hiding this comment.
This answers my question, where you get the RawStrategy...
But this design looks like we parse the workflow also for this again and again.
There was a problem hiding this comment.
The other option would be to analyze it once and use the raw strategy to evaluate whether a job output should be used for the subsequent matrix jobs.
|
BTW I just noticed the title and PR contains references to "GitHub Actions" but this is for "Gitea Actions". This is a common issue with AI which likes to confuse these names. Correct that and make you actually proof-read the content. |
I've adapted the title and the description. |
Signed-off-by: Pascal Zimmermann <pascal.zimmermann@theiotstudio.com>
|
I have two questions for this as I also touched this topic before:
|
|
Please run Also, check the test and failures. |
Signed-off-by: Pascal Zimmermann <pascal.zimmermann@theiotstudio.com>
|
We ran into this exact issue trying to use dynamic matrices in Gitea Actions. After tracing through the source code we confirmed the root cause: the act_runner executes one job at a time via PlanJob(jobID) and only receives the static YAML payload, so needs.<job>.outputs is never resolved when strategy.matrix is evaluated. |
I don't think so. I'll continue today to adapt the code. |
Signed-off-by: Pascal Zimmermann <pascal.zimmermann@theiotstudio.com>
Signed-off-by: Pascal Zimmermann <pascal.zimmermann@theiotstudio.com>
Signed-off-by: Pascal Zimmermann <pascal.zimmermann@theiotstudio.com>
Add support for dynamic matrix evaluation in Gitea Actions workflows
Description
This pull request adds support for dynamic matrix evaluation based on job outputs in Gitea Actions workflows. Workflows can now expand matrix strategies using outputs from dependent jobs, enabling more flexible and dynamic CI/CD pipelines.
The problem
Currently, workflow matrix strategies are evaluated statically at workflow creation time. There is no way to dynamically generate matrix values based on job outputs, which limits the flexibility of CI/CD workflows.
The solution
The implementation adds:
needs.<job>.outputs), the matrix is re-evaluated once those jobs completeFeatures
Supported workflow patterns
Prometheus metrics
When metrics are enabled, the following metrics are available at
/metrics:gitea_matrix_total_reevaluations- Total re-evaluation attemptsgitea_matrix_successful_reevaluations- Successful expansionsgitea_matrix_failed_reevaluations- Failed expansionsgitea_matrix_deferred_reevaluations- Evaluations waiting for dependenciesgitea_matrix_jobs_created_total- Total jobs created from matrix expansiongitea_matrix_total_reevaluation_time_ms- Cumulative evaluation timegitea_matrix_avg_reevaluation_time_ms- Average evaluation timegitea_matrix_total_parse_time_ms- Cumulative parse timegitea_matrix_avg_parse_time_ms- Average parse timegitea_matrix_total_insert_time_ms- Cumulative database insert timegitea_matrix_avg_insert_time_ms- Average insert timegitea_matrix_success_rate_percent- Evaluation success rate (0-100%)Backward compatibility
Testing
Checklist
Reviewer notes
[metrics].ENABLED = trueDepends on: