55
66from tqdm import tqdm
77
8- from gh_task .project import Project
8+ from gh_task .project import Project , UPDATE_STATUS_MUTATION
99
1010from .taskfile import TaskFile
1111
1717_FAILURE_LABEL = "⨉"
1818_SUCCESS_COLOR = "2da44e"
1919_FAILURE_COLOR = "d73a4a"
20+ _OWNER_PREFIX = "owner:"
2021
2122
2223def _canonical_task_name (path ):
@@ -42,6 +43,63 @@ def project_url(project):
4243 return f"https://github.com/{ owner } /projects/{ number } "
4344
4445
46+ def reset_project_tasks (project , name , description = False ):
47+ """Reset owned issues in a project back to Ready."""
48+ project = Project (project , name )
49+ owner_projects = {}
50+ issues = []
51+ for status in project .statuses ():
52+ for issue in project .list (status , return_issue = True ):
53+ issue = project .get_issue (issue , require_project_item = True )
54+ labels = issue .labels or []
55+ owner_labels = [label for label in labels if label .lower ().startswith (_OWNER_PREFIX )]
56+ if not owner_labels :
57+ continue
58+ issues .append ((issue , owner_labels ))
59+
60+ ready_name , ready_option = project ._resolve_status ("Ready" )
61+ project ._ensure_project_loaded ()
62+ try :
63+ project ._resolve_number_field ("Estimate" )
64+ estimate_supported = True
65+ except Exception :
66+ estimate_supported = False
67+
68+ for issue , owner_labels in issues :
69+ owner_name = None
70+ for label in owner_labels :
71+ parts = label .split (":" , 1 )
72+ if len (parts ) == 2 and parts [1 ].strip ():
73+ owner_name = parts [1 ].strip ()
74+ break
75+ if owner_name and estimate_supported :
76+ owner_project = owner_projects .get (owner_name )
77+ if owner_project is None :
78+ owner_project = Project (project .owner + "/projects/" + str (project .number ), owner_name )
79+ owner_projects [owner_name ] = owner_project
80+ owner_project .set_estimate (issue , None )
81+ for label in owner_labels :
82+ project ._remove_label (issue , label )
83+ project ._remove_label (issue , _SUCCESS_LABEL )
84+ project ._remove_label (issue , _FAILURE_LABEL )
85+ if (issue .status or "" ).lower () != ready_name .lower ():
86+ project .client .graphql (
87+ UPDATE_STATUS_MUTATION ,
88+ {
89+ "projectId" : project ._project_id ,
90+ "itemId" : issue .project_item_id ,
91+ "fieldId" : project ._status_field_id ,
92+ "optionId" : ready_option ,
93+ },
94+ )
95+ if description :
96+ body = issue .body if issue .body is not None else project .get_issue_body (issue )
97+ cleaned = _strip_progress_section (body )
98+ if cleaned != body :
99+ project .set_issue_body (issue , cleaned )
100+ return [issue for issue , _labels in issues ]
101+
102+
45103def _task_file_map (task_files ):
46104 mapping = {}
47105 for path in task_files :
0 commit comments