forked from chroe/gitlink-cli
83 lines
2.3 KiB
Go
83 lines
2.3 KiB
Go
package workflow
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"strings"
|
|
|
|
"github.com/gitlink-org/gitlink-cli/shortcuts/common"
|
|
)
|
|
|
|
// WorkflowResult holds the outcome of a full workflow run.
|
|
type WorkflowResult struct {
|
|
Workflow string `json:"workflow"`
|
|
Owner string `json:"owner"`
|
|
Repo string `json:"repo"`
|
|
Steps []StepResult `json:"steps"`
|
|
}
|
|
|
|
// Run executes every step in a workflow sequentially.
|
|
// Steps later in the sequence receive data from their DependsOn predecessors
|
|
// via ctx.Args (keyed by step name, stored as JSON).
|
|
// Set dryRun to true to skip AI API calls for skill steps.
|
|
func Run(ctx *common.RuntimeContext, wf *WorkflowDef, dryRun bool) (*WorkflowResult, error) {
|
|
return RunWithMode(ctx, wf, dryRun, "")
|
|
}
|
|
|
|
// RunWithMode executes a workflow with explicit AI mode control.
|
|
// aiMode must be "auto", "ai", "no-ai", or "" (equivalent to "auto").
|
|
func RunWithMode(ctx *common.RuntimeContext, wf *WorkflowDef, dryRun bool, aiMode string) (*WorkflowResult, error) {
|
|
if aiMode != "" {
|
|
ctx.AIMode = aiMode
|
|
}
|
|
return run(ctx, wf, dryRun)
|
|
}
|
|
|
|
func run(ctx *common.RuntimeContext, wf *WorkflowDef, dryRun bool) (*WorkflowResult, error) {
|
|
if err := ctx.ResolveOwnerRepo(); err != nil {
|
|
return nil, fmt.Errorf("resolve repo: %w", err)
|
|
}
|
|
|
|
if ctx.Args == nil {
|
|
ctx.Args = make(map[string]string)
|
|
}
|
|
if _, ok := ctx.Args["dry_run"]; !ok && dryRun {
|
|
ctx.Args["dry_run"] = "true"
|
|
}
|
|
|
|
results := make([]StepResult, 0, len(wf.Steps))
|
|
for _, step := range wf.Steps {
|
|
sr := ExecuteStep(ctx, step, dryRun)
|
|
results = append(results, *sr)
|
|
|
|
// Feed output of this step as input to downstream steps via Args.
|
|
if sr.OK && sr.Data != nil {
|
|
raw, err := json.Marshal(sr.Data)
|
|
if err == nil {
|
|
ctx.Args[step.Name] = string(raw)
|
|
} else {
|
|
ctx.Args[step.Name] = fmt.Sprint(sr.Data)
|
|
}
|
|
}
|
|
}
|
|
|
|
return &WorkflowResult{
|
|
Workflow: wf.Name,
|
|
Owner: ctx.Owner,
|
|
Repo: ctx.Repo,
|
|
Steps: results,
|
|
}, nil
|
|
}
|
|
|
|
// resolvePath replaces template placeholders in a path string.
|
|
//
|
|
// {base} → /owner/repo
|
|
// {v1} → /v1/owner/repo
|
|
func resolvePath(template, owner, repo string) string {
|
|
base := fmt.Sprintf("/%s/%s", owner, repo)
|
|
v1 := fmt.Sprintf("/v1/%s/%s", owner, repo)
|
|
s := strings.Replace(template, "{v1}", v1, 1)
|
|
s = strings.Replace(s, "{base}", base, 1)
|
|
return s
|
|
}
|