Return (content_keys, items_without_status, items_without_date). content_keys: {(repo_name, issue_or_pr_number), ...} — for the "is this linked to the project already?" check. items_without_status: [item_id, ...] — existing project items whose Status field is unset, needing a Tr
(
owner: str, number: int, status_field_name: str, date_field_name: str
)
| 69 | |
| 70 | |
| 71 | def fetch_project_items( |
| 72 | owner: str, number: int, status_field_name: str, date_field_name: str |
| 73 | ) -> tuple[set[tuple[str, int]], list[str], list[tuple[str, str]]]: # noqa: DCT002 |
| 74 | """Return (content_keys, items_without_status, items_without_date). |
| 75 | |
| 76 | content_keys: {(repo_name, issue_or_pr_number), ...} — for the |
| 77 | "is this linked to the project already?" check. |
| 78 | items_without_status: [item_id, ...] — existing project items whose |
| 79 | Status field is unset, needing a Triage assignment. |
| 80 | items_without_date: [(item_id, YYYY-MM-DD), ...] — existing project |
| 81 | items whose Date posted field is unset, needing the content's |
| 82 | createdAt (trimmed to date) written in. |
| 83 | """ |
| 84 | keys: set[tuple[str, int]] = set() |
| 85 | no_status: list[str] = [] |
| 86 | no_date: list[tuple[str, str]] = [] |
| 87 | cursor: str | None = None |
| 88 | while True: |
| 89 | after = f'"{cursor}"' if cursor else "null" |
| 90 | q = ( |
| 91 | 'query { organization(login: "' |
| 92 | + owner |
| 93 | + '") { projectV2(number: ' |
| 94 | + str(number) |
| 95 | + ") { items(first: 100, after: " |
| 96 | + after |
| 97 | + ") { pageInfo { hasNextPage endCursor } " |
| 98 | "nodes { id content { " |
| 99 | "... on Issue { number createdAt repository { name } } " |
| 100 | "... on PullRequest { number createdAt repository { name } } " |
| 101 | "} " |
| 102 | "fieldValues(first: 25) { nodes { " |
| 103 | "__typename " |
| 104 | "... on ProjectV2ItemFieldSingleSelectValue { " |
| 105 | "name field { ... on ProjectV2FieldCommon { name } } } " |
| 106 | "... on ProjectV2ItemFieldDateValue { " |
| 107 | "date field { ... on ProjectV2FieldCommon { name } } } " |
| 108 | "} } } } } } }" |
| 109 | ) |
| 110 | d = graphql(q) |
| 111 | items = d["data"]["organization"]["projectV2"]["items"] |
| 112 | for n in items["nodes"]: |
| 113 | c = n.get("content") |
| 114 | created_at: str | None = None |
| 115 | if c: |
| 116 | repo = (c.get("repository") or {}).get("name") |
| 117 | num = c.get("number") |
| 118 | created_at = c.get("createdAt") |
| 119 | if repo and isinstance(num, int): |
| 120 | keys.add((repo, num)) |
| 121 | # Scan field values for Status + Date posted. |
| 122 | has_status = False |
| 123 | has_date = False |
| 124 | for fv in (n.get("fieldValues") or {}).get("nodes") or []: |
| 125 | if not fv: |
| 126 | continue |
| 127 | fname = (fv.get("field") or {}).get("name") |
| 128 | typename = fv.get("__typename") |