Files
temp/features/steps/ci_workflow_validation_steps.py
T

117 lines
3.8 KiB
Python

"""Step definitions for CI workflow validation feature."""
from pathlib import Path
import yaml
from behave import given, then, when
@given('the CI workflow file at "{path}"')
def step_given_ci_workflow_file(context, path):
"""Store the CI workflow file path."""
context.ci_workflow_path = Path(path)
@then("the CI workflow file should exist")
def step_then_ci_workflow_exists(context):
"""Verify the CI workflow file exists."""
if not context.ci_workflow_path.exists():
raise AssertionError(
f"CI workflow file not found at {context.ci_workflow_path}"
)
@when("I parse the CI workflow YAML")
def step_when_parse_ci_workflow(context):
"""Parse the CI workflow YAML file."""
workflow_path = context.ci_workflow_path
if not workflow_path.exists():
raise FileNotFoundError(f"CI workflow file not found at {workflow_path}")
with workflow_path.open("r") as f:
context.ci_workflow = yaml.safe_load(f)
@then('the workflow should have a job named "{job_name}"')
def step_then_workflow_has_job(context, job_name):
"""Verify the workflow has a specific job."""
jobs = context.ci_workflow.get("jobs", {})
if job_name not in jobs:
raise AssertionError(
f"Job '{job_name}' not found in workflow. "
f"Available jobs: {list(jobs.keys())}"
)
@then('the job "{job_name}" should run "{command}"')
def step_then_job_runs_command(context, job_name, command):
"""Verify a job runs a specific command in one of its steps."""
jobs = context.ci_workflow.get("jobs", {})
job = jobs.get(job_name)
if job is None:
raise AssertionError(f"Job '{job_name}' not found in workflow")
steps = job.get("steps", [])
found = False
for step in steps:
run_cmd = step.get("run", "")
if command in run_cmd:
found = True
break
if not found:
step_runs = [s.get("run", "(no run)") for s in steps if "run" in s]
raise AssertionError(
f"Command '{command}' not found in job '{job_name}' steps. "
f"Step runs: {step_runs}"
)
@then('the workflow env should set "{key}" to "{value}"')
def step_then_workflow_env_set(context, key, value):
"""Verify a workflow-level environment variable is set."""
env = context.ci_workflow.get("env", {})
actual = env.get(key)
if actual != value:
raise AssertionError(f"Workflow env '{key}' expected '{value}', got '{actual}'")
@then('the job "{job_name}" should depend on "{dependency}"')
def step_then_job_depends_on(context, job_name, dependency):
"""Verify a job has a specific dependency."""
jobs = context.ci_workflow.get("jobs", {})
job = jobs.get(job_name)
if job is None:
raise AssertionError(f"Job '{job_name}' not found in workflow")
needs = job.get("needs", [])
if isinstance(needs, str):
needs = [needs]
if dependency not in needs:
raise AssertionError(
f"Job '{job_name}' does not depend on '{dependency}'. Dependencies: {needs}"
)
@then("the workflow should reference these nox sessions:")
def step_then_workflow_references_nox_sessions(context):
"""Verify all required nox sessions are referenced in the workflow."""
jobs = context.ci_workflow.get("jobs", {})
# Collect all run commands across all jobs
all_run_commands = ""
for job_data in jobs.values():
for step in job_data.get("steps", []):
run_cmd = step.get("run", "")
all_run_commands += run_cmd + "\n"
for row in context.table:
session_name = row["session"]
nox_call = f"nox -s {session_name}"
if nox_call not in all_run_commands:
raise AssertionError(
f"Nox session '{session_name}' (as '{nox_call}') "
f"not found in any CI workflow step"
)