Skip to content

Commit 93fbdbd

Browse files
committed
🔀 merge from main
2 parents 3f02216 + 33f4635 commit 93fbdbd

File tree

3 files changed

+42
-38
lines changed

3 files changed

+42
-38
lines changed

‎README.md

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -21,25 +21,27 @@ Meet the scripted Jira worklogging! Give it your worklogs in a CSV file (and you
2121
## Configuration
2222

2323
The jwl.config file is a simple JSON structure. It can be placed in (and will be read by jwl in the priority order of)
24-
- "current folder" (as in "where your shell's <code>%CD%</code> or <code>${PWD}</code> is at the moment")
25-
- local application data (<code>%USERPROFILE%\AppData\Local</code>)
26-
- roaming application data (<code>%USERPROFILE%\AppData\Roaming</code>)
27-
- jwl's "installation" folder
24+
- "current folder" (as in "where your shell's <code>%CD%</code> or <code>${PWD}</code> is at the moment")
25+
- local application data (<code>%USERPROFILE%\AppData\Local</code>)
26+
- roaming application data (<code>%USERPROFILE%\AppData\Roaming</code>)
27+
- jwl's "installation" folder
2828

2929
As for the CLI worklogger binary, there are command-line options available as well. Any partial options supplied via CLI will override their respective jwl.config counterparts with the highest priority.
3030

3131
### "ServerClass" setting
3232

3333
Available values are:
34-
- Vanilla
35-
- TempoTimeSheets
36-
- ICTime (not implemented yet)
34+
- Vanilla
35+
- TempoTimeSheets
36+
- ICTime (not implemented yet)
3737

3838
## The input CSV structure
3939

4040
Five columns, data delimited (by default) by a colon:
4141
- <code>Date</code> (string) - worklog day date (valid formats: <code>YYYY-MM-DD</code>, <code>YYYY/MM/DD</code>, <code>DD.MM.YYYY</code>, all with optional <code> HH:MI:SS</code> part)
4242
- <code>IssueKey</code> (string) - Jira issue key (<code>SOMEPROJECT-1234</code> and the likes)
43-
- <code>TempoWorklogType</code> (string) - Tempo Timesheets worklog type; values are checked against the available values from Jira server on each execution.
43+
- <code>Activity</code> (string) - Tempo Timesheets worklog type or ICTime activity; values are remapped
4444
- <code>TimeSpent</code> (string) - time to be logged for the Jira issue and the date (valid formats: <code>HH:MI</code>, <code>MI</code>, <code>HH h MI</code>, <code>HH h MI m</code>)
4545
- <code>Comment</code> (string) - optional worklog comment
46+
47+
The <code>Activity</code> values are remapped via config <code>$.JiraServer.ActivityMap</code>. The mapping configuration depends on your Jira server+plugins configuration and is a subject of manual setup by yourself.

‎jwl.core/JwlCoreProcess.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,7 @@ private async Task FillJiraWithWorklogs(InputWorkLog[] inputWorklogs, WorkLog[]
164164
MultiTaskStats progress = new MultiTaskStats(fillJiraWithWorklogsTasks.Length);
165165
MultiTask multiTask = new MultiTask()
166166
{
167-
TaskFeedback = t => Feedback?.FillJiraWithWorklogsProcess(progress.ApplyTaskStatus(t.Status))
167+
OnTaskAwaited = t => Feedback?.FillJiraWithWorklogsProcess(progress.ApplyTaskStatus(t.Status))
168168
};
169169

170170
await multiTask.WhenAll(fillJiraWithWorklogsTasks);
@@ -181,7 +181,7 @@ private async Task<InputWorkLog[]> ReadInputFiles(IEnumerable<string> fileNames)
181181
MultiTaskStats progressStats = new MultiTaskStats(readerTasks.Length);
182182
MultiTask multiTask = new MultiTask()
183183
{
184-
TaskFeedback = t => Feedback?.ReadCsvInputProcess(progressStats.ApplyTaskStatus(t.Status))
184+
OnTaskAwaited = t => Feedback?.ReadCsvInputProcess(progressStats.ApplyTaskStatus(t.Status))
185185
};
186186

187187
if (readerTasks.Any())

‎jwl.infra/MultiTask.cs

Lines changed: 30 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -6,17 +6,17 @@ public enum ProgressState
66
{
77
Unknown,
88
Starting,
9-
BeforeTaskWait,
10-
AfterTaskWait,
9+
BeforeTaskAwait,
10+
AfterTaskAwait,
1111
Finished,
1212
Error,
1313
Cancelled
1414
}
1515

1616
public ProgressState State { get; private set; } = ProgressState.Unknown;
1717

18-
public Action<MultiTask>? ProcessFeedback { get; init; }
19-
public Action<Task>? TaskFeedback { get; init; }
18+
public Action<MultiTask>? OnStateChange { get; init; }
19+
public Action<Task>? OnTaskAwaited { get; init; }
2020

2121
public MultiTask()
2222
{
@@ -25,35 +25,34 @@ public MultiTask()
2525
public async Task WhenAll(IEnumerable<Task> tasks, CancellationToken? cancellationToken = null)
2626
{
2727
State = ProgressState.Starting;
28-
ProcessFeedback?.Invoke(this);
28+
OnStateChange?.Invoke(this);
2929

3030
HashSet<Task> tasksToExecute = tasks.ToHashSet();
3131
List<Exception> errors = new List<Exception>();
3232

3333
while (tasksToExecute.Any())
3434
{
35-
State = ProgressState.BeforeTaskWait;
36-
ProcessFeedback?.Invoke(this);
35+
State = ProgressState.BeforeTaskAwait;
36+
OnStateChange?.Invoke(this);
3737

38-
Task? taskFinished = null;
3938
try
4039
{
4140
cancellationToken?.ThrowIfCancellationRequested();
4241

43-
taskFinished = await Task.WhenAny(tasksToExecute);
42+
Task finishedTask = await Task.WhenAny(tasksToExecute);
4443

45-
State = ProgressState.AfterTaskWait;
46-
ProcessFeedback?.Invoke(this);
47-
TaskFeedback?.Invoke(taskFinished);
44+
State = ProgressState.AfterTaskAwait;
45+
OnStateChange?.Invoke(this);
46+
OnTaskAwaited?.Invoke(finishedTask);
4847

49-
if (taskFinished.Status is TaskStatus.Faulted or TaskStatus.Canceled)
48+
if (finishedTask.Status is TaskStatus.Faulted or TaskStatus.Canceled)
5049
{
51-
tasksToExecute.Remove(taskFinished);
52-
throw taskFinished.Exception ?? new Exception($"Task ended in {taskFinished.Status} status without exception details");
50+
tasksToExecute.Remove(finishedTask);
51+
throw finishedTask.Exception ?? new Exception($"Task ended in {finishedTask.Status} status without exception details");
5352
}
54-
else if (taskFinished.Status == TaskStatus.RanToCompletion)
53+
else if (finishedTask.Status == TaskStatus.RanToCompletion)
5554
{
56-
if (!tasksToExecute.Remove(taskFinished))
55+
if (!tasksToExecute.Remove(finishedTask))
5756
throw new InvalidOperationException("Task reported as finished... again!");
5857
}
5958
}
@@ -67,24 +66,27 @@ public async Task WhenAll(IEnumerable<Task> tasks, CancellationToken? cancellati
6766
}
6867
}
6968

70-
if (errors.All(ex => ex is TaskCanceledException))
69+
if (errors.Any())
7170
{
72-
State = ProgressState.Cancelled;
73-
ProcessFeedback?.Invoke(this);
71+
if (errors.All(ex => ex is TaskCanceledException))
72+
{
73+
State = ProgressState.Cancelled;
74+
OnStateChange?.Invoke(this);
7475

75-
throw new TaskCanceledException($"All {errors.Count} tasks have been cancelled", new AggregateException(errors));
76-
}
77-
else if (errors.Any())
78-
{
79-
State = ProgressState.Error;
80-
ProcessFeedback?.Invoke(this);
76+
throw new TaskCanceledException($"All {errors.Count} tasks have been cancelled", new AggregateException(errors));
77+
}
78+
else
79+
{
80+
State = ProgressState.Error;
81+
OnStateChange?.Invoke(this);
8182

82-
throw new AggregateException(errors);
83+
throw new AggregateException(errors);
84+
}
8385
}
8486
else
8587
{
8688
State = ProgressState.Finished;
87-
ProcessFeedback?.Invoke(this);
89+
OnStateChange?.Invoke(this);
8890
}
8991
}
9092
}

0 commit comments

Comments
 (0)