Skip to content

Commit ec2a1d8

Browse files
CarliCarli
authored andcommitted
fix wrong Task Type
closes #6
1 parent 47fb49b commit ec2a1d8

File tree

4 files changed

+107
-7
lines changed

4 files changed

+107
-7
lines changed

CHANGELOG.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ Version 0.0.6
88
- Add shortcuts ``-u`` and ``-t`` for gitlab url and gitlab token
99
- Add `PreCommit`_ to prevent failing builds :issue:`4`
1010
- Fix Bug that percentage done was not calculated correctly :issue:`5`
11+
- Syncing always set Task Type to Fixed Work but revert to original after sync :issue:`6`
12+
- Adding parameter ``--force-fixed-work`` that does not reset the Task Type after sync
1113

1214
Version 0.0.5
1315
=============

src/syncgitlab2msproject/cli.py

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
get_group_issues,
2424
get_project_issues,
2525
)
26+
from syncgitlab2msproject.helper_classes import ForceFixedWork, SetTaskTypeConservative
2627
from syncgitlab2msproject.sync import sync_gitlab_issues_to_ms_project
2728

2829
_logger = logging.getLogger(f"{__package__}.{__name__}")
@@ -70,6 +71,14 @@ def parse_args(args):
7071
type=str,
7172
)
7273

