| 272 | } |
| 273 | |
| 274 | func parseWorkflowSpec(spec string) (*WorkflowSpec, error) { |
| 275 | specLog.Printf("Parsing workflow spec: %q", spec) |
| 276 | |
| 277 | // Check if this is a GitHub URL |
| 278 | if strings.HasPrefix(spec, "http://") || strings.HasPrefix(spec, "https://") { |
| 279 | specLog.Print("Detected URL format") |
| 280 | // Try to parse as a recognized GitHub URL first. |
| 281 | parsedURL, urlErr := url.Parse(spec) |
| 282 | if urlErr == nil && isGitHubHost(parsedURL.Host) { |
| 283 | specLog.Print("Detected GitHub URL format") |
| 284 | // Rewrite dotcom automations UI URLs to the CAPI endpoint before further parsing. |
| 285 | if capiURL, ok := rewriteAutomationsURL(parsedURL); ok { |
| 286 | specLog.Printf("Rewrote automations UI URL to CAPI URL") |
| 287 | return &WorkflowSpec{ |
| 288 | RawURL: capiURL, |
| 289 | WorkflowName: genericURLWorkflowName(capiURL), |
| 290 | }, nil |
| 291 | } |
| 292 | return parseGitHubURL(spec) |
| 293 | } |
| 294 | // Non-GitHub HTTP(S) URL: return a generic URL spec whose content will be |
| 295 | // fetched at resolution time and dispatched on Content-Type. |
| 296 | if urlErr != nil { |
| 297 | return nil, fmt.Errorf("invalid URL %q: %w", spec, urlErr) |
| 298 | } |
| 299 | if parsedURL.Scheme != "http" && parsedURL.Scheme != "https" { |
| 300 | return nil, fmt.Errorf("unsupported URL scheme %q: only http and https are supported", parsedURL.Scheme) |
| 301 | } |
| 302 | specLog.Printf("Detected generic import URL: %s", spec) |
| 303 | return &WorkflowSpec{ |
| 304 | RawURL: spec, |
| 305 | WorkflowName: genericURLWorkflowName(spec), |
| 306 | }, nil |
| 307 | } |
| 308 | |
| 309 | // Check if this is a local path |
| 310 | if isLocalWorkflowPath(spec) { |
| 311 | specLog.Print("Detected local path format") |
| 312 | |
| 313 | ws, err := parseLocalWorkflowSpec(spec) |
| 314 | if err != nil { |
| 315 | return nil, err |
| 316 | } |
| 317 | |
| 318 | // Detect local wildcard specs like "./*.md" and mark them so that |
| 319 | // downstream expansion (e.g., expandLocalWildcardWorkflows) can run. |
| 320 | if strings.ContainsAny(spec, "*?[") { |
| 321 | ws.IsWildcard = true |
| 322 | // Ensure a stable WorkflowName for wildcard specs. |
| 323 | if ws.WorkflowName == "" { |
| 324 | ws.WorkflowName = spec |
| 325 | } |
| 326 | } |
| 327 | |
| 328 | return ws, nil |
| 329 | } |
| 330 | |
| 331 | // Handle version first (anything after @) |