fetchAndSaveRemoteIncludes parses the workflow content for @include directives and fetches them from the remote source
(content string, spec *WorkflowSpec, targetDir string, verbose bool, force bool, tracker *FileTracker)
| 409 | |
| 410 | // fetchAndSaveRemoteIncludes parses the workflow content for @include directives and fetches them from the remote source |
| 411 | func fetchAndSaveRemoteIncludes(content string, spec *WorkflowSpec, targetDir string, verbose bool, force bool, tracker *FileTracker) error { |
| 412 | remoteWorkflowLog.Printf("Fetching remote includes for workflow: %s", spec.String()) |
| 413 | |
| 414 | // Parse the workflow content to find @include directives |
| 415 | scanner := bufio.NewScanner(strings.NewReader(content)) |
| 416 | seen := make(map[string]struct { |
| 417 | }) |
| 418 | |
| 419 | for scanner.Scan() { |
| 420 | line := scanner.Text() |
| 421 | matches := includeDirectivePattern.FindStringSubmatch(line) |
| 422 | if matches == nil { |
| 423 | continue |
| 424 | } |
| 425 | |
| 426 | isOptional := matches[1] == "?" |
| 427 | includePath := strings.TrimSpace(matches[2]) |
| 428 | |
| 429 | // Remove section reference for file fetching |
| 430 | filePath := includePath |
| 431 | if before, _, ok := strings.Cut(includePath, "#"); ok { |
| 432 | filePath = before |
| 433 | } |
| 434 | |
| 435 | // Skip if already processed |
| 436 | if setutil.Contains(seen, filePath) { |
| 437 | continue |
| 438 | } |
| 439 | seen[filePath] = struct { |
| 440 | }{} |
| 441 | |
| 442 | // Fetch the include file |
| 443 | includeContent, _, err := FetchIncludeFromSource(includePath, spec, verbose) |
| 444 | if err != nil { |
| 445 | if isOptional { |
| 446 | if verbose { |
| 447 | fmt.Fprintln(os.Stderr, console.FormatWarningMessage("Optional include not found: "+includePath)) |
| 448 | } |
| 449 | continue |
| 450 | } |
| 451 | return fmt.Errorf("failed to fetch include %s: %w", includePath, err) |
| 452 | } |
| 453 | |
| 454 | // Determine target path for the include file |
| 455 | var targetPath string |
| 456 | if strings.HasPrefix(filePath, "shared/") { |
| 457 | // shared/ files go to .github/shared/ |
| 458 | targetPath = filepath.Join(filepath.Dir(targetDir), filePath) |
| 459 | } else if isWorkflowSpecFormat(filePath) { |
| 460 | // Workflowspec includes: extract just the filename and put in shared/ |
| 461 | parts := strings.Split(filePath, "/") |
| 462 | filename := parts[len(parts)-1] |
| 463 | targetPath = filepath.Join(filepath.Dir(targetDir), "shared", filename) |
| 464 | } else { |
| 465 | // Relative includes go alongside the workflow |
| 466 | targetPath = filepath.Join(targetDir, filePath) |
| 467 | } |
| 468 |
no test coverage detected