74+
parser.add_argument(
75+
"--force-fixed-work",
76+
dest="fixed_work",
77+
help="Set all synced issued to fixed_work, overwriting "
78+
"also already existing tasks",
79+
action="store_true",
80+
)
81+
7382
# TODO read from ENV
7483
parser.add_argument(
7584
"--gitlab-url",
@@ -196,6 +205,11 @@ def main(args):
196205
else:
197206
raise ValueError("Invalid Resource Type")
198207

208+
if args.fixed_work:
209+
sync_task_helper = ForceFixedWork
210+
else:
211+
sync_task_helper = SetTaskTypeConservative
212+
199213
try:
200214
issues = get_issues_func(gitlab, args.gitlab_resource_id)
201215
except ConnectionError as e:
@@ -205,7 +219,7 @@ def main(args):
205219
include_issue = functools.partial(has_not_label, label=args.ignore_label)
206220
with MSProject(ms_project_file.absolute()) as tasks:
207221
sync_gitlab_issues_to_ms_project(
208-
tasks, issues, WebURL(args.gitlab_url), include_issue
222+
tasks, issues, WebURL(args.gitlab_url), sync_task_helper, include_issue
209223
)
210224
_logger.info("Finished syncing")
211225

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
from abc import ABC, abstractmethod
2+
from typing import Optional
3+
4+
from .gitlab_issues import Issue
5+
from .ms_project import PjTaskFixedType, Task
6+
7+
8+
class TaskTyperSetter(ABC):
9+
"""
10+
Abstract Base Class that is used to dynamically allow setting the task type
11+
"""
12+
13+
def __init__(self, issue: Issue) -> None:
14+
self._type_before_sync: Optional[PjTaskFixedType] = None
15+
self._effort_driven_before_sync: Optional[bool] = None
16+
self._is_initial: bool = False
17+
self.issue = Issue
18+
19+
@abstractmethod
20+
def set_task_type_before_sync(self, task: Task, is_initial: bool) -> None:
21+
"""
22+
Function that is called at the beginning of the sync
23+
"""
24+
25+
@abstractmethod
26+
def set_task_type_after_sync(self, task: Task) -> None:
27+
"""
28+
Function just before finishing the sync
29+
"""
30+
31+
32+
class SetTaskTypeConservative(TaskTyperSetter):
33+
"""
34+
Set Fixed Work as default creating a new task and before syncing any Task
35+
but make sure to reset to the original value (including Effort Driven Setting)
36+
after finishing the sync
37+
"""
38+
39+
def set_task_type_before_sync(self, task: Task, is_inital: bool) -> None:
40+
if task.has_children:
41+
# Can't update tasks with children
42+
return
43+
self._type_before_sync = task.type
44+
self._effort_driven_before_sync = task.effort_driven
45+
self._is_initial = is_inital
46+
task.type = PjTaskFixedType.pjFixedWork
47+
48+
def set_task_type_after_sync(self, task: Task) -> None:
49+
if task.has_children:
50+
# Can't update tasks with children
51+
return
52+
if not self._is_initial:
53+
assert self._effort_driven_before_sync is not None
54+
assert self._type_before_sync is not None
55+
# Only update if required
56+
if task.type != self._type_before_sync:
57+
task.type = self._type_before_sync
58+
if task.effort_driven != self._effort_driven_before_sync:
59+
task.effort_driven = self._effort_driven_before_sync
60+
61+
62+
class ForceFixedWork(SetTaskTypeConservative):
63+
"""
64+
No matter what always set Task Type to Fixed Work for all synced Task
65+
"""
66+
67+
def set_task_type_after_sync(self, task: Task) -> None:
68+
# Make sure the everything is FixedWork by default by not resetting it
69+
pass

src/syncgitlab2msproject/sync.py

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
import win32com.universal
22
from logging import getLogger
3-
from typing import Callable, Dict, List, Optional, overload
3+
from typing import Callable, Dict, List, Optional, Type, overload
44

55
from syncgitlab2msproject.custom_types import WebURL
6+
from syncgitlab2msproject.helper_classes import TaskTyperSetter
67

78
from .custom_types import IssueRef
89
from .exceptions import (
@@ -79,9 +80,11 @@ def check_get_url(value: Optional[str]) -> Optional[WebURL]:
7980
def update_task_with_issue_data(
8081
task: Task,
8182
issue: Issue,
83+
task_type_setter: Type[TaskTyperSetter],
8284
*,
8385
parent_ids: Optional[List[IssueRef]] = None,
8486
ignore_issue: bool = False,
87+
is_add: bool = False,
8588
) -> List[IssueRef]:
8689
"""
8790
Update task with issue data
@@ -91,9 +94,11 @@ def update_task_with_issue_data(
9194
Args:
9295
task: The MS Project task that will be updated
9396
issue: the issue with the data to be considered
97+
task_type_setter: Helper class to set the task type correct
9498
parent_ids: the parent stuff
9599
ignore_issue: only return the related (and moved) ids but do not really sync
96100
This is required so we can ignored also moved issues correctly
101+
is_add:
97102
98103
Returns:
99104
list of IssueRefs that
@@ -107,7 +112,11 @@ def update_task_with_issue_data(
107112
assert moved_ref is not None
108113
try:
109114
return update_task_with_issue_data(
110-
task, moved_ref, parent_ids=parent_ids, ignore_issue=ignore_issue
115+
task,
116+
moved_ref,
117+
task_type_setter,
118+
parent_ids=parent_ids,
119+
ignore_issue=ignore_issue,
111120
)
112121
except MovedIssueNotDefined:
113122
logger.warning(
@@ -117,6 +126,8 @@ def update_task_with_issue_data(
117126
elif not ignore_issue:
118127
set_issue_ref_to_task(task, issue)
119128
try:
129+
type_setter = task_type_setter(issue)
130+
type_setter.set_task_type_before_sync(task, is_add)
120131
task.name = issue.title
121132
task.notes = issue.description
122133
if issue.due_date is not None:
@@ -135,6 +146,7 @@ def update_task_with_issue_data(
135146
task.text28 = "; ".join([f'"{label}"' for label in issue.labels])
136147
if issue.is_closed:
137148
task.actual_finish = issue.closed_at
149+
type_setter.set_task_type_after_sync(task)
138150
except (MSProjectValueSetError, win32com.universal.com_error) as e:
139151
logger.error(
140152
f"FATAL: Could not sync issue {issue} to task {task}.\nError: {e}"
@@ -144,12 +156,14 @@ def update_task_with_issue_data(
144156
return parent_ids
145157

146158

147-
def add_issue_as_task_to_project(tasks: MSProject, issue: Issue):
159+
def add_issue_as_task_to_project(
160+
tasks: MSProject, issue: Issue, task_type_setter: Type[TaskTyperSetter]
161+
):
148162
task = tasks.add_task(issue.title)
149163
logger.info(f"Created {task} as it was missing for issue, now syncing it.")
150164
# Add a setting to allow forcing outline level on new tasks
151165
# task.outline_level = 1
152-
update_task_with_issue_data(task, issue)
166+
update_task_with_issue_data(task, issue, task_type_setter, is_add=True)
153167

154168

155169
class IssueFinder:
@@ -237,6 +251,7 @@ def sync_gitlab_issues_to_ms_project(
237251
tasks: MSProject,
238252
issues: List[Issue],
239253
gitlab_url: WebURL,
254+
task_type_setter: Type[TaskTyperSetter],
240255
include_issue: Optional[Callable[[Issue], bool]] = None,
241256
) -> None:
242257
"""
@@ -295,7 +310,7 @@ def always_true(x: Issue):
295310
# added and we also want make sure that moved ignored issues are handled
296311
# correctly
297312
synced += update_task_with_issue_data(
298-
task, ref_issue, ignore_issue=ignore_issue
313+
task, ref_issue, task_type_setter, ignore_issue=ignore_issue
299314
)
300315

301316
# adding everything that was not synced and is not duplicate
@@ -308,4 +323,4 @@ def always_true(x: Issue):
308323
f"as it has been marked to be ignored."
309324
)
310325
else:
311-
add_issue_as_task_to_project(tasks, ref_issue)
326+
add_issue_as_task_to_project(tasks, ref_issue, task_type_setter)

0 commit comments

Comments
 (0)