diff --git a/README.md b/README.md index 6f17442..ba4299c 100644 --- a/README.md +++ b/README.md @@ -21,25 +21,27 @@ Meet the scripted Jira worklogging! Give it your worklogs in a CSV file (and you ## Configuration 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) - - "current folder" (as in "where your shell's %CD% or ${PWD} is at the moment") - - local application data (%USERPROFILE%\AppData\Local) - - roaming application data (%USERPROFILE%\AppData\Roaming) - - jwl's "installation" folder +- "current folder" (as in "where your shell's %CD% or ${PWD} is at the moment") +- local application data (%USERPROFILE%\AppData\Local) +- roaming application data (%USERPROFILE%\AppData\Roaming) +- jwl's "installation" folder 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. ### "ServerClass" setting Available values are: - - Vanilla - - TempoTimeSheets - - ICTime (not implemented yet) +- Vanilla +- TempoTimeSheets +- ICTime (not implemented yet) ## The input CSV structure Five columns, data delimited (by default) by a colon: - Date (string) - worklog day date (valid formats: YYYY-MM-DD, YYYY/MM/DD, DD.MM.YYYY, all with optional HH:MI:SS part) - IssueKey (string) - Jira issue key (SOMEPROJECT-1234 and the likes) - - TempoWorklogType (string) - Tempo Timesheets worklog type; values are checked against the available values from Jira server on each execution. + - Activity (string) - Tempo Timesheets worklog type or ICTime activity; values are remapped - TimeSpent (string) - time to be logged for the Jira issue and the date (valid formats: HH:MI, MI, HH h MI, HH h MI m) - Comment (string) - optional worklog comment + +The Activity values are remapped via config $.JiraServer.ActivityMap. The mapping configuration depends on your Jira server+plugins configuration and is a subject of manual setup by yourself. diff --git a/jwl.core/JwlCoreProcess.cs b/jwl.core/JwlCoreProcess.cs index cc9cdb1..b380815 100644 --- a/jwl.core/JwlCoreProcess.cs +++ b/jwl.core/JwlCoreProcess.cs @@ -164,7 +164,7 @@ private async Task FillJiraWithWorklogs(InputWorkLog[] inputWorklogs, WorkLog[] MultiTaskStats progress = new MultiTaskStats(fillJiraWithWorklogsTasks.Length); MultiTask multiTask = new MultiTask() { - TaskFeedback = t => Feedback?.FillJiraWithWorklogsProcess(progress.ApplyTaskStatus(t.Status)) + OnTaskAwaited = t => Feedback?.FillJiraWithWorklogsProcess(progress.ApplyTaskStatus(t.Status)) }; await multiTask.WhenAll(fillJiraWithWorklogsTasks); @@ -181,7 +181,7 @@ private async Task ReadInputFiles(IEnumerable fileNames) MultiTaskStats progressStats = new MultiTaskStats(readerTasks.Length); MultiTask multiTask = new MultiTask() { - TaskFeedback = t => Feedback?.ReadCsvInputProcess(progressStats.ApplyTaskStatus(t.Status)) + OnTaskAwaited = t => Feedback?.ReadCsvInputProcess(progressStats.ApplyTaskStatus(t.Status)) }; if (readerTasks.Any()) diff --git a/jwl.infra/MultiTask.cs b/jwl.infra/MultiTask.cs index 2d7bb70..b180c39 100644 --- a/jwl.infra/MultiTask.cs +++ b/jwl.infra/MultiTask.cs @@ -6,8 +6,8 @@ public enum ProgressState { Unknown, Starting, - BeforeTaskWait, - AfterTaskWait, + BeforeTaskAwait, + AfterTaskAwait, Finished, Error, Cancelled @@ -15,8 +15,8 @@ public enum ProgressState public ProgressState State { get; private set; } = ProgressState.Unknown; - public Action? ProcessFeedback { get; init; } - public Action? TaskFeedback { get; init; } + public Action? OnStateChange { get; init; } + public Action? OnTaskAwaited { get; init; } public MultiTask() { @@ -25,35 +25,34 @@ public MultiTask() public async Task WhenAll(IEnumerable tasks, CancellationToken? cancellationToken = null) { State = ProgressState.Starting; - ProcessFeedback?.Invoke(this); + OnStateChange?.Invoke(this); HashSet tasksToExecute = tasks.ToHashSet(); List errors = new List(); while (tasksToExecute.Any()) { - State = ProgressState.BeforeTaskWait; - ProcessFeedback?.Invoke(this); + State = ProgressState.BeforeTaskAwait; + OnStateChange?.Invoke(this); - Task? taskFinished = null; try { cancellationToken?.ThrowIfCancellationRequested(); - taskFinished = await Task.WhenAny(tasksToExecute); + Task finishedTask = await Task.WhenAny(tasksToExecute); - State = ProgressState.AfterTaskWait; - ProcessFeedback?.Invoke(this); - TaskFeedback?.Invoke(taskFinished); + State = ProgressState.AfterTaskAwait; + OnStateChange?.Invoke(this); + OnTaskAwaited?.Invoke(finishedTask); - if (taskFinished.Status is TaskStatus.Faulted or TaskStatus.Canceled) + if (finishedTask.Status is TaskStatus.Faulted or TaskStatus.Canceled) { - tasksToExecute.Remove(taskFinished); - throw taskFinished.Exception ?? new Exception($"Task ended in {taskFinished.Status} status without exception details"); + tasksToExecute.Remove(finishedTask); + throw finishedTask.Exception ?? new Exception($"Task ended in {finishedTask.Status} status without exception details"); } - else if (taskFinished.Status == TaskStatus.RanToCompletion) + else if (finishedTask.Status == TaskStatus.RanToCompletion) { - if (!tasksToExecute.Remove(taskFinished)) + if (!tasksToExecute.Remove(finishedTask)) throw new InvalidOperationException("Task reported as finished... again!"); } } @@ -67,24 +66,27 @@ public async Task WhenAll(IEnumerable tasks, CancellationToken? cancellati } } - if (errors.All(ex => ex is TaskCanceledException)) + if (errors.Any()) { - State = ProgressState.Cancelled; - ProcessFeedback?.Invoke(this); + if (errors.All(ex => ex is TaskCanceledException)) + { + State = ProgressState.Cancelled; + OnStateChange?.Invoke(this); - throw new TaskCanceledException($"All {errors.Count} tasks have been cancelled", new AggregateException(errors)); - } - else if (errors.Any()) - { - State = ProgressState.Error; - ProcessFeedback?.Invoke(this); + throw new TaskCanceledException($"All {errors.Count} tasks have been cancelled", new AggregateException(errors)); + } + else + { + State = ProgressState.Error; + OnStateChange?.Invoke(this); - throw new AggregateException(errors); + throw new AggregateException(errors); + } } else { State = ProgressState.Finished; - ProcessFeedback?.Invoke(this); + OnStateChange?.Invoke(this); } } }