Files
devstar/services/actions/debug_workflow.go

174 lines
5.1 KiB
Go
Raw Normal View History

2025-11-20 21:12:51 +08:00
// Copyright 2025 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package actions
import (
"fmt"
actions_model "code.gitea.io/gitea/models/actions"
"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/actions"
"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"
webhook_module "code.gitea.io/gitea/modules/webhook"
"code.gitea.io/gitea/services/convert"
notify_service "code.gitea.io/gitea/services/notify"
"github.com/nektos/act/pkg/jobparser"
)
// DebugWorkflow starts a debug run for a workflow
func DebugWorkflow(ctx reqctx.RequestContext, doer *user_model.User, repo *repo_model.Repository,
gitRepo *git.Repository, debugSessionID int64, workflowContent string, ref string,
event string, inputs map[string]string, env map[string]string) (int64, error) {
if workflowContent == "" {
return 0, fmt.Errorf("workflow content is empty")
}
if ref == "" {
ref = repo.DefaultBranch
}
if event == "" {
event = "push"
}
// Get target commit from ref
refName := git.RefName(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 {
refName = git.RefNameFromBranch(ref)
runTargetCommit, err = gitRepo.GetBranchCommit(ref)
}
if err != nil {
return 0, fmt.Errorf("failed to get commit: %w", err)
}
// Parse workflow from content
workflows, err := jobparser.Parse([]byte(workflowContent))
if err != nil {
return 0, fmt.Errorf("failed to parse workflow: %w", err)
}
if len(workflows) == 0 {
return 0, fmt.Errorf("no workflows found in content")
}
// Create action run
run := &actions_model.ActionRun{
Title: fmt.Sprintf("Debug: %s", workflows[0].Name),
RepoID: repo.ID,
Repo: repo,
OwnerID: repo.OwnerID,
WorkflowID: fmt.Sprintf("debug_%d", debugSessionID),
TriggerUserID: doer.ID,
TriggerUser: doer,
Ref: string(refName),
CommitSHA: runTargetCommit.ID.String(),
IsForkPullRequest: false,
Event: webhook_module.HookEventType(event),
TriggerEvent: event,
Status: actions_model.StatusWaiting,
}
// Build event payload
eventPayload := map[string]interface{}{
"inputs": inputs,
"ref": ref,
}
// Convert to API payload
workflowDispatchPayload := &api.WorkflowDispatchPayload{
Workflow: fmt.Sprintf("debug_%d", debugSessionID),
Ref: ref,
Repository: convert.ToRepo(ctx, repo, access_model.Permission{AccessMode: perm.AccessModeNone}),
Inputs: eventPayload,
Sender: convert.ToUserWithAccessMode(ctx, doer, perm.AccessModeNone),
}
var eventPayloadBytes []byte
if eventPayloadBytes, err = workflowDispatchPayload.JSONPayload(); err != nil {
return 0, fmt.Errorf("JSONPayload: %w", err)
}
run.EventPayload = string(eventPayloadBytes)
// Insert the action run and its associated jobs into the database
if err := actions_model.InsertRun(ctx, run, workflows); err != nil {
return 0, fmt.Errorf("InsertRun: %w", err)
}
// Update debug session with run ID
debugSession, err := actions_model.GetDebugSession(ctx, debugSessionID)
if err == nil && debugSession != nil {
debugSession.RunID = run.ID
debugSession.Status = actions_model.DebugSessionStatusRunning
_ = actions_model.UpdateDebugSession(ctx, debugSession)
}
// Trigger notification to start the run
notify_service.WorkflowRunStatusUpdate(ctx, run.Repo, run.TriggerUser, run)
log.Info("Debug workflow started: run_id=%d, debug_session_id=%d", run.ID, debugSessionID)
return run.Index, nil
}
// GetDebugWorkflowStatus returns the status of a debug workflow run
func GetDebugWorkflowStatus(ctx reqctx.RequestContext, debugSessionID int64) (*actions_model.ActionRun, error) {
debugSession, err := actions_model.GetDebugSession(ctx, debugSessionID)
if err != nil {
return nil, err
}
if debugSession.RunID == 0 {
return nil, nil // Not run yet
}
return actions_model.GetRunByRepoAndID(ctx, debugSession.RepoID, debugSession.RunID)
}
// GetDebugSessionWorkflowContent retrieves the workflow content from repository for a debug session
func GetDebugSessionWorkflowContent(ctx reqctx.RequestContext, repo *repo_model.Repository, gitRepo *git.Repository,
workflowID string) (string, error) {
// Get default branch commit
commit, err := gitRepo.GetBranchCommit(repo.DefaultBranch)
if err != nil {
return "", err
}
// List workflows
_, entries, err := actions.ListWorkflows(commit)
if err != nil {
return "", err
}
// Find the workflow file
for _, entry := range entries {
if entry.Name() == workflowID {
content, err := actions.GetContentFromEntry(entry)
if err != nil {
return "", err
}
return string(content), nil
}
}
return "", fmt.Errorf("workflow %q not found", workflowID)
}