#!/usr/bin/env python3 """ Create an Aha epic in a target release using credentials from ~/.mcporter/mcporter.json. Usage: python3 skills/epics-standards/scripts/aha_create_epic.py \ --release MDM-R-889 \ --name "RDM PrivateLink on AWS" \ --description "Tracks Jira epic RP-176273 (...)" \ --jira-key RP-176273 """ from __future__ import annotations import argparse import json import pathlib import sys import urllib.error import urllib.parse import urllib.request MCPORTER_CONFIG = pathlib.Path.home() / ".mcporter" / "mcporter.json" def load_aha_env() -> dict[str, str]: cfg = json.loads(MCPORTER_CONFIG.read_text()) env = cfg["mcpServers"]["aha"]["env"] return {"domain": env["AHA_DOMAIN"], "token": env["AHA_API_TOKEN"]} def request(method: str, url: str, token: str, payload: dict | None = None) -> dict: headers = { "Authorization": f"Bearer {token}", "Accept": "application/json", "Content-Type": "application/json", } body = None if payload is None else json.dumps(payload).encode("utf-8") req = urllib.request.Request(url, data=body, headers=headers, method=method) with urllib.request.urlopen(req, timeout=30) as resp: return json.loads(resp.read().decode("utf-8")) def release_ref_from_name(domain: str, token: str, release_name: str) -> str: q = urllib.parse.quote(release_name) url = f"https://{domain}.aha.io/api/v1/releases?q={q}&per_page=200" data = request("GET", url, token) for rel in data.get("releases", []): if rel.get("name") == release_name: return rel["reference_num"] raise ValueError(f"Release not found by name: {release_name}") def main() -> int: parser = argparse.ArgumentParser() parser.add_argument("--release", required=True, help="Release reference (e.g. MDM-R-889) or exact release name (e.g. 2026.2.0.0)") parser.add_argument("--name", required=True, help="Aha epic name") parser.add_argument("--description", required=True, help="Aha epic description/body") parser.add_argument("--jira-key", required=False, help="Optional Jira key to print linking reminder") args = parser.parse_args() try: aha = load_aha_env() release = args.release if not release.startswith("MDM-R-"): release = release_ref_from_name(aha["domain"], aha["token"], release) url = f"https://{aha['domain']}.aha.io/api/v1/releases/{release}/epics" payload = {"epic": {"name": args.name, "description": args.description}} data = request("POST", url, aha["token"], payload) epic = data.get("epic", {}) print(json.dumps( { "aha_reference": epic.get("reference_num"), "aha_url": epic.get("url"), "release": release, "jira_key": args.jira_key, }, ensure_ascii=True, )) if args.jira_key and epic.get("url"): print( f"Next: set Jira {args.jira_key} Aha! Reference = {epic['url']}", file=sys.stderr, ) return 0 except (KeyError, FileNotFoundError, ValueError) as exc: print(f"Config/input error: {exc}", file=sys.stderr) return 2 except urllib.error.HTTPError as exc: detail = exc.read().decode("utf-8", errors="replace") print(f"Aha API HTTP {exc.code}: {detail}", file=sys.stderr) return 3 except Exception as exc: # noqa: BLE001 print(f"Unexpected error: {exc}", file=sys.stderr) return 1 if __name__ == "__main__": raise SystemExit(main())