Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 5 additions & 7 deletions .github/runner-config.yml
Original file line number Diff line number Diff line change
@@ -1,23 +1,21 @@
# Runner label → GPU hardware mapping
# Used by frameworks-devops-dashboard to display GPU architecture
# Update this when runners are added/changed in CI workflows
runners:
linux-flydsl-mi325-1:
gpu_arch: MI325
gpu_count: 1

linux-flydsl-mi325-8:
gpu_arch: MI325
gpu_count: 8

linux-flydsl-mi355-1:
gpu_arch: MI355
gpu_count: 1

linux-flydsl-mi355-8:
gpu_arch: MI355
gpu_count: 8

linux-flydsl-navi-2:
gpu_arch: gfx1201
gpu_count: 4
gpu_arch: Navi
gpu_count: 2
build-only-flydsl:
gpu_arch: "-"
gpu_count: "-"
118 changes: 118 additions & 0 deletions .github/scripts/list_jobs.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
#!/usr/bin/env python3
import argparse
import json
import re
from pathlib import Path

import yaml


def parse_args():
parser = argparse.ArgumentParser(description="Parse workflow files and output job matrix for GitHub Actions.")
parser.add_argument(
"--workflow-dir",
default=".github/workflows",
help="Directory containing workflow yaml files.",
)
parser.add_argument(
"--workflows",
default="",
help="Comma-separated workflow file names. Empty means auto-discover.",
)
parser.add_argument(
"--exclude-workflows",
default="",
help="Comma-separated workflow file names to skip.",
)
parser.add_argument(
"--exclude-jobs",
default="",
help="Comma-separated job IDs or display names to skip.",
)
parser.add_argument("--out-matrix", required=True, help="Output path for matrix JSON.")
parser.add_argument(
"--out-workflow-map",
required=True,
help="Output path for workflow -> jobs mapping JSON.",
)
return parser.parse_args()


def parse_csv(raw: str):
return [item.strip() for item in raw.split(",") if item.strip()]


def discover_workflows(workflow_dir: Path):
return sorted(
[path.name for path in workflow_dir.glob("*.yml") if path.is_file()]
+ [path.name for path in workflow_dir.glob("*.yaml") if path.is_file()]
)


def resolve_display_name(job_id: str, job_def):
raw_name = job_def.get("name") if isinstance(job_def, dict) else None
if not isinstance(raw_name, str):
return job_id
if "${{" not in raw_name:
return raw_name

display_name = re.sub(r"\$\{\{.*?\}\}", "", raw_name)
display_name = re.sub(r"\s*\(\s*\)\s*$", "", display_name)
display_name = re.sub(r"\s*/\s*$", "", display_name)
display_name = " ".join(display_name.split())
return display_name or job_id


def main():
args = parse_args()
workflow_dir = Path(args.workflow_dir)
excluded_workflows = set(parse_csv(args.exclude_workflows))
excluded_jobs = set(parse_csv(args.exclude_jobs))

if args.workflows.strip():
workflow_files = parse_csv(args.workflows)
else:
workflow_files = discover_workflows(workflow_dir)

workflow_files = [wf for wf in workflow_files if wf not in excluded_workflows]

matrix = []
workflow_map = {}

for workflow_file in workflow_files:
workflow_path = workflow_dir / workflow_file
if not workflow_path.exists():
continue

with workflow_path.open("r", encoding="utf-8") as file_obj:
content = yaml.safe_load(file_obj) or {}

jobs_dict = content.get("jobs") or {}

display_names = []
for job_id in jobs_dict.keys():
job_def = jobs_dict.get(job_id) or {}
display_name = resolve_display_name(job_id, job_def)
if job_id in excluded_jobs or display_name in excluded_jobs:
continue

display_names.append(display_name)
matrix.append(
{
"workflow": workflow_file,
"job_id": job_id,
"job_name": display_name,
}
)

workflow_map[workflow_file] = display_names

Path(args.out_matrix).write_text(json.dumps(matrix, ensure_ascii=False), encoding="utf-8")
Path(args.out_workflow_map).write_text(json.dumps(workflow_map, ensure_ascii=False), encoding="utf-8")

print(f"Discovered workflows: {len(workflow_map)}")
print(f"Total jobs in matrix: {len(matrix)}")


if __name__ == "__main__":
main()
Loading
Loading