mirror of
https://github.com/go-gitea/gitea.git
synced 2026-04-10 23:32:51 +02:00
Backport #37116 by @bircni `model.ReadWorkflow` succeeds for YAML that is syntactically valid but fails deeper parsing in `jobparser.Parse` (e.g. blank lines inside `run: |` blocks cause a SetJob round-trip error). Add `ValidateWorkflowContent` which runs the full `jobparser.Parse` to catch these cases, and use it in the file view, the actions workflow list, and the workflow detection loop so users see the error instead of silently getting a 500 or a dropped workflow. Fixes #37115 Signed-off-by: Nicolas <bircni@icloud.com> Co-authored-by: Nicolas <bircni@icloud.com> Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com> Co-authored-by: Zettat123 <zettat123@gmail.com> Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
This commit is contained in:
parent
a2283a0c03
commit
4eca71d6d4
@ -103,10 +103,20 @@ func GetEventsFromContent(content []byte) ([]*jobparser.Event, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := ValidateWorkflowContent(content); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return events, nil
|
||||
}
|
||||
|
||||
// ValidateWorkflowContent catches structural errors (e.g. blank lines in run: | blocks)
|
||||
// that model.ReadWorkflow alone does not detect.
|
||||
func ValidateWorkflowContent(content []byte) error {
|
||||
_, err := jobparser.Parse(content)
|
||||
return err
|
||||
}
|
||||
|
||||
func DetectWorkflows(
|
||||
gitRepo *git.Repository,
|
||||
commit *git.Commit,
|
||||
|
||||
@ -9,16 +9,26 @@ import (
|
||||
"code.gitea.io/gitea/modules/git"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
api "code.gitea.io/gitea/modules/structs"
|
||||
"code.gitea.io/gitea/modules/test"
|
||||
webhook_module "code.gitea.io/gitea/modules/webhook"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func fullWorkflowContent(part string) []byte {
|
||||
return []byte(`
|
||||
name: test
|
||||
` + part + `
|
||||
jobs:
|
||||
test:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- run: echo hello
|
||||
`)
|
||||
}
|
||||
|
||||
func TestIsWorkflow(t *testing.T) {
|
||||
oldDirs := setting.Actions.WorkflowDirs
|
||||
defer func() {
|
||||
setting.Actions.WorkflowDirs = oldDirs
|
||||
}()
|
||||
defer test.MockVariableValue(&setting.Actions.WorkflowDirs)()
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
@ -218,7 +228,7 @@ func TestDetectMatched(t *testing.T) {
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.desc, func(t *testing.T) {
|
||||
evts, err := GetEventsFromContent([]byte(tc.yamlOn))
|
||||
evts, err := GetEventsFromContent(fullWorkflowContent(tc.yamlOn))
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, evts, 1)
|
||||
assert.Equal(t, tc.expected, detectMatched(nil, tc.commit, tc.triggedEvent, tc.payload, evts[0]))
|
||||
@ -373,7 +383,7 @@ func TestMatchIssuesEvent(t *testing.T) {
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.desc, func(t *testing.T) {
|
||||
evts, err := GetEventsFromContent([]byte(tc.yamlOn))
|
||||
evts, err := GetEventsFromContent(fullWorkflowContent(tc.yamlOn))
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, evts, 1)
|
||||
|
||||
|
||||
@ -151,6 +151,11 @@ func prepareWorkflowTemplate(ctx *context.Context, commit *git.Commit) (workflow
|
||||
workflows = append(workflows, workflow)
|
||||
continue
|
||||
}
|
||||
if err := actions.ValidateWorkflowContent(content); err != nil {
|
||||
workflow.ErrMsg = ctx.Locale.TrString("actions.runs.invalid_workflow_helper", err.Error())
|
||||
workflows = append(workflows, workflow)
|
||||
continue
|
||||
}
|
||||
workflow.Workflow = wf
|
||||
// The workflow must contain at least one job without "needs". Otherwise, a deadlock will occur and no jobs will be able to run.
|
||||
hasJobWithoutNeeds := false
|
||||
@ -315,6 +320,10 @@ func prepareWorkflowList(ctx *context.Context, workflows []WorkflowInfo) {
|
||||
if !job.Status.IsWaiting() {
|
||||
continue
|
||||
}
|
||||
if err := actions.ValidateWorkflowContent(job.WorkflowPayload); err != nil {
|
||||
runErrors[run.ID] = ctx.Locale.TrString("actions.runs.invalid_workflow_helper", err.Error())
|
||||
break
|
||||
}
|
||||
hasOnlineRunner := false
|
||||
for _, runner := range runners {
|
||||
if !runner.IsDisabled && runner.CanMatchLabels(job.RunsOn) {
|
||||
|
||||
@ -25,8 +25,6 @@ import (
|
||||
"code.gitea.io/gitea/modules/util"
|
||||
"code.gitea.io/gitea/services/context"
|
||||
issue_service "code.gitea.io/gitea/services/issue"
|
||||
|
||||
"github.com/nektos/act/pkg/model"
|
||||
)
|
||||
|
||||
func prepareLatestCommitInfo(ctx *context.Context) bool {
|
||||
@ -184,8 +182,7 @@ func prepareFileView(ctx *context.Context, entry *git.TreeEntry) {
|
||||
if err != nil {
|
||||
log.Error("actions.GetContentFromEntry: %v", err)
|
||||
}
|
||||
_, workFlowErr := model.ReadWorkflow(bytes.NewReader(content))
|
||||
if workFlowErr != nil {
|
||||
if workFlowErr := actions.ValidateWorkflowContent(content); workFlowErr != nil {
|
||||
ctx.Data["FileError"] = ctx.Locale.Tr("actions.runs.invalid_workflow_helper", workFlowErr.Error())
|
||||
}
|
||||
} else if issue_service.IsCodeOwnerFile(ctx.Repo.TreePath) {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user