147 lines
4.3 KiB
Go
147 lines
4.3 KiB
Go
// Copyright 2025 The Gitea Authors. All rights reserved.
|
|
// SPDX-License-Identifier: MIT
|
|
|
|
package actions
|
|
|
|
import (
|
|
"fmt"
|
|
"strings"
|
|
|
|
actions_model "code.gitea.io/gitea/models/actions"
|
|
"code.gitea.io/gitea/models/db"
|
|
"code.gitea.io/gitea/models/perm"
|
|
access_model "code.gitea.io/gitea/models/perm/access"
|
|
repo_model "code.gitea.io/gitea/models/repo"
|
|
user_model "code.gitea.io/gitea/models/user"
|
|
"code.gitea.io/gitea/modules/git"
|
|
"code.gitea.io/gitea/modules/log"
|
|
"code.gitea.io/gitea/modules/reqctx"
|
|
api "code.gitea.io/gitea/modules/structs"
|
|
"code.gitea.io/gitea/services/convert"
|
|
|
|
"github.com/nektos/act/pkg/jobparser"
|
|
)
|
|
|
|
// DebugWorkflowOptions 调试工作流的选项
|
|
type DebugWorkflowOptions struct {
|
|
WorkflowContent string `json:"workflow_content"`
|
|
Ref string `json:"ref"`
|
|
Inputs map[string]string `json:"inputs"`
|
|
}
|
|
|
|
// DebugActionWorkflow 执行调试工作流
|
|
func DebugActionWorkflow(ctx reqctx.RequestContext, doer *user_model.User, repo *repo_model.Repository, gitRepo *git.Repository, opts *DebugWorkflowOptions) (*actions_model.ActionRun, error) {
|
|
if opts == nil || opts.WorkflowContent == "" {
|
|
return nil, fmt.Errorf("workflow content is empty")
|
|
}
|
|
|
|
if opts.Ref == "" {
|
|
opts.Ref = repo.DefaultBranch
|
|
}
|
|
|
|
// 验证工作流内容
|
|
if err := validateWorkflowContent(opts.WorkflowContent); err != nil {
|
|
return nil, fmt.Errorf("invalid workflow content: %w", err)
|
|
}
|
|
|
|
// 获取目标提交
|
|
refName := git.RefName(opts.Ref)
|
|
var runTargetCommit *git.Commit
|
|
var err error
|
|
|
|
if refName.IsTag() {
|
|
runTargetCommit, err = gitRepo.GetTagCommit(refName.TagName())
|
|
} else if refName.IsBranch() {
|
|
runTargetCommit, err = gitRepo.GetBranchCommit(refName.BranchName())
|
|
} else {
|
|
runTargetCommit, err = gitRepo.GetCommit(opts.Ref)
|
|
}
|
|
|
|
if err != nil {
|
|
return nil, fmt.Errorf("get target commit: %w", err)
|
|
}
|
|
|
|
// 创建临时工作流运行记录
|
|
run := &actions_model.ActionRun{
|
|
Title: "[DEBUG] " + strings.SplitN(runTargetCommit.CommitMessage, "\n", 2)[0],
|
|
RepoID: repo.ID,
|
|
Repo: repo,
|
|
OwnerID: repo.OwnerID,
|
|
WorkflowID: "debug-workflow.yml",
|
|
TriggerUserID: doer.ID,
|
|
TriggerUser: doer,
|
|
Ref: string(refName),
|
|
CommitSHA: runTargetCommit.ID.String(),
|
|
IsForkPullRequest: false,
|
|
Event: "workflow_dispatch",
|
|
TriggerEvent: "workflow_dispatch",
|
|
Status: actions_model.StatusWaiting,
|
|
}
|
|
|
|
// 验证工作流内容并获取任务信息
|
|
giteaCtx := GenerateGiteaContext(run, nil)
|
|
workflows, err := jobparser.Parse([]byte(opts.WorkflowContent), jobparser.WithGitContext(giteaCtx.ToGitHubContext()))
|
|
if err != nil {
|
|
return nil, fmt.Errorf("parse workflow: %w", err)
|
|
}
|
|
|
|
if len(workflows) == 0 {
|
|
return nil, fmt.Errorf("no jobs found in workflow")
|
|
}
|
|
|
|
// 如果工作流定义了名称,使用它
|
|
if len(workflows) > 0 && workflows[0].RunName != "" {
|
|
run.Title = "[DEBUG] " + workflows[0].RunName
|
|
}
|
|
|
|
// 创建事件负载
|
|
inputsAny := make(map[string]any)
|
|
for k, v := range opts.Inputs {
|
|
inputsAny[k] = v
|
|
}
|
|
|
|
workflowDispatchPayload := &api.WorkflowDispatchPayload{
|
|
Workflow: run.WorkflowID,
|
|
Ref: opts.Ref,
|
|
Repository: convert.ToRepo(ctx, repo, access_model.Permission{AccessMode: perm.AccessModeNone}),
|
|
Inputs: inputsAny,
|
|
Sender: convert.ToUserWithAccessMode(ctx, doer, perm.AccessModeNone),
|
|
}
|
|
|
|
eventPayload, err := workflowDispatchPayload.JSONPayload()
|
|
if err != nil {
|
|
return nil, fmt.Errorf("marshal event payload: %w", err)
|
|
}
|
|
run.EventPayload = string(eventPayload)
|
|
|
|
// 插入数据库
|
|
if err := db.Insert(ctx, run); err != nil {
|
|
return nil, fmt.Errorf("insert action run: %w", err)
|
|
}
|
|
|
|
log.Trace("Debug workflow created for run %d", run.ID)
|
|
|
|
return run, nil
|
|
}
|
|
|
|
// validateWorkflowContent 验证工作流内容
|
|
func validateWorkflowContent(content string) error {
|
|
_, err := jobparser.Parse([]byte(content))
|
|
return err
|
|
}
|
|
|
|
// GetDebugWorkflowRun 获取调试工作流运行详情
|
|
func GetDebugWorkflowRun(ctx reqctx.RequestContext, repoID, runID int64) (*actions_model.ActionRun, error) {
|
|
run, err := actions_model.GetRunByRepoAndID(ctx, repoID, runID)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("get run: %w", err)
|
|
}
|
|
|
|
// 检查这是否是调试工作流
|
|
if run.WorkflowID != "debug-workflow.yml" {
|
|
return nil, fmt.Errorf("not a debug workflow")
|
|
}
|
|
|
|
return run, nil
|
|
}
|