Created
January 29, 2025 22:21
-
-
Save 0xack13/6aa3f2a491ffd703995817cbf6a8d980 to your computer and use it in GitHub Desktop.
gha_map
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import os | |
import yaml | |
from pathlib import Path | |
import argparse | |
def find_called_workflows(file_path): | |
"""Parse a workflow file to find referenced workflows.""" | |
called_workflows = set() | |
with open(file_path, "r") as f: | |
try: | |
data = yaml.safe_load(f) | |
if not isinstance(data, dict): | |
return called_workflows | |
jobs = data.get("jobs", {}) | |
for job in jobs.values(): | |
if isinstance(job, dict): | |
steps = job.get("steps", []) | |
for step in steps: | |
if isinstance(step, dict): | |
uses = step.get("uses") | |
if uses and uses.startswith("./.github/workflows/"): | |
called_workflows.add(uses.replace("./", "")) | |
except yaml.YAMLError: | |
pass | |
return called_workflows | |
def build_workflow_tree(directory): | |
"""Build a tree of workflows and their dependencies.""" | |
workflow_tree = {} | |
for workflow_file in Path(directory).glob("*.yml") | Path(directory).glob("*.yaml"): | |
workflow_tree[workflow_file.name] = find_called_workflows(workflow_file) | |
return workflow_tree | |
def print_tree(tree, root, prefix=""): | |
"""Recursively print the workflow tree.""" | |
print(prefix + "├── " + root) | |
children = tree.get(root, []) | |
for idx, child in enumerate(children): | |
new_prefix = prefix + ("│ " if idx < len(children) - 1 else " ") | |
print_tree(tree, child, new_prefix) | |
def main(): | |
parser = argparse.ArgumentParser(description="Visualize GitHub Actions workflow dependencies.") | |
parser.add_argument("-r", "--root", help="Specify a workflow file as the root", default=None) | |
args = parser.parse_args() | |
workflows_dir = Path(".github/workflows") | |
if not workflows_dir.exists(): | |
print("No workflows directory found.") | |
return | |
workflow_tree = build_workflow_tree(workflows_dir) | |
if args.root: | |
if args.root not in workflow_tree: | |
print(f"Specified root '{args.root}' not found in workflows.") | |
return | |
print_tree(workflow_tree, args.root) | |
else: | |
roots = set(workflow_tree.keys()) - {w for deps in workflow_tree.values() for w in deps} | |
for root in sorted(roots): | |
print_tree(workflow_tree, root) | |
if __name__ == "__main__": | |
main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment