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

Method applyDefaults

pkg/workflow/tools.go:21–362  ·  view source on GitHub ↗

applyDefaults applies default values for missing workflow sections

(data *WorkflowData, markdownPath string)

Source from the content-addressed store, hash-verified

19
20// applyDefaults applies default values for missing workflow sections
21func (c *Compiler) applyDefaults(data *WorkflowData, markdownPath string) error {
22 toolsLog.Printf("Applying defaults to workflow: name=%s, path=%s", data.Name, markdownPath)
23
24 // Populate cached values after all mutations to Permissions and Concurrency have been applied.
25 // Using defer ensures the cache is always set on every return path, including early returns.
26 // applyDefaults is the final stage that mutates data.Permissions (setting defaults), so
27 // the values computed here represent the stable,
28 // final state that validateWorkflowData will use. These caches eliminate repeated
29 // YAML parsing, regex extraction, and expression parsing in the hot validateWorkflowData loop.
30 defer func() {
31 data.CachedPermissions = NewPermissionsParser(data.Permissions).ToPermissions()
32 data.CachedPermissionScopeNamesErr = ValidatePermissionScopeNames(data.Permissions)
33 data.CachedPermissionScopeNamesSet = true
34 data.ConcurrencyGroupExpr = extractConcurrencyGroupFromYAML(data.Concurrency)
35 // Pre-validate and cache the concurrency group expression so validateWorkflowData
36 // can short-circuit without re-running the expensive ExpressionParser on every call.
37 // CachedConcurrencyGroupExprSet is always true after applyDefaults regardless of whether
38 // a group expression exists, so callers can distinguish "already computed" from "not yet computed".
39 if data.ConcurrencyGroupExpr != "" {
40 data.CachedConcurrencyGroupExprErr = validateConcurrencyGroupExpression(data.ConcurrencyGroupExpr)
41 }
42 data.CachedConcurrencyGroupExprSet = true
43 // Cache the expanded + parsed toolsets for the GitHub tool so both
44 // ValidatePermissions and validateToolConfiguration reuse one result.
45 // Use GetToolsets() to stay aligned with the runtime normalization done by GitHubToolConfig.
46 if data.ParsedTools != nil && data.ParsedTools.GitHub != nil {
47 data.CachedParsedToolsets = ParseGitHubToolsets(data.ParsedTools.GitHub.GetToolsets())
48 }
49 }()
50
51 // Check if this is a command trigger workflow (by checking if user specified "on.command")
52 isCommandTrigger := false
53 isLabelCommandTrigger := false
54 if data.On == "" {
55 // parseOnSection may have already detected the command trigger and populated data.Command
56 // (this covers slash_command map format, slash_command shorthand "on: /name", and deprecated "command:")
57 if len(data.Command) > 0 {
58 isCommandTrigger = true
59 } else if len(data.LabelCommand) > 0 {
60 isLabelCommandTrigger = true
61 } else {
62 // Check the original frontmatter for command trigger
63 content, err := os.ReadFile(markdownPath)
64 if err == nil {
65 result, err := parser.ExtractFrontmatterFromContent(string(content))
66 if err == nil {
67 if onValue, exists := result.Frontmatter["on"]; exists {
68 // Check for slash_command or command (deprecated)
69 if onMap, ok := onValue.(map[string]any); ok {
70 if _, hasSlashCommand := onMap["slash_command"]; hasSlashCommand {
71 isCommandTrigger = true
72 } else if _, hasCommand := onMap["command"]; hasCommand {
73 isCommandTrigger = true
74 } else if _, hasLabelCommand := onMap["label_command"]; hasLabelCommand {
75 isLabelCommandTrigger = true
76 }
77 }
78 }