import re def parse_stages(content: str) -> list: # Try inline format: stages: a, b, c match = re.search(r"^stages:\s*(.+)$", content, re.MULTILINE) if match and "," in match.group(1) and "\n" not in match.group(1): return [s.strip() for s in match.group(1).split(",")] lines = content.splitlines() stages = [] in_stages_block = False for line in lines: if line.strip().startswith("stages:"): in_stages_block = True continue if in_stages_block: if line.strip().startswith("-"): stages.append(line.strip().lstrip("- ").strip()) elif line.strip() == "": continue else: break return stages def validate_ci_stages(ci_content: str): stages = parse_stages(ci_content) if not stages: raise ValueError("ci.yml has no valid stages defined.") if "install" not in stages or "test" not in stages: raise ValueError("ci.yml must define both 'install' and 'test' stages.") # Only check 'build' if it exists if "build" in stages: if stages.index("test") < stages.index("install") or stages.index("test") < stages.index("build"): raise ValueError("ci.yml stage ordering is invalid.") else: if stages.index("test") < stages.index("install"): raise ValueError("ci.yml stage ordering is invalid.")