Разделено получение коммитов и распределение времени
This commit is contained in:
@@ -83,6 +83,8 @@
|
|||||||
<DependentUpon>frmMain.cs</DependentUpon>
|
<DependentUpon>frmMain.cs</DependentUpon>
|
||||||
</Compile>
|
</Compile>
|
||||||
<Compile Include="JiraIntegration\JiraApi.cs" />
|
<Compile Include="JiraIntegration\JiraApi.cs" />
|
||||||
|
<Compile Include="Mercurial\MercurialCommitItem.cs" />
|
||||||
|
<Compile Include="Mercurial\MercurialLog.cs" />
|
||||||
<Compile Include="Passwords\EncryptionClass.cs" />
|
<Compile Include="Passwords\EncryptionClass.cs" />
|
||||||
<Compile Include="Program.cs" />
|
<Compile Include="Program.cs" />
|
||||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ using System.Threading;
|
|||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using JiraTimeBotForm.CommitWorks;
|
using JiraTimeBotForm.CommitWorks;
|
||||||
using JiraTimeBotForm.Configuration;
|
using JiraTimeBotForm.Configuration;
|
||||||
|
using JiraTimeBotForm.Mercurial;
|
||||||
using JiraTimeBotForm.TaskProcessors;
|
using JiraTimeBotForm.TaskProcessors;
|
||||||
using JiraTimeBotForm.TasksProcessors;
|
using JiraTimeBotForm.TasksProcessors;
|
||||||
using JiraTimeBotForm.TaskTime;
|
using JiraTimeBotForm.TaskTime;
|
||||||
@@ -13,12 +14,14 @@ namespace JiraTimeBotForm
|
|||||||
{
|
{
|
||||||
class Job
|
class Job
|
||||||
{
|
{
|
||||||
private readonly BuzzwordReplacer _buzzwordReplacer;
|
private readonly MercurialLog _mercurialLog;
|
||||||
|
private readonly TaskTimeDiscoverer _taskTimeDiscoverer;
|
||||||
private readonly ILog _log;
|
private readonly ILog _log;
|
||||||
|
|
||||||
public Job(BuzzwordReplacer buzzwordReplacer, ILog log)
|
public Job(MercurialLog mercurialLog, TaskTimeDiscoverer taskTimeDiscoverer, ILog log)
|
||||||
{
|
{
|
||||||
_buzzwordReplacer = buzzwordReplacer;
|
_mercurialLog = mercurialLog;
|
||||||
|
_taskTimeDiscoverer = taskTimeDiscoverer;
|
||||||
_log = log;
|
_log = log;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -31,8 +34,6 @@ namespace JiraTimeBotForm
|
|||||||
|
|
||||||
private void DoTheJobImpl(Settings settings, ITasksProcessor tasksProcessor, CancellationToken cancellationToken)
|
private void DoTheJobImpl(Settings settings, ITasksProcessor tasksProcessor, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
var taskDiscoverer = new TaskTimeDiscoverer(_buzzwordReplacer, _log);
|
|
||||||
|
|
||||||
int daysDiff = 0;
|
int daysDiff = 0;
|
||||||
if (tasksProcessor is MeetingProcessor)
|
if (tasksProcessor is MeetingProcessor)
|
||||||
{
|
{
|
||||||
@@ -43,7 +44,8 @@ namespace JiraTimeBotForm
|
|||||||
{
|
{
|
||||||
DateTime date = DateTime.Now.Date.AddDays(daysDiff);
|
DateTime date = DateTime.Now.Date.AddDays(daysDiff);
|
||||||
|
|
||||||
List<TaskTimeItem> taskTimes = taskDiscoverer.GetTaskTimes(settings, date, cancellationToken);
|
List<MercurialCommitItem> commits = _mercurialLog.GetMercurialLog(settings, date, cancellationToken);
|
||||||
|
List<TaskTimeItem> taskTimes = _taskTimeDiscoverer.GetTaskTimes(settings, commits, cancellationToken);
|
||||||
|
|
||||||
if (cancellationToken.IsCancellationRequested)
|
if (cancellationToken.IsCancellationRequested)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -0,0 +1,17 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace JiraTimeBotForm.Mercurial
|
||||||
|
{
|
||||||
|
public class MercurialCommitItem
|
||||||
|
{
|
||||||
|
public string Description { get; set; }
|
||||||
|
public string Branch { get; set; }
|
||||||
|
|
||||||
|
public DateTime StartTime { get; set; }
|
||||||
|
public DateTime EndTime { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,145 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using JiraTimeBotForm.Configuration;
|
||||||
|
using JiraTimeBotForm.TaskTime;
|
||||||
|
using Mercurial;
|
||||||
|
|
||||||
|
namespace JiraTimeBotForm.Mercurial
|
||||||
|
{
|
||||||
|
public class MercurialLog
|
||||||
|
{
|
||||||
|
private readonly ILog _log;
|
||||||
|
|
||||||
|
public MercurialLog(ILog log)
|
||||||
|
{
|
||||||
|
_log = log;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<MercurialCommitItem> GetMercurialLog(Settings settings, DateTime? date = null, CancellationToken cancellationToken = default(CancellationToken))
|
||||||
|
{
|
||||||
|
date = date.GetValueOrDefault(DateTime.Now.Date);
|
||||||
|
|
||||||
|
var workTasks = new List<MercurialCommitItem>();
|
||||||
|
foreach (var repoDirectory in Directory.GetDirectories(settings.RepositoryPath))
|
||||||
|
{
|
||||||
|
if (cancellationToken.IsCancellationRequested)
|
||||||
|
{
|
||||||
|
return new List<MercurialCommitItem>();
|
||||||
|
}
|
||||||
|
|
||||||
|
//var project = new DirectoryInfo(repoDirectory).Name;
|
||||||
|
if (!Directory.Exists(Path.Combine(repoDirectory, ".hg")))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
var repo = new Repository(repoDirectory);
|
||||||
|
var logCommand = new LogCommand
|
||||||
|
{
|
||||||
|
Date = date,
|
||||||
|
Users = { settings.MercurialAuthorEmail },
|
||||||
|
AdditionalArguments = { "--encoding=utf-8"},
|
||||||
|
};
|
||||||
|
|
||||||
|
var log = repo.Log(logCommand);
|
||||||
|
|
||||||
|
foreach (var changeset in log)
|
||||||
|
{
|
||||||
|
if (cancellationToken.IsCancellationRequested)
|
||||||
|
{
|
||||||
|
return new List<MercurialCommitItem>();
|
||||||
|
}
|
||||||
|
|
||||||
|
var commitMessage = FixEncoding(changeset.CommitMessage);
|
||||||
|
if (IsNeedToSkip(changeset.Branch, commitMessage))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
commitMessage = StripTechnicalInfo(commitMessage);
|
||||||
|
//commitMessage = _buzzwordReplacer.FixBuzzwords(commitMessage);
|
||||||
|
|
||||||
|
workTasks.Add(new MercurialCommitItem
|
||||||
|
{
|
||||||
|
Description = commitMessage,
|
||||||
|
Branch = changeset.Branch,
|
||||||
|
StartTime = changeset.Timestamp,
|
||||||
|
EndTime = changeset.Timestamp
|
||||||
|
});
|
||||||
|
_log?.Trace($" - Найден changeset: {changeset.Timestamp} - {changeset.Branch} - {changeset.AuthorEmailAddress} - {commitMessage}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!workTasks.Any())
|
||||||
|
{
|
||||||
|
return new List<MercurialCommitItem>();
|
||||||
|
}
|
||||||
|
|
||||||
|
return workTasks;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private string StripTechnicalInfo(string commitMessage)
|
||||||
|
{
|
||||||
|
if (!commitMessage.Contains("Signed-by:"))
|
||||||
|
{
|
||||||
|
return commitMessage;
|
||||||
|
}
|
||||||
|
|
||||||
|
var arr = commitMessage.Split('\n');
|
||||||
|
var sb = new StringBuilder();
|
||||||
|
foreach (var itm in arr)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(itm))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (itm.StartsWith("Signed-by"))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (itm.StartsWith("Jira:"))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
sb.AppendLine(itm);
|
||||||
|
}
|
||||||
|
|
||||||
|
var message = sb.ToString();
|
||||||
|
message = message.TrimEnd('\n');
|
||||||
|
message = message.TrimEnd('\r');
|
||||||
|
|
||||||
|
return message;
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool IsNeedToSkip(string branch, string commitMessage)
|
||||||
|
{
|
||||||
|
if (!branch.Contains("-"))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Пропускаем Close и Merge коммиты
|
||||||
|
if (commitMessage.StartsWith($"Close {branch} ", StringComparison.InvariantCultureIgnoreCase) ||
|
||||||
|
commitMessage.StartsWith($"Merge with ", StringComparison.InvariantCultureIgnoreCase))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private string FixEncoding(string source)
|
||||||
|
{
|
||||||
|
//перекодируем сообщение - ибо оно криво забирается в 1252
|
||||||
|
Encoding srcEncodingFormat = Encoding.GetEncoding("windows-1252");
|
||||||
|
byte[] originalByteString = srcEncodingFormat.GetBytes(source);
|
||||||
|
var commitMessage = Encoding.UTF8.GetString(originalByteString);
|
||||||
|
return commitMessage;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,11 +2,12 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using JiraTimeBotForm.Configuration;
|
using JiraTimeBotForm.Configuration;
|
||||||
|
using JiraTimeBotForm.Mercurial;
|
||||||
|
|
||||||
namespace JiraTimeBotForm.TaskTime
|
namespace JiraTimeBotForm.TaskTime
|
||||||
{
|
{
|
||||||
public interface ITaskTimeDiscoverer
|
public interface ITaskTimeDiscoverer
|
||||||
{
|
{
|
||||||
List<TaskTimeItem> GetTaskTimes(Settings settings, DateTime? date = null, CancellationToken cancellationToken = default(CancellationToken));
|
List<TaskTimeItem> GetTaskTimes(Settings settings, List<MercurialCommitItem> commitItems, CancellationToken cancellationToken = default(CancellationToken));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -3,92 +3,37 @@ using System.Collections.Generic;
|
|||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Text.RegularExpressions;
|
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using JiraTimeBotForm.CommitWorks;
|
|
||||||
using JiraTimeBotForm.Configuration;
|
using JiraTimeBotForm.Configuration;
|
||||||
|
using JiraTimeBotForm.Mercurial;
|
||||||
using Mercurial;
|
using Mercurial;
|
||||||
|
|
||||||
namespace JiraTimeBotForm.TaskTime
|
namespace JiraTimeBotForm.TaskTime
|
||||||
{
|
{
|
||||||
public class TaskTimeDiscoverer: ITaskTimeDiscoverer
|
public class TaskTimeDiscoverer: ITaskTimeDiscoverer
|
||||||
{
|
{
|
||||||
private readonly BuzzwordReplacer _buzzwordReplacer;
|
|
||||||
private readonly ILog _log;
|
private readonly ILog _log;
|
||||||
|
|
||||||
public TaskTimeDiscoverer(BuzzwordReplacer buzzwordReplacer, ILog log = null)
|
public TaskTimeDiscoverer(ILog log)
|
||||||
{
|
{
|
||||||
_buzzwordReplacer = buzzwordReplacer;
|
|
||||||
_log = log;
|
_log = log;
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<TaskTimeItem> GetTaskTimes(Settings settings, DateTime? date = null, CancellationToken cancellationToken = default(CancellationToken))
|
public List<TaskTimeItem> GetTaskTimes(Settings settings, List<MercurialCommitItem> commitItems, CancellationToken cancellationToken = default(CancellationToken))
|
||||||
{
|
{
|
||||||
var workTimeItems = new List<TaskTimeItem>();
|
int remainMinutes = settings.MinuterPerWorkDay;
|
||||||
|
int totalCommitsCount = commitItems.Count;
|
||||||
|
|
||||||
date = date.GetValueOrDefault(DateTime.Now.Date);
|
List<TaskTimeItem> workTimeItems = new List<TaskTimeItem>();
|
||||||
|
|
||||||
var workTasks = new List<TaskTimeItem>();
|
//Нам нужно раскидать 480 минут в день.
|
||||||
foreach (var repoDirectory in Directory.GetDirectories(settings.RepositoryPath))
|
foreach (var taskGroup in commitItems.GroupBy(f => f.Branch).OrderByDescending(f=>f.Count()))
|
||||||
{
|
{
|
||||||
if (cancellationToken.IsCancellationRequested)
|
if (cancellationToken.IsCancellationRequested)
|
||||||
{
|
{
|
||||||
return workTimeItems;
|
return new List<TaskTimeItem>();
|
||||||
}
|
}
|
||||||
|
|
||||||
//var project = new DirectoryInfo(repoDirectory).Name;
|
|
||||||
if (!Directory.Exists(Path.Combine(repoDirectory, ".hg")))
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
var repo = new Repository(repoDirectory);
|
|
||||||
var logCommand = new LogCommand
|
|
||||||
{
|
|
||||||
Date = date,
|
|
||||||
Users = { settings.MercurialAuthorEmail },
|
|
||||||
AdditionalArguments = { "--encoding=utf-8"},
|
|
||||||
};
|
|
||||||
|
|
||||||
var log = repo.Log(logCommand);
|
|
||||||
|
|
||||||
foreach (var changeset in log)
|
|
||||||
{
|
|
||||||
if (cancellationToken.IsCancellationRequested)
|
|
||||||
{
|
|
||||||
return workTimeItems;
|
|
||||||
}
|
|
||||||
|
|
||||||
var commitMessage = FixEncoding(changeset.CommitMessage);
|
|
||||||
if (IsNeedToSkip(changeset.Branch, commitMessage))
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
commitMessage = StripTechnicalInfo(commitMessage);
|
|
||||||
commitMessage = _buzzwordReplacer.FixBuzzwords(commitMessage);
|
|
||||||
|
|
||||||
workTasks.Add(new TaskTimeItem
|
|
||||||
{
|
|
||||||
Description = commitMessage,
|
|
||||||
Branch = changeset.Branch,
|
|
||||||
Commits = 1,
|
|
||||||
StartTime = changeset.Timestamp,
|
|
||||||
EndTime = changeset.Timestamp
|
|
||||||
});
|
|
||||||
_log?.Trace($" - Найден changeset: {changeset.Timestamp} - {changeset.Branch} - {changeset.AuthorEmailAddress} - {commitMessage}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!workTasks.Any())
|
|
||||||
{
|
|
||||||
return new List<TaskTimeItem>();
|
|
||||||
}
|
|
||||||
|
|
||||||
int remainMinutes = settings.MinuterPerWorkDay;
|
|
||||||
int totalCommitsCount = workTasks.Count;
|
|
||||||
|
|
||||||
//Нам нужно раскидать 480 минут в день.
|
|
||||||
foreach (var taskGroup in workTasks.GroupBy(f => f.Branch).OrderByDescending(f=>f.Count()))
|
|
||||||
{
|
|
||||||
int currentTaskCommits = taskGroup.Count();
|
int currentTaskCommits = taskGroup.Count();
|
||||||
int currentTaskTime = (int)RoundTo(settings.MinuterPerWorkDay / totalCommitsCount * currentTaskCommits);
|
int currentTaskTime = (int)RoundTo(settings.MinuterPerWorkDay / totalCommitsCount * currentTaskCommits);
|
||||||
remainMinutes = remainMinutes - currentTaskTime;
|
remainMinutes = remainMinutes - currentTaskTime;
|
||||||
@@ -113,6 +58,11 @@ namespace JiraTimeBotForm.TaskTime
|
|||||||
|
|
||||||
workTimeItems.Add(taskTimeItem);
|
workTimeItems.Add(taskTimeItem);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (remainMinutes != 0)
|
||||||
|
{
|
||||||
|
_log.Trace($"Погрешность распределения времени: {remainMinutes}. Добавляю к первой задаче.");
|
||||||
|
}
|
||||||
//если переборщили или не достаточно добавили до 8 часов - скореектируем остаток в первой задаче (она самая трудозатратная).
|
//если переборщили или не достаточно добавили до 8 часов - скореектируем остаток в первой задаче (она самая трудозатратная).
|
||||||
workTimeItems.First().Time += TimeSpan.FromMinutes(remainMinutes);
|
workTimeItems.First().Time += TimeSpan.FromMinutes(remainMinutes);
|
||||||
|
|
||||||
@@ -120,65 +70,6 @@ namespace JiraTimeBotForm.TaskTime
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private string StripTechnicalInfo(string commitMessage)
|
|
||||||
{
|
|
||||||
if (!commitMessage.Contains("Signed-by:"))
|
|
||||||
{
|
|
||||||
return commitMessage;
|
|
||||||
}
|
|
||||||
|
|
||||||
var arr = commitMessage.Split('\n');
|
|
||||||
var sb = new StringBuilder();
|
|
||||||
foreach (var itm in arr)
|
|
||||||
{
|
|
||||||
if (string.IsNullOrEmpty(itm))
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (itm.StartsWith("Signed-by"))
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (itm.StartsWith("Jira:"))
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
sb.AppendLine(itm);
|
|
||||||
}
|
|
||||||
|
|
||||||
var message = sb.ToString();
|
|
||||||
message = message.TrimEnd('\n');
|
|
||||||
message = message.TrimEnd('\r');
|
|
||||||
|
|
||||||
return message;
|
|
||||||
}
|
|
||||||
|
|
||||||
private bool IsNeedToSkip(string branch, string commitMessage)
|
|
||||||
{
|
|
||||||
if (!branch.Contains("-"))
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
//Пропускаем Close и Merge коммиты
|
|
||||||
if (commitMessage.StartsWith($"Close {branch} ", StringComparison.InvariantCultureIgnoreCase) ||
|
|
||||||
commitMessage.StartsWith($"Merge with ", StringComparison.InvariantCultureIgnoreCase))
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
private string FixEncoding(string source)
|
|
||||||
{
|
|
||||||
//перекодируем сообщение - ибо оно криво забирается в 1252
|
|
||||||
Encoding srcEncodingFormat = Encoding.GetEncoding("windows-1252");
|
|
||||||
byte[] originalByteString = srcEncodingFormat.GetBytes(source);
|
|
||||||
var commitMessage = Encoding.UTF8.GetString(originalByteString);
|
|
||||||
return commitMessage;
|
|
||||||
}
|
|
||||||
|
|
||||||
private decimal RoundTo(decimal value, decimal to = 15, bool up = true)
|
private decimal RoundTo(decimal value, decimal to = 15, bool up = true)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -6,8 +6,10 @@ using System.Threading.Tasks;
|
|||||||
using System.Windows.Forms;
|
using System.Windows.Forms;
|
||||||
using JiraTimeBotForm.CommitWorks;
|
using JiraTimeBotForm.CommitWorks;
|
||||||
using JiraTimeBotForm.Configuration;
|
using JiraTimeBotForm.Configuration;
|
||||||
|
using JiraTimeBotForm.Mercurial;
|
||||||
using JiraTimeBotForm.Passwords;
|
using JiraTimeBotForm.Passwords;
|
||||||
using JiraTimeBotForm.TasksProcessors;
|
using JiraTimeBotForm.TasksProcessors;
|
||||||
|
using JiraTimeBotForm.TaskTime;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
// This is the code for your desktop app.
|
// This is the code for your desktop app.
|
||||||
@@ -59,7 +61,9 @@ namespace JiraTimeBotForm
|
|||||||
trayIcon.Click += btnTray_Click;
|
trayIcon.Click += btnTray_Click;
|
||||||
trayIcon.DoubleClick += btnTray_Click;
|
trayIcon.DoubleClick += btnTray_Click;
|
||||||
|
|
||||||
_job = new Job(_buzzwordReplacer, _log);
|
var mercurialLog = new MercurialLog(_log);
|
||||||
|
var taskTimeDiscoverer = new TaskTimeDiscoverer(_log);
|
||||||
|
_job = new Job(mercurialLog, taskTimeDiscoverer, _log);
|
||||||
|
|
||||||
_controls = new Control[] { txtJiraLogin, txtJiraPassword, txtMercurialEmail, actTime, txtRepoPath, txtDummyMode, btnSave, btnStart, btnMeeting, chkAddComments };
|
_controls = new Control[] { txtJiraLogin, txtJiraPassword, txtMercurialEmail, actTime, txtRepoPath, txtDummyMode, btnSave, btnStart, btnMeeting, chkAddComments };
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user