File size: 1,367 Bytes
a7caaff
4b07aaf
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
"""YAML parsing helpers."""

from typing import Any, Optional, Tuple

import yaml


def safe_parse_yaml(content: str) -> Tuple[Optional[Any], Optional[str]]:
    """Parse YAML content safely.

    Returns (parsed, error_message). If parsing succeeds, error_message is None.
    If parsing fails, parsed is None and error_message contains the description.
    """
    try:
        parsed = yaml.safe_load(content)
        return parsed, None
    except yaml.YAMLError as exc:
        return None, str(exc)


def is_valid_workflow(content: str) -> Tuple[bool, Optional[str]]:
    """Check if content is a valid GitHub Actions workflow YAML.

    Returns (is_valid, error_message).
    """
    parsed, err = safe_parse_yaml(content)
    if err:
        return False, f"YAML parse error: {err}"
    if not isinstance(parsed, dict):
        return False, "Workflow root must be a mapping"
    if "jobs" not in parsed:
        return False, "Workflow must define 'jobs'"
    jobs = parsed.get("jobs")
    if not isinstance(jobs, dict) or not jobs:
        return False, "Workflow must define at least one job"
    for job_name, job in jobs.items():
        if not isinstance(job, dict):
            return False, f"Job '{job_name}' must be a mapping"
        if "runs-on" not in job:
            return False, f"Job '{job_name}' is missing 'runs-on'"
    return True, None