From 8d799c236c854c8bb132b38c97385beaf53d9327 Mon Sep 17 00:00:00 2001 From: badhezi Date: Tue, 15 Apr 2025 19:56:19 +0300 Subject: [PATCH 01/17] use the correct context data for PR link template in issue card --- templates/repo/issue/card.tmpl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/templates/repo/issue/card.tmpl b/templates/repo/issue/card.tmpl index c7bbe91885012..41fe6cea8fbae 100644 --- a/templates/repo/issue/card.tmpl +++ b/templates/repo/issue/card.tmpl @@ -45,7 +45,7 @@ {{if $.Page.LinkedPRs}} {{range index $.Page.LinkedPRs .ID}}
- + {{svg "octicon-git-merge" 16 "tw-mr-1 tw-align-middle"}} {{.Title}} #{{.Index}} From bea83a2328b94841a845e7888b716bcf22873506 Mon Sep 17 00:00:00 2001 From: badhezi Date: Sun, 27 Apr 2025 16:14:32 +0300 Subject: [PATCH 02/17] save test - revert me later --- go.mod | 2 +- go.sum | 4 ++-- services/actions/notifier_helper.go | 7 ++++++- 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/go.mod b/go.mod index a43a0a31114cb..d340dcc4d9812 100644 --- a/go.mod +++ b/go.mod @@ -317,7 +317,7 @@ replace github.com/hashicorp/go-version => github.com/6543/go-version v1.3.1 replace github.com/shurcooL/vfsgen => github.com/lunny/vfsgen v0.0.0-20220105142115-2c99e1ffdfa0 -replace github.com/nektos/act => gitea.com/gitea/act v0.261.4 +replace github.com/nektos/act => gitea.com/badhezi/act v0.0.1 // TODO: the only difference is in `PutObject`: the fork doesn't use `NewVerifyingReader(r, sha256.New(), oid, expectedSize)`, need to figure out why replace github.com/charmbracelet/git-lfs-transfer => gitea.com/gitea/git-lfs-transfer v0.2.0 diff --git a/go.sum b/go.sum index 9b200cc2d9477..605ad7c9bb311 100644 --- a/go.sum +++ b/go.sum @@ -14,8 +14,8 @@ dario.cat/mergo v1.0.1 h1:Ra4+bf83h2ztPIQYNP99R6m+Y7KfnARDfID+a+vLl4s= dario.cat/mergo v1.0.1/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk= filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA= filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= -gitea.com/gitea/act v0.261.4 h1:Tf9eLlvsYFtKcpuxlMvf9yT3g4Hshb2Beqw6C1STuH8= -gitea.com/gitea/act v0.261.4/go.mod h1:Pg5C9kQY1CEA3QjthjhlrqOC/QOT5NyWNjOjRHw23Ok= +gitea.com/badhezi/act v0.0.1 h1:lsJL7/BHco3XJyFqI1GJKc0VTX0TPxg/tvsUwAcRiKU= +gitea.com/badhezi/act v0.0.1/go.mod h1:Pg5C9kQY1CEA3QjthjhlrqOC/QOT5NyWNjOjRHw23Ok= gitea.com/gitea/git-lfs-transfer v0.2.0 h1:baHaNoBSRaeq/xKayEXwiDQtlIjps4Ac/Ll4KqLMB40= gitea.com/gitea/git-lfs-transfer v0.2.0/go.mod h1:UrXUCm3xLQkq15fu7qlXHUMlrhdlXHoi13KH2Dfiits= gitea.com/gitea/go-xsd-duration v0.0.0-20220703122237-02e73435a078 h1:BAFmdZpRW7zMQZQDClaCWobRj9uL1MR3MzpCVJvc5s4= diff --git a/services/actions/notifier_helper.go b/services/actions/notifier_helper.go index d179134798267..4d2b2fe98b104 100644 --- a/services/actions/notifier_helper.go +++ b/services/actions/notifier_helper.go @@ -28,6 +28,7 @@ import ( webhook_module "code.gitea.io/gitea/modules/webhook" "code.gitea.io/gitea/services/convert" notify_service "code.gitea.io/gitea/services/notify" + "gopkg.in/yaml.v3" "github.com/nektos/act/pkg/jobparser" "github.com/nektos/act/pkg/model" @@ -299,8 +300,12 @@ func handleWorkflows( } for _, dwf := range detectedWorkflows { + var yamlData map[string]any + if err := yaml.Unmarshal([]byte(dwf.Content), &yamlData); err != nil { + log.Fatal(err.Error()) + } run := &actions_model.ActionRun{ - Title: strings.SplitN(commit.CommitMessage, "\n", 2)[0], + Title: yamlData["run-name"].(string), RepoID: input.Repo.ID, OwnerID: input.Repo.OwnerID, WorkflowID: dwf.EntryName, From c791e73206a87218f60e0d4301e190da4243bde7 Mon Sep 17 00:00:00 2001 From: badhezi Date: Mon, 28 Apr 2025 17:08:16 +0300 Subject: [PATCH 03/17] Support run-name evaluation in action runs --- go.mod | 2 +- services/actions/notifier_helper.go | 72 ++++++++++++++++++++++-- services/actions/workflow.go | 14 +++++ web_src/js/components/RepoActionView.vue | 4 +- 4 files changed, 84 insertions(+), 8 deletions(-) diff --git a/go.mod b/go.mod index d340dcc4d9812..a43a0a31114cb 100644 --- a/go.mod +++ b/go.mod @@ -317,7 +317,7 @@ replace github.com/hashicorp/go-version => github.com/6543/go-version v1.3.1 replace github.com/shurcooL/vfsgen => github.com/lunny/vfsgen v0.0.0-20220105142115-2c99e1ffdfa0 -replace github.com/nektos/act => gitea.com/badhezi/act v0.0.1 +replace github.com/nektos/act => gitea.com/gitea/act v0.261.4 // TODO: the only difference is in `PutObject`: the fork doesn't use `NewVerifyingReader(r, sha256.New(), oid, expectedSize)`, need to figure out why replace github.com/charmbracelet/git-lfs-transfer => gitea.com/gitea/git-lfs-transfer v0.2.0 diff --git a/services/actions/notifier_helper.go b/services/actions/notifier_helper.go index 4d2b2fe98b104..438dff2d1db7f 100644 --- a/services/actions/notifier_helper.go +++ b/services/actions/notifier_helper.go @@ -30,6 +30,7 @@ import ( notify_service "code.gitea.io/gitea/services/notify" "gopkg.in/yaml.v3" + "github.com/nektos/act/pkg/exprparser" "github.com/nektos/act/pkg/jobparser" "github.com/nektos/act/pkg/model" ) @@ -300,16 +301,14 @@ func handleWorkflows( } for _, dwf := range detectedWorkflows { - var yamlData map[string]any - if err := yaml.Unmarshal([]byte(dwf.Content), &yamlData); err != nil { - log.Fatal(err.Error()) - } run := &actions_model.ActionRun{ - Title: yamlData["run-name"].(string), + Title: strings.SplitN(commit.CommitMessage, "\n", 2)[0], RepoID: input.Repo.ID, + Repo: input.Repo, OwnerID: input.Repo.OwnerID, WorkflowID: dwf.EntryName, TriggerUserID: input.Doer.ID, + TriggerUser: input.Doer, Ref: ref, CommitSHA: commit.ID.String(), IsForkPullRequest: isForkPullRequest, @@ -319,6 +318,11 @@ func handleWorkflows( Status: actions_model.StatusWaiting, } + if err := EvaluateExpressionsForRun(run, dwf); err != nil { + log.Error("EvaluateExpressionsForRun: %v", err) + continue + } + need, err := ifNeedApproval(ctx, run, input.Repo, input.Doer) if err != nil { log.Error("check if need approval for repo %d with user %d: %v", input.Repo.ID, input.Doer.ID, err) @@ -523,6 +527,11 @@ func handleSchedules( Specs: schedules, Content: dwf.Content, } + + if runName, err := parseRunNameFromDetectedWorkflow(dwf); err == nil { + run.Title = runName + } + crons = append(crons, run) } @@ -561,3 +570,56 @@ func DetectAndHandleSchedules(ctx context.Context, repo *repo_model.Repository) return handleSchedules(ctx, scheduleWorkflows, commit, notifyInput, repo.DefaultBranch) } + +func newExpressionEvaluatorForRun(r *actions_model.ActionRun) (*jobparser.ExpressionEvaluator, error) { + ghCtx := &model.GithubContext{} + gitCtx := GenerateGiteaContext(r, nil) + + gitCtxRaw, err := json.Marshal(gitCtx) + if err != nil { + log.Error("NewInterpolatorForRun: %v", err) + return nil, err + } + + err = json.Unmarshal(gitCtxRaw, ghCtx) + if err != nil { + log.Error("NewInterpolatorForRun: %v", err) + return nil, err + } + + interp := exprparser.NewInterpeter(&exprparser.EvaluationEnvironment{Github: ghCtx}, exprparser.Config{}) + ee := jobparser.NewExpressionEvaluator(interp) + return ee, nil +} + +func parseRunNameFromDetectedWorkflow(w *actions_module.DetectedWorkflow) (string, error) { + var data map[string]any + var value string + + if err := yaml.Unmarshal([]byte(w.Content), &data); err != nil { + log.Error("parseRunNameFromDetectedWorkflow: %v", err) + return "", err + } + + if v, ok := data["run-name"]; !ok { + return "", fmt.Errorf("run-name not found in workflow") + } else { + value = v.(string) + } + + return value, nil +} + +func EvaluateExpressionsForRun(r *actions_model.ActionRun, w *actions_module.DetectedWorkflow) error { + if runName, err := parseRunNameFromDetectedWorkflow(w); err == nil { + ee, err := newExpressionEvaluatorForRun(r) + if err != nil { + log.Error("newExpressionEvaluatorForRun: %v", err) + return err + } + r.Title = ee.Interpolate(runName) + } else { + log.Error("parseRunNameFromDetectedWorkflow: %v", err) + } + return nil +} diff --git a/services/actions/workflow.go b/services/actions/workflow.go index dc8a1dd34924f..09c1d1bdd6b2b 100644 --- a/services/actions/workflow.go +++ b/services/actions/workflow.go @@ -18,6 +18,7 @@ import ( "code.gitea.io/gitea/models/unit" user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/actions" + actions_module "code.gitea.io/gitea/modules/actions" "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/reqctx" @@ -192,6 +193,8 @@ func DispatchActionWorkflow(ctx reqctx.RequestContext, doer *user_model.User, re // find workflow from commit var workflows []*jobparser.SingleWorkflow + dwf := &actions_module.DetectedWorkflow{} + for _, entry := range entries { if entry.Name() != workflowID { continue @@ -201,10 +204,15 @@ func DispatchActionWorkflow(ctx reqctx.RequestContext, doer *user_model.User, re if err != nil { return err } + workflows, err = jobparser.Parse(content) if err != nil { return err } + + dwf.Content = content + dwf.EntryName = entry.Name() + break } @@ -244,9 +252,11 @@ func DispatchActionWorkflow(ctx reqctx.RequestContext, doer *user_model.User, re run := &actions_model.ActionRun{ Title: strings.SplitN(runTargetCommit.CommitMessage, "\n", 2)[0], RepoID: repo.ID, + Repo: repo, OwnerID: repo.OwnerID, WorkflowID: workflowID, TriggerUserID: doer.ID, + TriggerUser: doer, Ref: string(refName), CommitSHA: runTargetCommit.ID.String(), IsForkPullRequest: false, @@ -256,6 +266,10 @@ func DispatchActionWorkflow(ctx reqctx.RequestContext, doer *user_model.User, re Status: actions_model.StatusWaiting, } + if err := EvaluateExpressionsForRun(run, dwf); err != nil { + log.Error("EvaluateExpressionsForRun: %v", err) + } + // cancel running jobs of the same workflow if err := CancelPreviousJobs( ctx, diff --git a/web_src/js/components/RepoActionView.vue b/web_src/js/components/RepoActionView.vue index af300622b46e8..5021e25ad331c 100644 --- a/web_src/js/components/RepoActionView.vue +++ b/web_src/js/components/RepoActionView.vue @@ -346,11 +346,11 @@ export default defineComponent({ const isFirstLoad = !this.run.status; const job = await this.fetchJobData(abortController); if (this.loadingAbortController !== abortController) return; - + console.log(job) this.artifacts = job.artifacts || []; this.run = job.state.run; this.currentJob = job.state.currentJob; - + console.log(this.currentJob) // sync the currentJobStepsStates to store the job step states for (let i = 0; i < this.currentJob.steps.length; i++) { const expanded = isFirstLoad && this.optionAlwaysExpandRunning && this.currentJob.steps[i].status === 'running'; From 52b29192b9942fd9b147793531f239ce1db7d546 Mon Sep 17 00:00:00 2001 From: badhezi Date: Mon, 28 Apr 2025 17:15:16 +0300 Subject: [PATCH 04/17] remove redundant prints --- web_src/js/components/RepoActionView.vue | 2 -- 1 file changed, 2 deletions(-) diff --git a/web_src/js/components/RepoActionView.vue b/web_src/js/components/RepoActionView.vue index 5021e25ad331c..8f4907803f957 100644 --- a/web_src/js/components/RepoActionView.vue +++ b/web_src/js/components/RepoActionView.vue @@ -346,11 +346,9 @@ export default defineComponent({ const isFirstLoad = !this.run.status; const job = await this.fetchJobData(abortController); if (this.loadingAbortController !== abortController) return; - console.log(job) this.artifacts = job.artifacts || []; this.run = job.state.run; this.currentJob = job.state.currentJob; - console.log(this.currentJob) // sync the currentJobStepsStates to store the job step states for (let i = 0; i < this.currentJob.steps.length; i++) { const expanded = isFirstLoad && this.optionAlwaysExpandRunning && this.currentJob.steps[i].status === 'running'; From 48984c90715eeb66f7479685b27f5a231ef94f79 Mon Sep 17 00:00:00 2001 From: badhezi Date: Mon, 28 Apr 2025 18:09:53 +0300 Subject: [PATCH 05/17] lowercase function name --- services/actions/notifier_helper.go | 6 +++--- services/actions/workflow.go | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/services/actions/notifier_helper.go b/services/actions/notifier_helper.go index 438dff2d1db7f..f7a438cb5869c 100644 --- a/services/actions/notifier_helper.go +++ b/services/actions/notifier_helper.go @@ -318,8 +318,8 @@ func handleWorkflows( Status: actions_model.StatusWaiting, } - if err := EvaluateExpressionsForRun(run, dwf); err != nil { - log.Error("EvaluateExpressionsForRun: %v", err) + if err := evaluateExpressionsForRun(run, dwf); err != nil { + log.Error("evaluateExpressionsForRun: %v", err) continue } @@ -610,7 +610,7 @@ func parseRunNameFromDetectedWorkflow(w *actions_module.DetectedWorkflow) (strin return value, nil } -func EvaluateExpressionsForRun(r *actions_model.ActionRun, w *actions_module.DetectedWorkflow) error { +func evaluateExpressionsForRun(r *actions_model.ActionRun, w *actions_module.DetectedWorkflow) error { if runName, err := parseRunNameFromDetectedWorkflow(w); err == nil { ee, err := newExpressionEvaluatorForRun(r) if err != nil { diff --git a/services/actions/workflow.go b/services/actions/workflow.go index 09c1d1bdd6b2b..f00402740f71e 100644 --- a/services/actions/workflow.go +++ b/services/actions/workflow.go @@ -266,8 +266,8 @@ func DispatchActionWorkflow(ctx reqctx.RequestContext, doer *user_model.User, re Status: actions_model.StatusWaiting, } - if err := EvaluateExpressionsForRun(run, dwf); err != nil { - log.Error("EvaluateExpressionsForRun: %v", err) + if err := evaluateExpressionsForRun(run, dwf); err != nil { + log.Error("evaluateExpressionsForRun: %v", err) } // cancel running jobs of the same workflow From 99b277e9a54ad30e82d107edd26824f962a44327 Mon Sep 17 00:00:00 2001 From: badhezi Date: Mon, 28 Apr 2025 18:21:04 +0300 Subject: [PATCH 06/17] revert redundant change --- web_src/js/components/RepoActionView.vue | 2 ++ 1 file changed, 2 insertions(+) diff --git a/web_src/js/components/RepoActionView.vue b/web_src/js/components/RepoActionView.vue index 8f4907803f957..c8e227d1cb3ab 100644 --- a/web_src/js/components/RepoActionView.vue +++ b/web_src/js/components/RepoActionView.vue @@ -346,9 +346,11 @@ export default defineComponent({ const isFirstLoad = !this.run.status; const job = await this.fetchJobData(abortController); if (this.loadingAbortController !== abortController) return; + this.artifacts = job.artifacts || []; this.run = job.state.run; this.currentJob = job.state.currentJob; + // sync the currentJobStepsStates to store the job step states for (let i = 0; i < this.currentJob.steps.length; i++) { const expanded = isFirstLoad && this.optionAlwaysExpandRunning && this.currentJob.steps[i].status === 'running'; From acb502a542e84271e6b3e8a4a28393467d54d590 Mon Sep 17 00:00:00 2001 From: badhezi Date: Mon, 28 Apr 2025 18:21:21 +0300 Subject: [PATCH 07/17] revert redundant change --- web_src/js/components/RepoActionView.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web_src/js/components/RepoActionView.vue b/web_src/js/components/RepoActionView.vue index c8e227d1cb3ab..af300622b46e8 100644 --- a/web_src/js/components/RepoActionView.vue +++ b/web_src/js/components/RepoActionView.vue @@ -350,7 +350,7 @@ export default defineComponent({ this.artifacts = job.artifacts || []; this.run = job.state.run; this.currentJob = job.state.currentJob; - + // sync the currentJobStepsStates to store the job step states for (let i = 0; i < this.currentJob.steps.length; i++) { const expanded = isFirstLoad && this.optionAlwaysExpandRunning && this.currentJob.steps[i].status === 'running'; From e12e843201d800282cadc1e13b3bb28003ff235a Mon Sep 17 00:00:00 2001 From: badhezi Date: Mon, 28 Apr 2025 19:16:52 +0300 Subject: [PATCH 08/17] fix lint errors --- services/actions/notifier_helper.go | 8 ++++---- services/actions/workflow.go | 3 +-- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/services/actions/notifier_helper.go b/services/actions/notifier_helper.go index f7a438cb5869c..fa1ddebd7f690 100644 --- a/services/actions/notifier_helper.go +++ b/services/actions/notifier_helper.go @@ -596,15 +596,15 @@ func parseRunNameFromDetectedWorkflow(w *actions_module.DetectedWorkflow) (strin var data map[string]any var value string - if err := yaml.Unmarshal([]byte(w.Content), &data); err != nil { + if err := yaml.Unmarshal(w.Content, &data); err != nil { log.Error("parseRunNameFromDetectedWorkflow: %v", err) return "", err } - if v, ok := data["run-name"]; !ok { - return "", fmt.Errorf("run-name not found in workflow") - } else { + if v, ok := data["run-name"]; ok { value = v.(string) + } else { + return "", fmt.Errorf("run-name not found in workflow") } return value, nil diff --git a/services/actions/workflow.go b/services/actions/workflow.go index f00402740f71e..bf26b79cfaf0e 100644 --- a/services/actions/workflow.go +++ b/services/actions/workflow.go @@ -18,7 +18,6 @@ import ( "code.gitea.io/gitea/models/unit" user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/actions" - actions_module "code.gitea.io/gitea/modules/actions" "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/reqctx" @@ -193,7 +192,7 @@ func DispatchActionWorkflow(ctx reqctx.RequestContext, doer *user_model.User, re // find workflow from commit var workflows []*jobparser.SingleWorkflow - dwf := &actions_module.DetectedWorkflow{} + dwf := &actions.DetectedWorkflow{} for _, entry := range entries { if entry.Name() != workflowID { From 52664edc704bcc3c45f6a8dad050a823dca60c56 Mon Sep 17 00:00:00 2001 From: badhezi Date: Tue, 29 Apr 2025 12:45:06 +0300 Subject: [PATCH 09/17] move code to act/jobparser, support scheduled actions --- models/actions/utils.go | 16 +++++++++ services/actions/notifier_helper.go | 54 +++++++---------------------- services/actions/workflow.go | 6 ++-- 3 files changed, 33 insertions(+), 43 deletions(-) diff --git a/models/actions/utils.go b/models/actions/utils.go index 12657942fc24f..c6d5769d9c553 100644 --- a/models/actions/utils.go +++ b/models/actions/utils.go @@ -82,3 +82,19 @@ func calculateDuration(started, stopped timeutil.TimeStamp, status Status) time. } return timeSince(s).Truncate(time.Second) } + +func (s *ActionSchedule) ToActionRun() *ActionRun { + return &ActionRun{ + Title: s.Title, + RepoID: s.RepoID, + Repo: s.Repo, + OwnerID: s.OwnerID, + WorkflowID: s.WorkflowID, + TriggerUserID: s.TriggerUserID, + TriggerUser: s.TriggerUser, + Ref: s.Ref, + CommitSHA: s.CommitSHA, + Event: s.Event, + EventPayload: s.EventPayload, + } +} diff --git a/services/actions/notifier_helper.go b/services/actions/notifier_helper.go index fa1ddebd7f690..34c9cc60ffa89 100644 --- a/services/actions/notifier_helper.go +++ b/services/actions/notifier_helper.go @@ -28,9 +28,7 @@ import ( webhook_module "code.gitea.io/gitea/modules/webhook" "code.gitea.io/gitea/services/convert" notify_service "code.gitea.io/gitea/services/notify" - "gopkg.in/yaml.v3" - "github.com/nektos/act/pkg/exprparser" "github.com/nektos/act/pkg/jobparser" "github.com/nektos/act/pkg/model" ) @@ -318,7 +316,9 @@ func handleWorkflows( Status: actions_model.StatusWaiting, } - if err := evaluateExpressionsForRun(run, dwf); err != nil { + if runName, err := parseRunName(run, dwf); err == nil { + run.Title = runName + } else { log.Error("evaluateExpressionsForRun: %v", err) continue } @@ -517,9 +517,11 @@ func handleSchedules( run := &actions_model.ActionSchedule{ Title: strings.SplitN(commit.CommitMessage, "\n", 2)[0], RepoID: input.Repo.ID, + Repo: input.Repo, OwnerID: input.Repo.OwnerID, WorkflowID: dwf.EntryName, TriggerUserID: user_model.ActionsUserID, + TriggerUser: user_model.NewActionsUser(), Ref: ref, CommitSHA: commit.ID.String(), Event: input.Event, @@ -528,8 +530,10 @@ func handleSchedules( Content: dwf.Content, } - if runName, err := parseRunNameFromDetectedWorkflow(dwf); err == nil { + if runName, err := parseRunName(run.ToActionRun(), dwf); err == nil { run.Title = runName + } else { + log.Error("ParseRunName: %v", err) } crons = append(crons, run) @@ -571,55 +575,23 @@ func DetectAndHandleSchedules(ctx context.Context, repo *repo_model.Repository) return handleSchedules(ctx, scheduleWorkflows, commit, notifyInput, repo.DefaultBranch) } -func newExpressionEvaluatorForRun(r *actions_model.ActionRun) (*jobparser.ExpressionEvaluator, error) { +func parseRunName(r *actions_model.ActionRun, w *actions_module.DetectedWorkflow) (string, error) { ghCtx := &model.GithubContext{} gitCtx := GenerateGiteaContext(r, nil) gitCtxRaw, err := json.Marshal(gitCtx) if err != nil { log.Error("NewInterpolatorForRun: %v", err) - return nil, err + return "", err } err = json.Unmarshal(gitCtxRaw, ghCtx) if err != nil { log.Error("NewInterpolatorForRun: %v", err) - return nil, err - } - - interp := exprparser.NewInterpeter(&exprparser.EvaluationEnvironment{Github: ghCtx}, exprparser.Config{}) - ee := jobparser.NewExpressionEvaluator(interp) - return ee, nil -} - -func parseRunNameFromDetectedWorkflow(w *actions_module.DetectedWorkflow) (string, error) { - var data map[string]any - var value string - - if err := yaml.Unmarshal(w.Content, &data); err != nil { - log.Error("parseRunNameFromDetectedWorkflow: %v", err) return "", err } - if v, ok := data["run-name"]; ok { - value = v.(string) - } else { - return "", fmt.Errorf("run-name not found in workflow") - } - - return value, nil -} - -func evaluateExpressionsForRun(r *actions_model.ActionRun, w *actions_module.DetectedWorkflow) error { - if runName, err := parseRunNameFromDetectedWorkflow(w); err == nil { - ee, err := newExpressionEvaluatorForRun(r) - if err != nil { - log.Error("newExpressionEvaluatorForRun: %v", err) - return err - } - r.Title = ee.Interpolate(runName) - } else { - log.Error("parseRunNameFromDetectedWorkflow: %v", err) - } - return nil + title, _ := jobparser.ParseRunName(w.Content, jobparser.WithGitContext(ghCtx)) + log.Info("title: %s", title) + return title, nil } diff --git a/services/actions/workflow.go b/services/actions/workflow.go index bf26b79cfaf0e..ce311baa41796 100644 --- a/services/actions/workflow.go +++ b/services/actions/workflow.go @@ -265,8 +265,10 @@ func DispatchActionWorkflow(ctx reqctx.RequestContext, doer *user_model.User, re Status: actions_model.StatusWaiting, } - if err := evaluateExpressionsForRun(run, dwf); err != nil { - log.Error("evaluateExpressionsForRun: %v", err) + if runName, err := parseRunName(run, dwf); err == nil { + run.Title = runName + } else { + log.Error("ParseRunName: %v", err) } // cancel running jobs of the same workflow From a2fa2396ee55b7ffe2181d3f3305ac8cfc6541e6 Mon Sep 17 00:00:00 2001 From: badhezi Date: Tue, 29 Apr 2025 13:11:01 +0300 Subject: [PATCH 10/17] use pseudo-version of act --- go.mod | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/go.mod b/go.mod index a43a0a31114cb..021ad3eba2584 100644 --- a/go.mod +++ b/go.mod @@ -317,7 +317,7 @@ replace github.com/hashicorp/go-version => github.com/6543/go-version v1.3.1 replace github.com/shurcooL/vfsgen => github.com/lunny/vfsgen v0.0.0-20220105142115-2c99e1ffdfa0 -replace github.com/nektos/act => gitea.com/gitea/act v0.261.4 +replace github.com/nektos/act => gitea.com/badhezi/act v0.0.0-20250429095415-d27028e1df50 // TODO: the only difference is in `PutObject`: the fork doesn't use `NewVerifyingReader(r, sha256.New(), oid, expectedSize)`, need to figure out why replace github.com/charmbracelet/git-lfs-transfer => gitea.com/gitea/git-lfs-transfer v0.2.0 From bf06b4077e4489b5fa1fc68ada0d06608ce382f0 Mon Sep 17 00:00:00 2001 From: badhezi Date: Tue, 29 Apr 2025 15:20:39 +0300 Subject: [PATCH 11/17] update act --- go.sum | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/go.sum b/go.sum index 605ad7c9bb311..10542584456d5 100644 --- a/go.sum +++ b/go.sum @@ -14,8 +14,8 @@ dario.cat/mergo v1.0.1 h1:Ra4+bf83h2ztPIQYNP99R6m+Y7KfnARDfID+a+vLl4s= dario.cat/mergo v1.0.1/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk= filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA= filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= -gitea.com/badhezi/act v0.0.1 h1:lsJL7/BHco3XJyFqI1GJKc0VTX0TPxg/tvsUwAcRiKU= -gitea.com/badhezi/act v0.0.1/go.mod h1:Pg5C9kQY1CEA3QjthjhlrqOC/QOT5NyWNjOjRHw23Ok= +gitea.com/badhezi/act v0.0.0-20250429095415-d27028e1df50 h1:46UPmv+pLMBd2TR/N/hKpWY3SloOlVusmZg6SmpcfbE= +gitea.com/badhezi/act v0.0.0-20250429095415-d27028e1df50/go.mod h1:Pg5C9kQY1CEA3QjthjhlrqOC/QOT5NyWNjOjRHw23Ok= gitea.com/gitea/git-lfs-transfer v0.2.0 h1:baHaNoBSRaeq/xKayEXwiDQtlIjps4Ac/Ll4KqLMB40= gitea.com/gitea/git-lfs-transfer v0.2.0/go.mod h1:UrXUCm3xLQkq15fu7qlXHUMlrhdlXHoi13KH2Dfiits= gitea.com/gitea/go-xsd-duration v0.0.0-20220703122237-02e73435a078 h1:BAFmdZpRW7zMQZQDClaCWobRj9uL1MR3MzpCVJvc5s4= From 53d9753f9d7f8fe286106a81b47893121e7d079a Mon Sep 17 00:00:00 2001 From: badhezi Date: Tue, 29 Apr 2025 15:59:01 +0300 Subject: [PATCH 12/17] fix integration tests --- tests/integration/actions_trigger_test.go | 136 +++++++++++++--------- 1 file changed, 82 insertions(+), 54 deletions(-) diff --git a/tests/integration/actions_trigger_test.go b/tests/integration/actions_trigger_test.go index f576dc38abf7f..ed6dedd016e14 100644 --- a/tests/integration/actions_trigger_test.go +++ b/tests/integration/actions_trigger_test.go @@ -414,12 +414,15 @@ jobs: err = repo_service.CreateNewBranchFromCommit(db.DefaultContext, user2, repo, gitRepo, branch.CommitID, "test-create-branch") assert.NoError(t, err) run := unittest.AssertExistsAndLoadBean(t, &actions_model.ActionRun{ - Title: "add workflow", - RepoID: repo.ID, - Event: "create", - Ref: "refs/heads/test-create-branch", - WorkflowID: "createdelete.yml", - CommitSHA: branch.CommitID, + Title: "add workflow", + RepoID: repo.ID, + Repo: repo, + Event: "create", + Ref: "refs/heads/test-create-branch", + WorkflowID: "createdelete.yml", + CommitSHA: branch.CommitID, + TriggerUserID: user2.ID, + TriggerUser: user2, }) assert.NotNil(t, run) @@ -427,12 +430,15 @@ jobs: err = release_service.CreateNewTag(db.DefaultContext, user2, repo, branch.CommitID, "test-create-tag", "test create tag event") assert.NoError(t, err) run = unittest.AssertExistsAndLoadBean(t, &actions_model.ActionRun{ - Title: "add workflow", - RepoID: repo.ID, - Event: "create", - Ref: "refs/tags/test-create-tag", - WorkflowID: "createdelete.yml", - CommitSHA: branch.CommitID, + Title: "add workflow", + RepoID: repo.ID, + Repo: repo, + Event: "create", + Ref: "refs/tags/test-create-tag", + WorkflowID: "createdelete.yml", + CommitSHA: branch.CommitID, + TriggerUserID: user2.ID, + TriggerUser: user2, }) assert.NotNil(t, run) @@ -440,12 +446,15 @@ jobs: err = repo_service.DeleteBranch(db.DefaultContext, user2, repo, gitRepo, "test-create-branch", nil) assert.NoError(t, err) run = unittest.AssertExistsAndLoadBean(t, &actions_model.ActionRun{ - Title: "add workflow", - RepoID: repo.ID, - Event: "delete", - Ref: "refs/heads/main", - WorkflowID: "createdelete.yml", - CommitSHA: branch.CommitID, + Title: "add workflow", + RepoID: repo.ID, + Repo: repo, + Event: "delete", + Ref: "refs/heads/main", + WorkflowID: "createdelete.yml", + CommitSHA: branch.CommitID, + TriggerUserID: user2.ID, + TriggerUser: user2, }) assert.NotNil(t, run) @@ -455,12 +464,15 @@ jobs: err = release_service.DeleteReleaseByID(db.DefaultContext, repo, tag, user2, true) assert.NoError(t, err) run = unittest.AssertExistsAndLoadBean(t, &actions_model.ActionRun{ - Title: "add workflow", - RepoID: repo.ID, - Event: "delete", - Ref: "refs/heads/main", - WorkflowID: "createdelete.yml", - CommitSHA: branch.CommitID, + Title: "add workflow", + RepoID: repo.ID, + Repo: repo, + Event: "delete", + Ref: "refs/heads/main", + WorkflowID: "createdelete.yml", + CommitSHA: branch.CommitID, + TriggerUserID: user2.ID, + TriggerUser: user2, }) assert.NotNil(t, run) }) @@ -762,12 +774,15 @@ jobs: _ = MakeRequest(t, req, http.StatusNoContent) run := unittest.AssertExistsAndLoadBean(t, &actions_model.ActionRun{ - Title: "add workflow", - RepoID: repo.ID, - Event: "workflow_dispatch", - Ref: "refs/heads/main", - WorkflowID: "dispatch.yml", - CommitSHA: branch.CommitID, + Title: "add workflow", + RepoID: repo.ID, + Repo: repo, + Event: "workflow_dispatch", + Ref: "refs/heads/main", + WorkflowID: "dispatch.yml", + CommitSHA: branch.CommitID, + TriggerUserID: user2.ID, + TriggerUser: user2, }) assert.NotNil(t, run) }) @@ -844,12 +859,15 @@ jobs: _ = MakeRequest(t, req, http.StatusNoContent) run := unittest.AssertExistsAndLoadBean(t, &actions_model.ActionRun{ - Title: "add workflow", - RepoID: repo.ID, - Event: "workflow_dispatch", - Ref: "refs/heads/main", - WorkflowID: "dispatch.yml", - CommitSHA: branch.CommitID, + Title: "add workflow", + RepoID: repo.ID, + Repo: repo, + Event: "workflow_dispatch", + Ref: "refs/heads/main", + WorkflowID: "dispatch.yml", + CommitSHA: branch.CommitID, + TriggerUserID: user2.ID, + TriggerUser: user2, }) assert.NotNil(t, run) dispatchPayload := &api.WorkflowDispatchPayload{} @@ -939,12 +957,15 @@ jobs: _ = MakeRequest(t, req, http.StatusNoContent) run := unittest.AssertExistsAndLoadBean(t, &actions_model.ActionRun{ - Title: "add workflow", - RepoID: repo.ID, - Event: "workflow_dispatch", - Ref: "refs/heads/main", - WorkflowID: "dispatch.yml", - CommitSHA: branch.CommitID, + Title: "add workflow", + RepoID: repo.ID, + Repo: repo, + Event: "workflow_dispatch", + Ref: "refs/heads/main", + WorkflowID: "dispatch.yml", + CommitSHA: branch.CommitID, + TriggerUserID: user2.ID, + TriggerUser: user2, }) assert.NotNil(t, run) }) @@ -1024,12 +1045,15 @@ jobs: _ = MakeRequest(t, req, http.StatusNoContent) run := unittest.AssertExistsAndLoadBean(t, &actions_model.ActionRun{ - Title: "add workflow", - RepoID: repo.ID, - Event: "workflow_dispatch", - Ref: "refs/heads/main", - WorkflowID: "dispatch.yml", - CommitSHA: branch.CommitID, + Title: "add workflow", + RepoID: repo.ID, + Repo: repo, + Event: "workflow_dispatch", + Ref: "refs/heads/main", + WorkflowID: "dispatch.yml", + CommitSHA: branch.CommitID, + TriggerUserID: user2.ID, + TriggerUser: user2, }) assert.NotNil(t, run) dispatchPayload := &api.WorkflowDispatchPayload{} @@ -1156,6 +1180,7 @@ jobs: run := unittest.AssertExistsAndLoadBean(t, &actions_model.ActionRun{ Title: "add workflow", RepoID: repo.ID, + Repo: repo, Event: "workflow_dispatch", Ref: "refs/heads/dispatch", WorkflowID: "dispatch.yml", @@ -1351,12 +1376,15 @@ jobs: _ = MakeRequest(t, req, http.StatusNoContent) run := unittest.AssertExistsAndLoadBean(t, &actions_model.ActionRun{ - Title: "add workflow", - RepoID: repo.ID, - Event: "workflow_dispatch", - Ref: "refs/heads/main", - WorkflowID: "dispatch.yml", - CommitSHA: branch.CommitID, + Title: "add workflow", + RepoID: repo.ID, + Repo: repo, + Event: "workflow_dispatch", + Ref: "refs/heads/main", + WorkflowID: "dispatch.yml", + CommitSHA: branch.CommitID, + TriggerUserID: user2.ID, + TriggerUser: user2, }) assert.NotNil(t, run) dispatchPayload := &api.WorkflowDispatchPayload{} From 318bf1c4845e67b7fdcddc53412cc8ffc0315d3a Mon Sep 17 00:00:00 2001 From: badhezi Date: Wed, 30 Apr 2025 09:55:06 +0300 Subject: [PATCH 13/17] fix error handling and revert changes to test files --- services/actions/notifier_helper.go | 13 +-- tests/integration/actions_trigger_test.go | 135 +++++++++------------- 2 files changed, 60 insertions(+), 88 deletions(-) diff --git a/services/actions/notifier_helper.go b/services/actions/notifier_helper.go index 34c9cc60ffa89..288361148156c 100644 --- a/services/actions/notifier_helper.go +++ b/services/actions/notifier_helper.go @@ -318,9 +318,6 @@ func handleWorkflows( if runName, err := parseRunName(run, dwf); err == nil { run.Title = runName - } else { - log.Error("evaluateExpressionsForRun: %v", err) - continue } need, err := ifNeedApproval(ctx, run, input.Repo, input.Doer) @@ -532,8 +529,6 @@ func handleSchedules( if runName, err := parseRunName(run.ToActionRun(), dwf); err == nil { run.Title = runName - } else { - log.Error("ParseRunName: %v", err) } crons = append(crons, run) @@ -591,7 +586,11 @@ func parseRunName(r *actions_model.ActionRun, w *actions_module.DetectedWorkflow return "", err } - title, _ := jobparser.ParseRunName(w.Content, jobparser.WithGitContext(ghCtx)) - log.Info("title: %s", title) + title, err := jobparser.ParseRunName(w.Content, jobparser.WithGitContext(ghCtx)) + if err != nil { + // stay silent, run-name was not provided. + return "", err + } + return title, nil } diff --git a/tests/integration/actions_trigger_test.go b/tests/integration/actions_trigger_test.go index ed6dedd016e14..dd6be25204c34 100644 --- a/tests/integration/actions_trigger_test.go +++ b/tests/integration/actions_trigger_test.go @@ -414,15 +414,12 @@ jobs: err = repo_service.CreateNewBranchFromCommit(db.DefaultContext, user2, repo, gitRepo, branch.CommitID, "test-create-branch") assert.NoError(t, err) run := unittest.AssertExistsAndLoadBean(t, &actions_model.ActionRun{ - Title: "add workflow", - RepoID: repo.ID, - Repo: repo, - Event: "create", - Ref: "refs/heads/test-create-branch", - WorkflowID: "createdelete.yml", - CommitSHA: branch.CommitID, - TriggerUserID: user2.ID, - TriggerUser: user2, + Title: "add workflow", + RepoID: repo.ID, + Event: "create", + Ref: "refs/heads/test-create-branch", + WorkflowID: "createdelete.yml", + CommitSHA: branch.CommitID, }) assert.NotNil(t, run) @@ -430,15 +427,12 @@ jobs: err = release_service.CreateNewTag(db.DefaultContext, user2, repo, branch.CommitID, "test-create-tag", "test create tag event") assert.NoError(t, err) run = unittest.AssertExistsAndLoadBean(t, &actions_model.ActionRun{ - Title: "add workflow", - RepoID: repo.ID, - Repo: repo, - Event: "create", - Ref: "refs/tags/test-create-tag", - WorkflowID: "createdelete.yml", - CommitSHA: branch.CommitID, - TriggerUserID: user2.ID, - TriggerUser: user2, + Title: "add workflow", + RepoID: repo.ID, + Event: "create", + Ref: "refs/tags/test-create-tag", + WorkflowID: "createdelete.yml", + CommitSHA: branch.CommitID, }) assert.NotNil(t, run) @@ -446,15 +440,12 @@ jobs: err = repo_service.DeleteBranch(db.DefaultContext, user2, repo, gitRepo, "test-create-branch", nil) assert.NoError(t, err) run = unittest.AssertExistsAndLoadBean(t, &actions_model.ActionRun{ - Title: "add workflow", - RepoID: repo.ID, - Repo: repo, - Event: "delete", - Ref: "refs/heads/main", - WorkflowID: "createdelete.yml", - CommitSHA: branch.CommitID, - TriggerUserID: user2.ID, - TriggerUser: user2, + Title: "add workflow", + RepoID: repo.ID, + Event: "delete", + Ref: "refs/heads/main", + WorkflowID: "createdelete.yml", + CommitSHA: branch.CommitID, }) assert.NotNil(t, run) @@ -464,15 +455,12 @@ jobs: err = release_service.DeleteReleaseByID(db.DefaultContext, repo, tag, user2, true) assert.NoError(t, err) run = unittest.AssertExistsAndLoadBean(t, &actions_model.ActionRun{ - Title: "add workflow", - RepoID: repo.ID, - Repo: repo, - Event: "delete", - Ref: "refs/heads/main", - WorkflowID: "createdelete.yml", - CommitSHA: branch.CommitID, - TriggerUserID: user2.ID, - TriggerUser: user2, + Title: "add workflow", + RepoID: repo.ID, + Event: "delete", + Ref: "refs/heads/main", + WorkflowID: "createdelete.yml", + CommitSHA: branch.CommitID, }) assert.NotNil(t, run) }) @@ -774,15 +762,12 @@ jobs: _ = MakeRequest(t, req, http.StatusNoContent) run := unittest.AssertExistsAndLoadBean(t, &actions_model.ActionRun{ - Title: "add workflow", - RepoID: repo.ID, - Repo: repo, - Event: "workflow_dispatch", - Ref: "refs/heads/main", - WorkflowID: "dispatch.yml", - CommitSHA: branch.CommitID, - TriggerUserID: user2.ID, - TriggerUser: user2, + Title: "add workflow", + RepoID: repo.ID, + Event: "workflow_dispatch", + Ref: "refs/heads/main", + WorkflowID: "dispatch.yml", + CommitSHA: branch.CommitID, }) assert.NotNil(t, run) }) @@ -859,15 +844,12 @@ jobs: _ = MakeRequest(t, req, http.StatusNoContent) run := unittest.AssertExistsAndLoadBean(t, &actions_model.ActionRun{ - Title: "add workflow", - RepoID: repo.ID, - Repo: repo, - Event: "workflow_dispatch", - Ref: "refs/heads/main", - WorkflowID: "dispatch.yml", - CommitSHA: branch.CommitID, - TriggerUserID: user2.ID, - TriggerUser: user2, + Title: "add workflow", + RepoID: repo.ID, + Event: "workflow_dispatch", + Ref: "refs/heads/main", + WorkflowID: "dispatch.yml", + CommitSHA: branch.CommitID, }) assert.NotNil(t, run) dispatchPayload := &api.WorkflowDispatchPayload{} @@ -957,15 +939,12 @@ jobs: _ = MakeRequest(t, req, http.StatusNoContent) run := unittest.AssertExistsAndLoadBean(t, &actions_model.ActionRun{ - Title: "add workflow", - RepoID: repo.ID, - Repo: repo, - Event: "workflow_dispatch", - Ref: "refs/heads/main", - WorkflowID: "dispatch.yml", - CommitSHA: branch.CommitID, - TriggerUserID: user2.ID, - TriggerUser: user2, + Title: "add workflow", + RepoID: repo.ID, + Event: "workflow_dispatch", + Ref: "refs/heads/main", + WorkflowID: "dispatch.yml", + CommitSHA: branch.CommitID, }) assert.NotNil(t, run) }) @@ -1045,15 +1024,12 @@ jobs: _ = MakeRequest(t, req, http.StatusNoContent) run := unittest.AssertExistsAndLoadBean(t, &actions_model.ActionRun{ - Title: "add workflow", - RepoID: repo.ID, - Repo: repo, - Event: "workflow_dispatch", - Ref: "refs/heads/main", - WorkflowID: "dispatch.yml", - CommitSHA: branch.CommitID, - TriggerUserID: user2.ID, - TriggerUser: user2, + Title: "add workflow", + RepoID: repo.ID, + Event: "workflow_dispatch", + Ref: "refs/heads/main", + WorkflowID: "dispatch.yml", + CommitSHA: branch.CommitID, }) assert.NotNil(t, run) dispatchPayload := &api.WorkflowDispatchPayload{} @@ -1376,15 +1352,12 @@ jobs: _ = MakeRequest(t, req, http.StatusNoContent) run := unittest.AssertExistsAndLoadBean(t, &actions_model.ActionRun{ - Title: "add workflow", - RepoID: repo.ID, - Repo: repo, - Event: "workflow_dispatch", - Ref: "refs/heads/main", - WorkflowID: "dispatch.yml", - CommitSHA: branch.CommitID, - TriggerUserID: user2.ID, - TriggerUser: user2, + Title: "add workflow", + RepoID: repo.ID, + Event: "workflow_dispatch", + Ref: "refs/heads/main", + WorkflowID: "dispatch.yml", + CommitSHA: branch.CommitID, }) assert.NotNil(t, run) dispatchPayload := &api.WorkflowDispatchPayload{} From 6d8d43d3e80056b625e772f48104cd7889c3e9c7 Mon Sep 17 00:00:00 2001 From: badhezi Date: Fri, 2 May 2025 00:35:38 +0300 Subject: [PATCH 14/17] Move interpolation logic to jobparser, add helper ToGitHubContext, reorder DispatchActionWorkflow to support run-name parsing --- go.mod | 2 +- go.sum | 4 + services/actions/context.go | 25 +++- services/actions/notifier_helper.go | 55 ++++---- services/actions/workflow.go | 72 +++++----- tests/integration/actions_trigger_test.go | 154 ++++++++++++++++++++++ 6 files changed, 240 insertions(+), 72 deletions(-) diff --git a/go.mod b/go.mod index 021ad3eba2584..a4f81c02e5c26 100644 --- a/go.mod +++ b/go.mod @@ -317,7 +317,7 @@ replace github.com/hashicorp/go-version => github.com/6543/go-version v1.3.1 replace github.com/shurcooL/vfsgen => github.com/lunny/vfsgen v0.0.0-20220105142115-2c99e1ffdfa0 -replace github.com/nektos/act => gitea.com/badhezi/act v0.0.0-20250429095415-d27028e1df50 +replace github.com/nektos/act => gitea.com/badhezi/act v0.0.0-20250501202946-5f2de4d09b1f // TODO: the only difference is in `PutObject`: the fork doesn't use `NewVerifyingReader(r, sha256.New(), oid, expectedSize)`, need to figure out why replace github.com/charmbracelet/git-lfs-transfer => gitea.com/gitea/git-lfs-transfer v0.2.0 diff --git a/go.sum b/go.sum index 10542584456d5..b5b49655faf05 100644 --- a/go.sum +++ b/go.sum @@ -16,6 +16,10 @@ filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA= filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= gitea.com/badhezi/act v0.0.0-20250429095415-d27028e1df50 h1:46UPmv+pLMBd2TR/N/hKpWY3SloOlVusmZg6SmpcfbE= gitea.com/badhezi/act v0.0.0-20250429095415-d27028e1df50/go.mod h1:Pg5C9kQY1CEA3QjthjhlrqOC/QOT5NyWNjOjRHw23Ok= +gitea.com/badhezi/act v0.0.0-20250501200956-eaed3ad12395 h1:LWYeTtkf2cBhRNPqXrIPxMOlH3EmvU6EyKyqzf66hM0= +gitea.com/badhezi/act v0.0.0-20250501200956-eaed3ad12395/go.mod h1:Pg5C9kQY1CEA3QjthjhlrqOC/QOT5NyWNjOjRHw23Ok= +gitea.com/badhezi/act v0.0.0-20250501202946-5f2de4d09b1f h1:aPHa4bpjOgUGJoMkQZ5PvpASmrjHLx55sIu+RtGWzvE= +gitea.com/badhezi/act v0.0.0-20250501202946-5f2de4d09b1f/go.mod h1:Pg5C9kQY1CEA3QjthjhlrqOC/QOT5NyWNjOjRHw23Ok= gitea.com/gitea/git-lfs-transfer v0.2.0 h1:baHaNoBSRaeq/xKayEXwiDQtlIjps4Ac/Ll4KqLMB40= gitea.com/gitea/git-lfs-transfer v0.2.0/go.mod h1:UrXUCm3xLQkq15fu7qlXHUMlrhdlXHoi13KH2Dfiits= gitea.com/gitea/go-xsd-duration v0.0.0-20220703122237-02e73435a078 h1:BAFmdZpRW7zMQZQDClaCWobRj9uL1MR3MzpCVJvc5s4= diff --git a/services/actions/context.go b/services/actions/context.go index 2667e18337dac..9156c2f60b058 100644 --- a/services/actions/context.go +++ b/services/actions/context.go @@ -14,12 +14,17 @@ import ( "code.gitea.io/gitea/modules/container" "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/json" + "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/setting" + + "github.com/nektos/act/pkg/model" ) +type GiteaContext map[string]any + // GenerateGiteaContext generate the gitea context without token and gitea_runtime_token // job can be nil when generating a context for parsing workflow-level expressions -func GenerateGiteaContext(run *actions_model.ActionRun, job *actions_model.ActionRunJob) map[string]any { +func GenerateGiteaContext(run *actions_model.ActionRun, job *actions_model.ActionRunJob) GiteaContext { event := map[string]any{} _ = json.Unmarshal([]byte(run.EventPayload), &event) @@ -42,7 +47,7 @@ func GenerateGiteaContext(run *actions_model.ActionRun, job *actions_model.Actio refName := git.RefName(ref) - gitContext := map[string]any{ + gitContext := GiteaContext{ // standard contexts, see https://docs.github.com/en/actions/learn-github-actions/contexts#github-context "action": "", // string, The name of the action currently running, or the id of a step. GitHub removes special characters, and uses the name __run when the current step runs a script without an id. If you use the same action more than once in the same job, the name will include a suffix with the sequence number with underscore before it. For example, the first script you run will have the name __run, and the second script will be named __run_2. Similarly, the second invocation of actions/checkout will be actionscheckout2. "action_path": "", // string, The path where an action is located. This property is only supported in composite actions. You can use this path to access files located in the same repository as the action. @@ -160,3 +165,19 @@ func mergeTwoOutputs(o1, o2 map[string]string) map[string]string { } return ret } + +func (g *GiteaContext) ToGitHubContext() *model.GithubContext { + ghCtx := &model.GithubContext{} + + gitCtxRaw, err := json.Marshal(g) + if err != nil { + log.Error("ToGitHubContext.json.Marshal: %v", err) + } + + err = json.Unmarshal(gitCtxRaw, ghCtx) + if err != nil { + log.Error("ToGitHubContext.json.Unmarshal: %v", err) + } + + return ghCtx +} diff --git a/services/actions/notifier_helper.go b/services/actions/notifier_helper.go index 288361148156c..54f4346a6605b 100644 --- a/services/actions/notifier_helper.go +++ b/services/actions/notifier_helper.go @@ -316,10 +316,6 @@ func handleWorkflows( Status: actions_model.StatusWaiting, } - if runName, err := parseRunName(run, dwf); err == nil { - run.Title = runName - } - need, err := ifNeedApproval(ctx, run, input.Repo, input.Doer) if err != nil { log.Error("check if need approval for repo %d with user %d: %v", input.Repo.ID, input.Doer.ID, err) @@ -339,12 +335,18 @@ func handleWorkflows( continue } - jobs, err := jobparser.Parse(dwf.Content, jobparser.WithVars(vars)) + giteaCtx := GenerateGiteaContext(run, nil) + + jobs, err := jobparser.Parse(dwf.Content, jobparser.WithVars(vars), jobparser.WithGitContext(giteaCtx.ToGitHubContext())) if err != nil { log.Error("jobparser.Parse: %v", err) continue } + if len(jobs) > 0 && jobs[0].RunName != "" { + run.Title = jobs[0].RunName + } + // cancel running jobs if the event is push or pull_request_sync if run.Event == webhook_module.HookEventPush || run.Event == webhook_module.HookEventPullRequestSync { @@ -527,8 +529,22 @@ func handleSchedules( Content: dwf.Content, } - if runName, err := parseRunName(run.ToActionRun(), dwf); err == nil { - run.Title = runName + vars, err := actions_model.GetVariablesOfRun(ctx, run.ToActionRun()) + if err != nil { + log.Error("GetVariablesOfRun: %v", err) + continue + } + + giteaCtx := GenerateGiteaContext(run.ToActionRun(), nil) + + jobs, err := jobparser.Parse(dwf.Content, jobparser.WithVars(vars), jobparser.WithGitContext(giteaCtx.ToGitHubContext())) + if err != nil { + log.Error("jobparser.Parse: %v", err) + continue + } + + if len(jobs) > 0 && jobs[0].RunName != "" { + run.Title = jobs[0].RunName } crons = append(crons, run) @@ -569,28 +585,3 @@ func DetectAndHandleSchedules(ctx context.Context, repo *repo_model.Repository) return handleSchedules(ctx, scheduleWorkflows, commit, notifyInput, repo.DefaultBranch) } - -func parseRunName(r *actions_model.ActionRun, w *actions_module.DetectedWorkflow) (string, error) { - ghCtx := &model.GithubContext{} - gitCtx := GenerateGiteaContext(r, nil) - - gitCtxRaw, err := json.Marshal(gitCtx) - if err != nil { - log.Error("NewInterpolatorForRun: %v", err) - return "", err - } - - err = json.Unmarshal(gitCtxRaw, ghCtx) - if err != nil { - log.Error("NewInterpolatorForRun: %v", err) - return "", err - } - - title, err := jobparser.ParseRunName(w.Content, jobparser.WithGitContext(ghCtx)) - if err != nil { - // stay silent, run-name was not provided. - return "", err - } - - return title, nil -} diff --git a/services/actions/workflow.go b/services/actions/workflow.go index ce311baa41796..ccc74d840286c 100644 --- a/services/actions/workflow.go +++ b/services/actions/workflow.go @@ -192,27 +192,46 @@ func DispatchActionWorkflow(ctx reqctx.RequestContext, doer *user_model.User, re // find workflow from commit var workflows []*jobparser.SingleWorkflow - dwf := &actions.DetectedWorkflow{} + var entry *git.TreeEntry - for _, entry := range entries { - if entry.Name() != workflowID { + for _, e := range entries { + if e.Name() != workflowID { continue } + entry = e + break + } - content, err := actions.GetContentFromEntry(entry) - if err != nil { - return err - } + content, err := actions.GetContentFromEntry(entry) + if err != nil { + return err + } - workflows, err = jobparser.Parse(content) - if err != nil { - return err - } + run := &actions_model.ActionRun{ + Title: strings.SplitN(runTargetCommit.CommitMessage, "\n", 2)[0], + RepoID: repo.ID, + Repo: repo, + OwnerID: repo.OwnerID, + WorkflowID: workflowID, + TriggerUserID: doer.ID, + TriggerUser: doer, + Ref: string(refName), + CommitSHA: runTargetCommit.ID.String(), + IsForkPullRequest: false, + Event: "workflow_dispatch", + TriggerEvent: "workflow_dispatch", + Status: actions_model.StatusWaiting, + } - dwf.Content = content - dwf.EntryName = entry.Name() + giteaCtx := GenerateGiteaContext(run, nil) - break + workflows, err = jobparser.Parse(content, jobparser.WithGitContext(giteaCtx.ToGitHubContext())) + if err != nil { + return err + } + + if len(workflows) > 0 && workflows[0].RunName != "" { + run.Title = workflows[0].RunName } if len(workflows) == 0 { @@ -243,33 +262,12 @@ func DispatchActionWorkflow(ctx reqctx.RequestContext, doer *user_model.User, re Inputs: inputsWithDefaults, Sender: convert.ToUserWithAccessMode(ctx, doer, perm.AccessModeNone), } + var eventPayload []byte if eventPayload, err = workflowDispatchPayload.JSONPayload(); err != nil { return fmt.Errorf("JSONPayload: %w", err) } - - run := &actions_model.ActionRun{ - Title: strings.SplitN(runTargetCommit.CommitMessage, "\n", 2)[0], - RepoID: repo.ID, - Repo: repo, - OwnerID: repo.OwnerID, - WorkflowID: workflowID, - TriggerUserID: doer.ID, - TriggerUser: doer, - Ref: string(refName), - CommitSHA: runTargetCommit.ID.String(), - IsForkPullRequest: false, - Event: "workflow_dispatch", - TriggerEvent: "workflow_dispatch", - EventPayload: string(eventPayload), - Status: actions_model.StatusWaiting, - } - - if runName, err := parseRunName(run, dwf); err == nil { - run.Title = runName - } else { - log.Error("ParseRunName: %v", err) - } + run.EventPayload = string(eventPayload) // cancel running jobs of the same workflow if err := CancelPreviousJobs( diff --git a/tests/integration/actions_trigger_test.go b/tests/integration/actions_trigger_test.go index dd6be25204c34..e755481d09e68 100644 --- a/tests/integration/actions_trigger_test.go +++ b/tests/integration/actions_trigger_test.go @@ -1449,3 +1449,157 @@ jobs: assert.Equal(t, pullRequest.MergedCommitID, actionRun.CommitSHA) }) } + +func TestActionRunNameWithContextVariables(t *testing.T) { + onGiteaRun(t, func(t *testing.T, u *url.URL) { + user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) + + // create the repo + repo, err := repo_service.CreateRepository(db.DefaultContext, user2, user2, repo_service.CreateRepoOptions{ + Name: "action-run-name-with-variables", + Description: "test action run name", + AutoInit: true, + Gitignores: "Go", + License: "MIT", + Readme: "Default", + DefaultBranch: "main", + IsPrivate: false, + }) + assert.NoError(t, err) + assert.NotEmpty(t, repo) + + // add workflow file to the repo + addWorkflowToBaseResp, err := files_service.ChangeRepoFiles(git.DefaultContext, repo, user2, &files_service.ChangeRepoFilesOptions{ + Files: []*files_service.ChangeRepoFile{ + { + Operation: "create", + TreePath: ".gitea/workflows/runname.yml", + ContentReader: strings.NewReader(`name: test +on: + [create,delete] +run-name: ${{ gitea.actor }} is running this workflow +jobs: + test: + runs-on: ubuntu-latest + steps: + - run: echo helloworld +`), + }, + }, + Message: "add workflow with run-name", + OldBranch: "main", + NewBranch: "main", + Author: &files_service.IdentityOptions{ + GitUserName: user2.Name, + GitUserEmail: user2.Email, + }, + Committer: &files_service.IdentityOptions{ + GitUserName: user2.Name, + GitUserEmail: user2.Email, + }, + Dates: &files_service.CommitDateOptions{ + Author: time.Now(), + Committer: time.Now(), + }, + }) + assert.NoError(t, err) + assert.NotEmpty(t, addWorkflowToBaseResp) + + // Get the commit ID of the default branch + gitRepo, err := gitrepo.OpenRepository(git.DefaultContext, repo) + assert.NoError(t, err) + defer gitRepo.Close() + branch, err := git_model.GetBranch(db.DefaultContext, repo.ID, repo.DefaultBranch) + assert.NoError(t, err) + + // create a branch + err = repo_service.CreateNewBranchFromCommit(db.DefaultContext, user2, repo, gitRepo, branch.CommitID, "test-action-run-name-with-variables") + assert.NoError(t, err) + run := unittest.AssertExistsAndLoadBean(t, &actions_model.ActionRun{ + Title: user2.LoginName + " is running this workflow", + RepoID: repo.ID, + Event: "create", + Ref: "refs/heads/test-action-run-name-with-variables", + WorkflowID: "runname.yml", + CommitSHA: branch.CommitID, + }) + assert.NotNil(t, run) + }) +} + +func TestActionRunName(t *testing.T) { + onGiteaRun(t, func(t *testing.T, u *url.URL) { + user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) + + // create the repo + repo, err := repo_service.CreateRepository(db.DefaultContext, user2, user2, repo_service.CreateRepoOptions{ + Name: "action-run-name", + Description: "test action run-name", + AutoInit: true, + Gitignores: "Go", + License: "MIT", + Readme: "Default", + DefaultBranch: "main", + IsPrivate: false, + }) + assert.NoError(t, err) + assert.NotEmpty(t, repo) + + // add workflow file to the repo + addWorkflowToBaseResp, err := files_service.ChangeRepoFiles(git.DefaultContext, repo, user2, &files_service.ChangeRepoFilesOptions{ + Files: []*files_service.ChangeRepoFile{ + { + Operation: "create", + TreePath: ".gitea/workflows/runname.yml", + ContentReader: strings.NewReader(`name: test +on: + [create,delete] +run-name: run name without variables +jobs: + test: + runs-on: ubuntu-latest + steps: + - run: echo helloworld +`), + }, + }, + Message: "add workflow with run name", + OldBranch: "main", + NewBranch: "main", + Author: &files_service.IdentityOptions{ + GitUserName: user2.Name, + GitUserEmail: user2.Email, + }, + Committer: &files_service.IdentityOptions{ + GitUserName: user2.Name, + GitUserEmail: user2.Email, + }, + Dates: &files_service.CommitDateOptions{ + Author: time.Now(), + Committer: time.Now(), + }, + }) + assert.NoError(t, err) + assert.NotEmpty(t, addWorkflowToBaseResp) + + // Get the commit ID of the default branch + gitRepo, err := gitrepo.OpenRepository(git.DefaultContext, repo) + assert.NoError(t, err) + defer gitRepo.Close() + branch, err := git_model.GetBranch(db.DefaultContext, repo.ID, repo.DefaultBranch) + assert.NoError(t, err) + + // create a branch + err = repo_service.CreateNewBranchFromCommit(db.DefaultContext, user2, repo, gitRepo, branch.CommitID, "test-action-run-name") + assert.NoError(t, err) + run := unittest.AssertExistsAndLoadBean(t, &actions_model.ActionRun{ + Title: "run name without variables", + RepoID: repo.ID, + Event: "create", + Ref: "refs/heads/test-action-run-name", + WorkflowID: "runname.yml", + CommitSHA: branch.CommitID, + }) + assert.NotNil(t, run) + }) +} From 7a52cac8378efb23c22f2a0023eb719f3b1d6fdb Mon Sep 17 00:00:00 2001 From: badhezi Date: Fri, 2 May 2025 00:58:52 +0300 Subject: [PATCH 15/17] remove redundant sums --- go.sum | 4 ---- 1 file changed, 4 deletions(-) diff --git a/go.sum b/go.sum index b5b49655faf05..2b0d33c5d2b29 100644 --- a/go.sum +++ b/go.sum @@ -14,10 +14,6 @@ dario.cat/mergo v1.0.1 h1:Ra4+bf83h2ztPIQYNP99R6m+Y7KfnARDfID+a+vLl4s= dario.cat/mergo v1.0.1/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk= filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA= filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= -gitea.com/badhezi/act v0.0.0-20250429095415-d27028e1df50 h1:46UPmv+pLMBd2TR/N/hKpWY3SloOlVusmZg6SmpcfbE= -gitea.com/badhezi/act v0.0.0-20250429095415-d27028e1df50/go.mod h1:Pg5C9kQY1CEA3QjthjhlrqOC/QOT5NyWNjOjRHw23Ok= -gitea.com/badhezi/act v0.0.0-20250501200956-eaed3ad12395 h1:LWYeTtkf2cBhRNPqXrIPxMOlH3EmvU6EyKyqzf66hM0= -gitea.com/badhezi/act v0.0.0-20250501200956-eaed3ad12395/go.mod h1:Pg5C9kQY1CEA3QjthjhlrqOC/QOT5NyWNjOjRHw23Ok= gitea.com/badhezi/act v0.0.0-20250501202946-5f2de4d09b1f h1:aPHa4bpjOgUGJoMkQZ5PvpASmrjHLx55sIu+RtGWzvE= gitea.com/badhezi/act v0.0.0-20250501202946-5f2de4d09b1f/go.mod h1:Pg5C9kQY1CEA3QjthjhlrqOC/QOT5NyWNjOjRHw23Ok= gitea.com/gitea/git-lfs-transfer v0.2.0 h1:baHaNoBSRaeq/xKayEXwiDQtlIjps4Ac/Ll4KqLMB40= From a063d2ac50389da6f1b506bc6af898897ca4675f Mon Sep 17 00:00:00 2001 From: badhezi Date: Mon, 12 May 2025 21:58:06 +0300 Subject: [PATCH 16/17] bump gitea/act to v0.261.6 --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index a4f81c02e5c26..a99e9b821445f 100644 --- a/go.mod +++ b/go.mod @@ -317,7 +317,7 @@ replace github.com/hashicorp/go-version => github.com/6543/go-version v1.3.1 replace github.com/shurcooL/vfsgen => github.com/lunny/vfsgen v0.0.0-20220105142115-2c99e1ffdfa0 -replace github.com/nektos/act => gitea.com/badhezi/act v0.0.0-20250501202946-5f2de4d09b1f +replace github.com/nektos/act => gitea.com/gitea/act v0.261.6 // TODO: the only difference is in `PutObject`: the fork doesn't use `NewVerifyingReader(r, sha256.New(), oid, expectedSize)`, need to figure out why replace github.com/charmbracelet/git-lfs-transfer => gitea.com/gitea/git-lfs-transfer v0.2.0 diff --git a/go.sum b/go.sum index 2b0d33c5d2b29..24abf4909972b 100644 --- a/go.sum +++ b/go.sum @@ -14,8 +14,8 @@ dario.cat/mergo v1.0.1 h1:Ra4+bf83h2ztPIQYNP99R6m+Y7KfnARDfID+a+vLl4s= dario.cat/mergo v1.0.1/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk= filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA= filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= -gitea.com/badhezi/act v0.0.0-20250501202946-5f2de4d09b1f h1:aPHa4bpjOgUGJoMkQZ5PvpASmrjHLx55sIu+RtGWzvE= -gitea.com/badhezi/act v0.0.0-20250501202946-5f2de4d09b1f/go.mod h1:Pg5C9kQY1CEA3QjthjhlrqOC/QOT5NyWNjOjRHw23Ok= +gitea.com/gitea/act v0.261.6 h1:CjZwKOyejonNFDmsXOw3wGm5Vet573hHM6VMLsxtvPY= +gitea.com/gitea/act v0.261.6/go.mod h1:Pg5C9kQY1CEA3QjthjhlrqOC/QOT5NyWNjOjRHw23Ok= gitea.com/gitea/git-lfs-transfer v0.2.0 h1:baHaNoBSRaeq/xKayEXwiDQtlIjps4Ac/Ll4KqLMB40= gitea.com/gitea/git-lfs-transfer v0.2.0/go.mod h1:UrXUCm3xLQkq15fu7qlXHUMlrhdlXHoi13KH2Dfiits= gitea.com/gitea/go-xsd-duration v0.0.0-20220703122237-02e73435a078 h1:BAFmdZpRW7zMQZQDClaCWobRj9uL1MR3MzpCVJvc5s4= From 4593bbdc0e281b8b5b59f70a7837b667607c408d Mon Sep 17 00:00:00 2001 From: badhezi Date: Tue, 13 May 2025 11:28:31 +0300 Subject: [PATCH 17/17] additional fields for ActionSchedule.ToActionRun --- models/actions/utils.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/models/actions/utils.go b/models/actions/utils.go index c6d5769d9c553..f6ba661ae309f 100644 --- a/models/actions/utils.go +++ b/models/actions/utils.go @@ -83,6 +83,7 @@ func calculateDuration(started, stopped timeutil.TimeStamp, status Status) time. return timeSince(s).Truncate(time.Second) } +// best effort function to convert an action schedule to action run, to be used in GenerateGiteaContext func (s *ActionSchedule) ToActionRun() *ActionRun { return &ActionRun{ Title: s.Title, @@ -96,5 +97,7 @@ func (s *ActionSchedule) ToActionRun() *ActionRun { CommitSHA: s.CommitSHA, Event: s.Event, EventPayload: s.EventPayload, + Created: s.Created, + Updated: s.Updated, } }