Created
September 16, 2026 15:43
-
-
Save derekxmartin/2d72e269a11bb7bc0eda1f783be21ee2 to your computer and use it in GitHub Desktop.
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
| #!/usr/bin/env python3 | |
| """Extract required fields from Jira createmeta JSON. Prints to STDOUT. | |
| Usage: | |
| python3 required_fields.py < createmeta.json | |
| python3 required_fields.py createmeta.json | |
| curl ... | python3 required_fields.py | |
| """ | |
| from __future__ import annotations | |
| import json | |
| import sys | |
| from typing import Any, Iterable | |
| def _load(src: Any) -> Any: | |
| data = json.load(src) | |
| if isinstance(data, str): | |
| data = json.loads(data) | |
| return data | |
| def _as_field_items(fields: Any) -> Iterable[tuple[str, dict]]: | |
| if isinstance(fields, dict): | |
| for key, meta in fields.items(): | |
| if isinstance(meta, dict): | |
| yield key, meta | |
| return | |
| if isinstance(fields, list): | |
| for meta in fields: | |
| if not isinstance(meta, dict): | |
| continue | |
| key = meta.get("fieldId") or meta.get("key") or meta.get("id") | |
| if key: | |
| yield str(key), meta | |
| def _collect_from_fields(fields: Any, out: list[dict]) -> None: | |
| for field_id, meta in _as_field_items(fields): | |
| if not meta.get("required"): | |
| continue | |
| out.append( | |
| { | |
| "id": field_id, | |
| "name": meta.get("name") or field_id, | |
| "hasDefaultValue": bool(meta.get("hasDefaultValue")), | |
| "schema": (meta.get("schema") or {}).get("type"), | |
| "custom": (meta.get("schema") or {}).get("custom"), | |
| "allowedValues": [ | |
| v.get("name") or v.get("value") or v.get("id") | |
| for v in (meta.get("allowedValues") or []) | |
| if isinstance(v, dict) | |
| ], | |
| } | |
| ) | |
| def extract_required(data: Any) -> list[dict]: | |
| required: list[dict] = [] | |
| # Shape A: GET /issue/createmeta/{project}/issuetypes/{issueTypeId} | |
| # { "values": [ { "fieldId": "summary", "required": true, ... }, ... ] } | |
| if isinstance(data, dict) and isinstance(data.get("values"), list): | |
| sample = data["values"][0] if data["values"] else {} | |
| if isinstance(sample, dict) and ( | |
| "fieldId" in sample or "required" in sample or "schema" in sample | |
| ): | |
| _collect_from_fields(data["values"], required) | |
| return required | |
| # Shape B: classic createmeta | |
| # { "projects": [ { "issuetypes": [ { "fields": { "summary": {...} } } ] } ] } | |
| if isinstance(data, dict) and isinstance(data.get("projects"), list): | |
| for project in data["projects"]: | |
| for itype in project.get("issuetypes") or []: | |
| _collect_from_fields(itype.get("fields"), required) | |
| return required | |
| # Shape C: a single issue type object with "fields" | |
| if isinstance(data, dict) and "fields" in data: | |
| _collect_from_fields(data.get("fields"), required) | |
| return required | |
| # Shape D: raw fields dict / list | |
| if isinstance(data, (dict, list)): | |
| _collect_from_fields(data, required) | |
| return required | |
| def main() -> int: | |
| try: | |
| if len(sys.argv) > 1 and sys.argv[1] != "-": | |
| with open(sys.argv[1], encoding="utf-8") as fh: | |
| data = _load(fh) | |
| else: | |
| if sys.stdin.isatty(): | |
| print("Pass JSON on stdin or as a file argument.", file=sys.stderr) | |
| return 2 | |
| data = _load(sys.stdin) | |
| except (OSError, json.JSONDecodeError) as exc: | |
| print(f"error: {exc}", file=sys.stderr) | |
| return 1 | |
| required = extract_required(data) | |
| if not required: | |
| print("No required fields found.", file=sys.stderr) | |
| return 0 | |
| for field in required: | |
| extras = [] | |
| if field["hasDefaultValue"]: | |
| extras.append("default") | |
| if field["schema"]: | |
| extras.append(field["schema"]) | |
| if field["custom"]: | |
| extras.append(field["custom"].rsplit(":", 1)[-1]) | |
| suffix = f" ({', '.join(extras)})" if extras else "" | |
| print(f"{field['id']}\t{field['name']}{suffix}") | |
| if field["allowedValues"]: | |
| print(f" allowed: {', '.join(str(v) for v in field['allowedValues'][:20])}") | |
| return 0 | |
| if __name__ == "__main__": | |
| raise SystemExit(main()) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment