From 8d799c236c854c8bb132b38c97385beaf53d9327 Mon Sep 17 00:00:00 2001 From: badhezi Date: Tue, 15 Apr 2025 19:56:19 +0300 Subject: [PATCH 01/15] 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 18016d6be71927e3751e85743a4a15c363bb91c1 Mon Sep 17 00:00:00 2001 From: badhezi Date: Sun, 27 Apr 2025 16:14:32 +0300 Subject: [PATCH 02/15] 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 892f03dc1ceef..7bf2cd6cb284f 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 c9dcc235aaeff..b428037331213 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 abcb0d5de7159615c43264a95e9e52e295eb46aa Mon Sep 17 00:00:00 2001 From: badhezi Date: Mon, 28 Apr 2025 17:08:16 +0300 Subject: [PATCH 03/15] 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 7bf2cd6cb284f..892f03dc1ceef 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 447347890b7f4..fd83c2a7a2afe 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 27805b3e773645260d9599d824863b1a72f6466d Mon Sep 17 00:00:00 2001 From: badhezi Date: Mon, 28 Apr 2025 17:15:16 +0300 Subject: [PATCH 04/15] 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 fd83c2a7a2afe..f59566cd7bfc3 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 7d4f72244e248e82607c399424803b7e716897d7 Mon Sep 17 00:00:00 2001 From: badhezi Date: Mon, 28 Apr 2025 18:09:53 +0300 Subject: [PATCH 05/15] 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 73ff39b9cf17e75b01af0c7769903a937800b2a1 Mon Sep 17 00:00:00 2001 From: badhezi Date: Mon, 28 Apr 2025 18:21:04 +0300 Subject: [PATCH 06/15] 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 f59566cd7bfc3..287b3c41089df 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 5b853095e658c68ab0eb60abc3178b7476ceea4a Mon Sep 17 00:00:00 2001 From: badhezi Date: Mon, 28 Apr 2025 18:21:21 +0300 Subject: [PATCH 07/15] 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 287b3c41089df..447347890b7f4 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 384f6b1319f98e7d261e6d5627b3182211949173 Mon Sep 17 00:00:00 2001 From: badhezi Date: Mon, 28 Apr 2025 19:16:52 +0300 Subject: [PATCH 08/15] 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 1df49898c59daed5d5e4f5fe236410b73b722e12 Mon Sep 17 00:00:00 2001 From: badhezi Date: Tue, 29 Apr 2025 12:45:06 +0300 Subject: [PATCH 09/15] 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 9408c76c24dc8c5ece4f5ea426f3dfc25cbe6755 Mon Sep 17 00:00:00 2001 From: badhezi Date: Tue, 29 Apr 2025 13:11:01 +0300 Subject: [PATCH 10/15] use pseudo-version of act --- go.mod | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/go.mod b/go.mod index 892f03dc1ceef..0e3c3f5cac97c 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 2fb5f3f1becc098b54f8eb715e116775f92d5ead Mon Sep 17 00:00:00 2001 From: badhezi Date: Tue, 29 Apr 2025 15:20:39 +0300 Subject: [PATCH 11/15] update act --- go.sum | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/go.sum b/go.sum index b428037331213..6a97b7d6be994 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 883c8eb5963e26f6bdd132059d7e7d3cc4c2c637 Mon Sep 17 00:00:00 2001 From: badhezi Date: Tue, 29 Apr 2025 15:59:01 +0300 Subject: [PATCH 12/15] 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 4248591809757ab8cff1a0bac0686005a90bf5ec Mon Sep 17 00:00:00 2001 From: badhezi Date: Wed, 30 Apr 2025 09:55:06 +0300 Subject: [PATCH 13/15] 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 11e23c28d90094ea90ca16da14607d2853255479 Mon Sep 17 00:00:00 2001 From: badhezi Date: Fri, 2 May 2025 00:35:38 +0300 Subject: [PATCH 14/15] 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 9076ee5bc1cd6..7015a7b946674 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 6a97b7d6be994..b0090d0d6090c 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 ae352dc6cddca6c67eb28f4570905277763601d3 Mon Sep 17 00:00:00 2001 From: badhezi Date: Fri, 2 May 2025 00:58:52 +0300 Subject: [PATCH 15/15] remove redundant sums --- go.sum | 4 ---- 1 file changed, 4 deletions(-) diff --git a/go.sum b/go.sum index b0090d0d6090c..0800985eee555 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=