mirror of
https://codeberg.org/forgejo/forgejo.git
synced 2025-08-19 08:51:10 +00:00
This PR contains the following updates: | Package | Change | Age | Confidence | |---|---|---|---| | [code.forgejo.org/forgejo/act](https://code.forgejo.org/forgejo/act) | `v1.29.0` -> `v1.32.0` | [](https://docs.renovatebot.com/merge-confidence/) | [](https://docs.renovatebot.com/merge-confidence/) | --- ### Release Notes <details> <summary>forgejo/act (code.forgejo.org/forgejo/act)</summary> ### [`v1.32.0`](https://code.forgejo.org/forgejo/act/compare/v1.31.0...v1.32.0) [Compare Source](https://code.forgejo.org/forgejo/act/compare/v1.31.0...v1.32.0) ### [`v1.31.0`](https://code.forgejo.org/forgejo/act/compare/v1.30.0...v1.31.0) [Compare Source](https://code.forgejo.org/forgejo/act/compare/v1.30.0...v1.31.0) ### [`v1.30.0`](https://code.forgejo.org/forgejo/act/compare/v1.29.0...v1.30.0) [Compare Source](https://code.forgejo.org/forgejo/act/compare/v1.29.0...v1.30.0) </details> --- ### Configuration 📅 **Schedule**: Branch creation - Between 12:00 AM and 03:59 AM ( * 0-3 * * * ) (UTC), Automerge - Between 12:00 AM and 03:59 AM ( * 0-3 * * * ) (UTC). 🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied. ♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox. 🔕 **Ignore**: Close this PR and you won't be reminded about this update again. --- - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box --- This PR has been generated by [Renovate Bot](https://github.com/renovatebot/renovate). <!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0MS4yMy4yIiwidXBkYXRlZEluVmVyIjoiNDEuNDIuMiIsInRhcmdldEJyYW5jaCI6ImZvcmdlam8iLCJsYWJlbHMiOlsiZGVwZW5kZW5jeS11cGdyYWRlIiwidGVzdC9ub3QtbmVlZGVkIl19--> <!--start release-notes-assistant--> ## Release notes <!--URL:https://codeberg.org/forgejo/forgejo--> - Breaking features - [PR](https://codeberg.org/forgejo/forgejo/pulls/8502): <!--number 8502 --><!--line 0 --><!--description Rm9yZ2VqbyBBY3Rpb25zIHdvcmtmbG93cyBhcmUgdmVyaWZpZWQgd2l0aCBhIFlBTUwgc2NoZW1hIGFuZCBjb21tb24gZXJyb3JzIHN1Y2ggYXMgdXNpbmcgYW4gaW5jb3JyZWN0IGNvbnRleHQgKGUuZy4gYCR7eyBiYWRjb250ZXh0LkZPUkdFSk9fUkVQT1NJVE9SWSB9fWApIG9yIGEgdHlwbyBpbiBhIHJlcXVpcmVkIGtleXdvcmQgKGUuZy4gYHJ1aW5zLW9uOmAgaW5zdGVhZCBvZiBgcnVucy1vbjpgKSB3aWxsIGJlIHJlcG9ydGVkIGluIHRoZSBhY3Rpb24gcGFnZSBhbmQgdGhlIHdlYiBwYWdlIHRoYXQgZGlzcGxheXMgdGhlIGZpbGUgaW4gdGhlIHJlcG9zaXRvcnkuIEl0IGlzIHJlY29tbWVuZGVkIHRvIHZlcmlmeSBleGlzdGluZyB3b3JrZmxvd3MgYXJlIHN1Y2Nlc3NmdWxseSB2ZXJpZmllZCBwcmlvciB0byB1cGdyYWRpbmcsIFthcyBleHBsYWluZWQgaW4gdGhlIEZvcmdlam8gcnVubmVyIHJlbGVhc2Ugbm90ZXNdKGh0dHBzOi8vY29kZS5mb3JnZWpvLm9yZy9mb3JnZWpvL3J1bm5lci9zcmMvYnJhbmNoL21haW4vUkVMRUFTRS1OT1RFUy5tZCM4LTAtMCku-->Forgejo Actions workflows are verified with a YAML schema and common errors such as using an incorrect context (e.g. `${{ badcontext.FORGEJO_REPOSITORY }}`) or a typo in a required keyword (e.g. `ruins-on:` instead of `runs-on:`) will be reported in the action page and the web page that displays the file in the repository. It is recommended to verify existing workflows are successfully verified prior to upgrading, [as explained in the Forgejo runner release notes](https://code.forgejo.org/forgejo/runner/src/branch/main/RELEASE-NOTES.md#8-0-0).<!--description--> <!--end release-notes-assistant--> Co-authored-by: Earl Warren <contact@earl-warren.org> Reviewed-on: https://codeberg.org/forgejo/forgejo/pulls/8502 Reviewed-by: Michael Kriese <michael.kriese@gmx.de> Co-authored-by: Renovate Bot <forgejo-renovate-action@forgejo.org> Co-committed-by: Renovate Bot <forgejo-renovate-action@forgejo.org>
162 lines
4 KiB
Go
162 lines
4 KiB
Go
// Copyright 2022 The Gitea Authors. All rights reserved.
|
|
// SPDX-License-Identifier: MIT
|
|
|
|
package actions
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"fmt"
|
|
|
|
actions_model "forgejo.org/models/actions"
|
|
"forgejo.org/models/db"
|
|
"forgejo.org/modules/graceful"
|
|
"forgejo.org/modules/queue"
|
|
|
|
"github.com/nektos/act/pkg/jobparser"
|
|
"xorm.io/builder"
|
|
)
|
|
|
|
var jobEmitterQueue *queue.WorkerPoolQueue[*jobUpdate]
|
|
|
|
type jobUpdate struct {
|
|
RunID int64
|
|
}
|
|
|
|
func EmitJobsIfReady(runID int64) error {
|
|
err := jobEmitterQueue.Push(&jobUpdate{
|
|
RunID: runID,
|
|
})
|
|
if errors.Is(err, queue.ErrAlreadyInQueue) {
|
|
return nil
|
|
}
|
|
return err
|
|
}
|
|
|
|
func jobEmitterQueueHandler(items ...*jobUpdate) []*jobUpdate {
|
|
ctx := graceful.GetManager().ShutdownContext()
|
|
var ret []*jobUpdate
|
|
for _, update := range items {
|
|
if err := checkJobsOfRun(ctx, update.RunID); err != nil {
|
|
ret = append(ret, update)
|
|
}
|
|
}
|
|
return ret
|
|
}
|
|
|
|
func checkJobsOfRun(ctx context.Context, runID int64) error {
|
|
jobs, err := db.Find[actions_model.ActionRunJob](ctx, actions_model.FindRunJobOptions{RunID: runID})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if err := db.WithTx(ctx, func(ctx context.Context) error {
|
|
idToJobs := make(map[string][]*actions_model.ActionRunJob, len(jobs))
|
|
for _, job := range jobs {
|
|
idToJobs[job.JobID] = append(idToJobs[job.JobID], job)
|
|
}
|
|
|
|
updates := newJobStatusResolver(jobs).Resolve()
|
|
for _, job := range jobs {
|
|
if status, ok := updates[job.ID]; ok {
|
|
job.Status = status
|
|
if n, err := UpdateRunJob(ctx, job, builder.Eq{"status": actions_model.StatusBlocked}, "status"); err != nil {
|
|
return err
|
|
} else if n != 1 {
|
|
return fmt.Errorf("no affected for updating blocked job %v", job.ID)
|
|
}
|
|
}
|
|
}
|
|
return nil
|
|
}); err != nil {
|
|
return err
|
|
}
|
|
CreateCommitStatus(ctx, jobs...)
|
|
return nil
|
|
}
|
|
|
|
type jobStatusResolver struct {
|
|
statuses map[int64]actions_model.Status
|
|
needs map[int64][]int64
|
|
jobMap map[int64]*actions_model.ActionRunJob
|
|
}
|
|
|
|
func newJobStatusResolver(jobs actions_model.ActionJobList) *jobStatusResolver {
|
|
idToJobs := make(map[string][]*actions_model.ActionRunJob, len(jobs))
|
|
jobMap := make(map[int64]*actions_model.ActionRunJob)
|
|
for _, job := range jobs {
|
|
idToJobs[job.JobID] = append(idToJobs[job.JobID], job)
|
|
jobMap[job.ID] = job
|
|
}
|
|
|
|
statuses := make(map[int64]actions_model.Status, len(jobs))
|
|
needs := make(map[int64][]int64, len(jobs))
|
|
for _, job := range jobs {
|
|
statuses[job.ID] = job.Status
|
|
for _, need := range job.Needs {
|
|
for _, v := range idToJobs[need] {
|
|
needs[job.ID] = append(needs[job.ID], v.ID)
|
|
}
|
|
}
|
|
}
|
|
return &jobStatusResolver{
|
|
statuses: statuses,
|
|
needs: needs,
|
|
jobMap: jobMap,
|
|
}
|
|
}
|
|
|
|
func (r *jobStatusResolver) Resolve() map[int64]actions_model.Status {
|
|
ret := map[int64]actions_model.Status{}
|
|
for i := 0; i < len(r.statuses); i++ {
|
|
updated := r.resolve()
|
|
if len(updated) == 0 {
|
|
return ret
|
|
}
|
|
for k, v := range updated {
|
|
ret[k] = v
|
|
r.statuses[k] = v
|
|
}
|
|
}
|
|
return ret
|
|
}
|
|
|
|
func (r *jobStatusResolver) resolve() map[int64]actions_model.Status {
|
|
ret := map[int64]actions_model.Status{}
|
|
for id, status := range r.statuses {
|
|
if status != actions_model.StatusBlocked {
|
|
continue
|
|
}
|
|
allDone, allSucceed := true, true
|
|
for _, need := range r.needs[id] {
|
|
needStatus := r.statuses[need]
|
|
if !needStatus.IsDone() {
|
|
allDone = false
|
|
}
|
|
if needStatus.In(actions_model.StatusFailure, actions_model.StatusCancelled, actions_model.StatusSkipped) {
|
|
allSucceed = false
|
|
}
|
|
}
|
|
if allDone {
|
|
if allSucceed {
|
|
ret[id] = actions_model.StatusWaiting
|
|
} else {
|
|
// Check if the job has an "if" condition
|
|
hasIf := false
|
|
if wfJobs, _ := jobparser.Parse(r.jobMap[id].WorkflowPayload, false); len(wfJobs) == 1 {
|
|
_, wfJob := wfJobs[0].Job()
|
|
hasIf = len(wfJob.If.Value) > 0
|
|
}
|
|
|
|
if hasIf {
|
|
// act_runner will check the "if" condition
|
|
ret[id] = actions_model.StatusWaiting
|
|
} else {
|
|
// If the "if" condition is empty and not all dependent jobs completed successfully,
|
|
// the job should be skipped.
|
|
ret[id] = actions_model.StatusSkipped
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return ret
|
|
}
|