MCPcopy Create free account
hub / github.com/github/gh-aw / IsRunnable

Function IsRunnable

pkg/cli/run_workflow_validation.go:34–83  ·  view source on GitHub ↗

IsRunnable checks if a workflow can be run (has schedule or workflow_dispatch trigger) This function checks the compiled .lock.yml file because that's what GitHub Actions uses.

(markdownPath string)

Source from the content-addressed store, hash-verified

32// IsRunnable checks if a workflow can be run (has schedule or workflow_dispatch trigger)
33// This function checks the compiled .lock.yml file because that's what GitHub Actions uses.
34func IsRunnable(markdownPath string) (bool, error) {
35 // Convert markdown path to lock file path
36 lockPath := getLockFilePath(markdownPath)
37 cleanLockPath := filepath.Clean(lockPath)
38
39 validationLog.Printf("Checking if workflow is runnable: markdown=%s, lock=%s", markdownPath, lockPath)
40
41 // Check if the lock file exists
42 if _, err := os.Stat(cleanLockPath); os.IsNotExist(err) {
43 validationLog.Printf("Lock file does not exist: %s", cleanLockPath)
44 return false, errors.New("workflow has not been compiled yet - run 'gh aw compile' first")
45 }
46
47 // Read the lock file - path is sanitized using filepath.Clean() to prevent path traversal attacks.
48 // The lockPath is derived from markdownPath which comes from trusted sources (CLI arguments, validated workflow paths).
49 contentBytes, err := os.ReadFile(cleanLockPath) // #nosec G304 -- path is sanitized with filepath.Clean() and derived from trusted CLI argument
50 if err != nil {
51 return false, fmt.Errorf("failed to read lock file: %w", err)
52 }
53
54 // Parse the YAML content
55 var workflowYAML map[string]any
56 if err := yaml.Unmarshal(contentBytes, &workflowYAML); err != nil {
57 return false, fmt.Errorf("failed to parse lock file YAML: %w", err)
58 }
59
60 // Check if 'on' section is present
61 onSection, exists := workflowYAML["on"]
62 if !exists {
63 validationLog.Printf("No 'on' section found in lock file")
64 // If no 'on' section, it's not runnable
65 return false, nil
66 }
67
68 // Convert to map if possible
69 onMap, ok := onSection.(map[string]any)
70 if !ok {
71 // If 'on' is not a map, check if it's a string/list that might indicate workflow_dispatch
72 onStr := fmt.Sprintf("%v", onSection)
73 onStrLower := strings.ToLower(onStr)
74 hasWorkflowDispatch := strings.Contains(onStrLower, "workflow_dispatch")
75 validationLog.Printf("On section is not a map, checking string: hasWorkflowDispatch=%v", hasWorkflowDispatch)
76 return hasWorkflowDispatch, nil
77 }
78
79 // Check if workflow_dispatch trigger exists
80 _, hasWorkflowDispatch := onMap["workflow_dispatch"]
81 validationLog.Printf("Workflow runnable check: hasWorkflowDispatch=%v", hasWorkflowDispatch)
82 return hasWorkflowDispatch, nil
83}
84
85// getWorkflowInputs extracts workflow_dispatch inputs from the compiled lock file
86// This function checks the .lock.yml file because that's what GitHub Actions uses.

Callers 7

TestIsRunnableFunction · 0.85
findRunnableWorkflowsFunction · 0.85
RunWorkflowOnGitHubFunction · 0.85
RunWorkflowsOnGitHubFunction · 0.85

Calls 4

getLockFilePathFunction · 0.85
ToLowerMethod · 0.80
PrintfMethod · 0.45
ErrorfMethod · 0.45

Tested by 4

TestIsRunnableFunction · 0.68