diff --git a/JiraTimeBotForm/JiraIntegration/JiraApi.cs b/JiraTimeBotForm/JiraIntegration/JiraApi.cs index 38bc572..77cceae 100644 --- a/JiraTimeBotForm/JiraIntegration/JiraApi.cs +++ b/JiraTimeBotForm/JiraIntegration/JiraApi.cs @@ -22,10 +22,9 @@ namespace JiraTimeBotForm.JiraIntegration public string GetTaskName(string branch) { - Issue issue = null; try { - issue = _jira.Issues.Queryable.FirstOrDefault(f => f.Key == branch); + var issue = _jira.Issues.Queryable.FirstOrDefault(f => f.Key == branch); return issue?.Summary; } catch (Exception) diff --git a/JiraTimeBotForm/TaskTime/ITaskTimeDiscoverer.cs b/JiraTimeBotForm/TaskTime/ITaskTimeDiscoverer.cs index dec1dc7..c520e40 100644 --- a/JiraTimeBotForm/TaskTime/ITaskTimeDiscoverer.cs +++ b/JiraTimeBotForm/TaskTime/ITaskTimeDiscoverer.cs @@ -1,11 +1,12 @@ using System; using System.Collections.Generic; +using System.Threading; using JiraTimeBotForm.Configuration; namespace JiraTimeBotForm.TaskTime { public interface ITaskTimeDiscoverer { - List GetTaskTimes(Settings settings, DateTime? date = null); + List GetTaskTimes(Settings settings, DateTime? date = null, CancellationToken cancellationToken = default(CancellationToken)); } } \ No newline at end of file diff --git a/JiraTimeBotForm/TaskTime/TaskTimeDiscoverer.cs b/JiraTimeBotForm/TaskTime/TaskTimeDiscoverer.cs index 49d4e07..be91472 100644 --- a/JiraTimeBotForm/TaskTime/TaskTimeDiscoverer.cs +++ b/JiraTimeBotForm/TaskTime/TaskTimeDiscoverer.cs @@ -2,7 +2,7 @@ using System.Collections.Generic; using System.IO; using System.Linq; -using System.Windows.Forms; +using System.Threading; using JiraTimeBotForm.Configuration; using Mercurial; @@ -17,28 +17,37 @@ namespace JiraTimeBotForm.TaskTime _log = log; } - public List GetTaskTimes(Settings settings, DateTime? date = null) + public List GetTaskTimes(Settings settings, DateTime? date = null, CancellationToken cancellationToken = default(CancellationToken)) { - if (date == null) - { - date = DateTime.Now.Date; - } - date = date.Value.Date; + var workTimeItems = new List(); + + date = date.GetValueOrDefault(DateTime.Now.Date); + + var workTasks = new List(); - List workTasks = new List(); foreach (var repoDirectory in Directory.GetDirectories(settings.RepositoryPath)) { + cancellationToken.ThrowIfCancellationRequested(); + //var project = new DirectoryInfo(repoDirectory).Name; if (!Directory.Exists(Path.Combine(repoDirectory, ".hg"))) { continue; } - Application.DoEvents(); var repo = new Repository(repoDirectory); - var log = repo.Log(new LogCommand {Date = date, Users = { settings.MercurialAuthorEmail } }); + var logCommand = new LogCommand + { + Date = date, + Users = { settings.MercurialAuthorEmail } + }; + + var log = repo.Log(logCommand); + foreach (var changeset in log) { + cancellationToken.ThrowIfCancellationRequested(); + if (!changeset.Branch.Contains("-")) { continue; @@ -51,23 +60,23 @@ namespace JiraTimeBotForm.TaskTime workTasks.Add(changeset.Branch); _log?.Trace($" - Найден changeset: {changeset.Timestamp} - {changeset.Branch} - {changeset.AuthorEmailAddress}"); - Application.DoEvents(); } } //Нам нужно раскидать 480 минут в день. - var workTimeItems = new List(); - foreach (var taskGroup in workTasks.GroupBy(f=>f)) + foreach (var taskGroup in workTasks.GroupBy(f => f)) { var minutesPerTime = settings.MinuterPerWorkDay / workTasks.Count; var minutesForCurrentTaskGroup = minutesPerTime * taskGroup.Count(); - workTimeItems.Add(new TaskTimeItem + var taskTimeItem = new TaskTimeItem { Branch = taskGroup.Key, Time = TimeSpan.FromMinutes(minutesForCurrentTaskGroup), Commits = taskGroup.Count(), - }); + }; + + workTimeItems.Add(taskTimeItem); } return workTimeItems; diff --git a/JiraTimeBotForm/frmMain.Designer.cs b/JiraTimeBotForm/frmMain.Designer.cs index 1dc3466..96b1143 100644 --- a/JiraTimeBotForm/frmMain.Designer.cs +++ b/JiraTimeBotForm/frmMain.Designer.cs @@ -47,6 +47,7 @@ this.tmrStart = new System.Windows.Forms.Timer(this.components); this.txtDummyMode = new System.Windows.Forms.CheckBox(); this.btnMeeting = new System.Windows.Forms.Button(); + this.btnCancel = new System.Windows.Forms.Button(); this.SuspendLayout(); // // actTime @@ -147,13 +148,14 @@ this.txtLog.Location = new System.Drawing.Point(218, 16); this.txtLog.Multiline = true; this.txtLog.Name = "txtLog"; + this.txtLog.ReadOnly = true; this.txtLog.ScrollBars = System.Windows.Forms.ScrollBars.Vertical; this.txtLog.Size = new System.Drawing.Size(510, 264); this.txtLog.TabIndex = 11; // // btnStart // - this.btnStart.Location = new System.Drawing.Point(34, 257); + this.btnStart.Location = new System.Drawing.Point(34, 224); this.btnStart.Name = "btnStart"; this.btnStart.Size = new System.Drawing.Size(103, 23); this.btnStart.TabIndex = 12; @@ -175,7 +177,7 @@ // txtDummyMode // this.txtDummyMode.AutoSize = true; - this.txtDummyMode.Location = new System.Drawing.Point(31, 234); + this.txtDummyMode.Location = new System.Drawing.Point(31, 201); this.txtDummyMode.Name = "txtDummyMode"; this.txtDummyMode.Size = new System.Drawing.Size(114, 17); this.txtDummyMode.TabIndex = 13; @@ -184,7 +186,7 @@ // // btnMeeting // - this.btnMeeting.Location = new System.Drawing.Point(160, 257); + this.btnMeeting.Location = new System.Drawing.Point(160, 224); this.btnMeeting.Name = "btnMeeting"; this.btnMeeting.Size = new System.Drawing.Size(52, 23); this.btnMeeting.TabIndex = 14; @@ -192,11 +194,23 @@ this.btnMeeting.UseVisualStyleBackColor = true; this.btnMeeting.Click += new System.EventHandler(this.btnMeeting_Click); // + // btnCancel + // + this.btnCancel.Enabled = false; + this.btnCancel.Location = new System.Drawing.Point(34, 256); + this.btnCancel.Name = "btnCancel"; + this.btnCancel.Size = new System.Drawing.Size(178, 23); + this.btnCancel.TabIndex = 15; + this.btnCancel.Text = "Cancel operation"; + this.btnCancel.UseVisualStyleBackColor = true; + this.btnCancel.Click += new System.EventHandler(this.btnCancel_Click); + // // frmMain // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; this.ClientSize = new System.Drawing.Size(740, 292); + this.Controls.Add(this.btnCancel); this.Controls.Add(this.btnMeeting); this.Controls.Add(this.txtDummyMode); this.Controls.Add(this.btnStart); @@ -243,6 +257,7 @@ private System.Windows.Forms.Timer tmrStart; private System.Windows.Forms.CheckBox txtDummyMode; private System.Windows.Forms.Button btnMeeting; + private System.Windows.Forms.Button btnCancel; } } diff --git a/JiraTimeBotForm/frmMain.cs b/JiraTimeBotForm/frmMain.cs index 3a1d1bc..1d80a69 100644 --- a/JiraTimeBotForm/frmMain.cs +++ b/JiraTimeBotForm/frmMain.cs @@ -1,10 +1,15 @@ -using System; +using System; +using System.Collections.Generic; using System.IO; using System.Linq; +using System.Runtime.Remoting.Messaging; +using System.Threading; +using System.Threading.Tasks; using System.Windows.Forms; using JiraTimeBotForm.Configuration; using JiraTimeBotForm.JiraIntegration; using JiraTimeBotForm.Passwords; +using JiraTimeBotForm.TasksProcessors; using JiraTimeBotForm.TaskTime; using Newtonsoft.Json; @@ -19,7 +24,22 @@ namespace JiraTimeBotForm private readonly ILog _log; private readonly NotifyIcon trayIcon; private readonly ContextMenu trayMenu; - + private Job _job; + private readonly IReadOnlyList _controls; + private CancellationTokenSource _tokenSource; + + private CancellationTokenSource GetTokenSource() + { + var tokenSource = new CancellationTokenSource(); + tokenSource.Token.Register(() => + { + _log.Info("Îïåðàöèÿ îòìåíåíà..."); + LockUnlock(true); + }); + + return tokenSource; + } + public frmMain() { InitializeComponent(); @@ -37,6 +57,10 @@ namespace JiraTimeBotForm trayIcon.Click += btnTray_Click; trayIcon.DoubleClick += btnTray_Click; trayIcon.Visible = false; + + _job = new Job(_log); + + _controls = new Control[] { txtJiraLogin, txtJiraPassword, txtMercurialEmail, actTime, txtRepoPath, txtDummyMode, btnSave, btnStart, btnMeeting }; } private void frmMain_FormClosing(object sender, FormClosingEventArgs e) @@ -57,7 +81,7 @@ namespace JiraTimeBotForm Extensions.Extensions.Restore(this); } - private void btnSave_Click(object sender, EventArgs e) + public Settings ReadSettingsAndLock() { var settings = new Settings { @@ -65,9 +89,30 @@ namespace JiraTimeBotForm JiraPassword = txtJiraPassword.Text, MercurialAuthorEmail = txtMercurialEmail.Text, ActivationTime = TimeSpan.Parse(actTime.Text), - RepositoryPath = txtRepoPath.Text - + RepositoryPath = txtRepoPath.Text, + DummyMode = txtDummyMode.Checked }; + + LockUnlock(false); + + return settings; + } + + public void LockUnlock(bool enabled) + { + foreach (var control in _controls) + { + control.Enabled = enabled; + } + + btnCancel.Enabled = !enabled; + tmrStart.Enabled = enabled; + } + + private void btnSave_Click(object sender, EventArgs e) + { + var settings = ReadSettingsAndLock(); + LockUnlock(true); var password = new EncryptionClass().Encrypt(settings.JiraUserName, settings.JiraPassword, settings.JiraUrl); settings.JiraPassword = password; @@ -99,11 +144,25 @@ namespace JiraTimeBotForm txtMercurialEmail.Text = settings.MercurialAuthorEmail; txtRepoPath.Text = settings.RepositoryPath; actTime.Text = settings.ActivationTime.ToString("hh\\:mm\\:ss"); + txtDummyMode.Checked = settings.DummyMode; } - private void btnStart_Click(object sender, EventArgs e) + private async void btnStart_Click(object sender, EventArgs e) { - DoTheJob(); + var settings = ReadSettingsAndLock(); + + if (!Directory.Exists(settings.RepositoryPath)) + { + MessageBox.Show("Ïàïêà ñ ðåïî íå ñóøåñòâóåò.", "", MessageBoxButtons.OK, MessageBoxIcon.Error); + return; + } + + using (_tokenSource = GetTokenSource()) + { + await _job.DoTheJob(settings, new WorkLogTasksProcessor(_log), _tokenSource.Token); + } + + LockUnlock(true); } private void frmMain_Resize(object sender, EventArgs e) @@ -120,127 +179,65 @@ namespace JiraTimeBotForm } } - private void tmrStart_Tick(object sender, EventArgs e) + private async void tmrStart_Tick(object sender, EventArgs e) { var runTime = TimeSpan.Parse(actTime.Text); + if (Math.Abs((DateTime.Now.TimeOfDay - runTime).TotalSeconds) < 1) { if (DateTime.Now.DayOfWeek == DayOfWeek.Saturday || DateTime.Now.DayOfWeek == DayOfWeek.Sunday) { - _log.Error("сегодня суббота или воскресенье. Работать нельзя =)"); + _log.Error("Ñåãîäíÿ ñóááîòà èëè âîñêðåñåíüå. Ðàáîòàòü íåëüçÿ =)"); return; } - txtDummyMode.Checked = false; - DoTheJob(); + _log.Info("Àâòîìàòè÷åñêîå âíåñåíèå âðåìåíè."); + + var settings = ReadSettingsAndLock(); + + await Task.Delay(2000); + + if (settings.DummyMode) + { + settings.DummyMode = false; + _log.Info("Âûêëþ÷àåì ðåæèì Òåñòîâîãî ïðîãîíà"); + } + + using (var tokenSource = GetTokenSource()) + { + await _job.DoTheJob(settings, new WorkLogTasksProcessor(_log), tokenSource.Token); + } + + LockUnlock(true); } } - private void DoTheJob() + private async void btnMeeting_Click(object sender, EventArgs e) { - if (!Directory.Exists(txtRepoPath.Text)) + var settings = ReadSettingsAndLock(); + + if (!Directory.Exists(settings.RepositoryPath)) { - MessageBox.Show("Папка с репо не сушествует.", "", MessageBoxButtons.OK, MessageBoxIcon.Error); + MessageBox.Show("Ïàïêà ñ ðåïî íå ñóøåñòâóåò.", "", MessageBoxButtons.OK, MessageBoxIcon.Error); return; } - txtLog.Text = ""; - var settings = new Settings + using (_tokenSource = GetTokenSource()) { - JiraUserName = txtJiraLogin.Text, - JiraPassword = txtJiraPassword.Text, - MercurialAuthorEmail = txtMercurialEmail.Text, - ActivationTime = TimeSpan.Parse(actTime.Text), - RepositoryPath = txtRepoPath.Text - }; - - var jira = new JiraApi(settings, _log); - var taskDiscoverer = new TaskTimeDiscoverer(_log); - - int daysDiff = 0; - while (true) - { - var date = DateTime.Now.Date.AddDays(daysDiff); - var taskTimes = taskDiscoverer.GetTaskTimes(settings, date); - if (!taskTimes.Any()) - { - _log.Warn($"{date:dd.MM.yyyy} вы не сделали ничего полезного =) Использую предыдущий день."); - daysDiff--; - if (daysDiff < -7) - { - _log.Error("Не нашли ни одного коммита за предыдущие 7 дней. Возможно вы в отпуске? Выхожу."); - return; - } - - continue; - } - - _log.Trace($"На реальную дату {date:dd.MM.yyyy} распределение по задачам:"); - foreach (var taskTime in taskTimes) - { - _log.Trace($"- {taskTime.Branch} (коммитов {taskTime.Commits}): {taskTime.Time}"); - } - - jira.SetTodayWorklog(taskTimes, dummy: txtDummyMode.Checked); - _log.Info("Готово."); - return; - } - } - - private void btnMeeting_Click(object sender, EventArgs e) - { - if (!Directory.Exists(txtRepoPath.Text)) - { - MessageBox.Show("Папка с репо не сушествует.", "", MessageBoxButtons.OK, MessageBoxIcon.Error); - return; - } - - txtLog.Text = ""; - var settings = new Settings - { - JiraUserName = txtJiraLogin.Text, - JiraPassword = txtJiraPassword.Text, - MercurialAuthorEmail = txtMercurialEmail.Text, - ActivationTime = TimeSpan.Parse(actTime.Text), - RepositoryPath = txtRepoPath.Text - }; - - var jira = new JiraApi(settings, _log); - var taskDiscoverer = new TaskTimeDiscoverer(); - - int daysDiff = -1; - while (true) - { - var date = DateTime.Now.Date.AddDays(daysDiff); - var taskTimes = taskDiscoverer.GetTaskTimes(settings, date); - if (!taskTimes.Any()) - { - _log.Warn($"{date:dd.MM.yyyy} вы не сделали ничего полезного =) Использую предыдущий день."); - daysDiff--; - if (daysDiff < -7) - { - _log.Error("Не нашли ни одного коммита за предыдущие 7 дней. Возможно вы в отпуске? Выхожу."); - return; - } - - continue; - } - - _log.Trace($"На реальную дату {date:dd.MM.yyyy} распределение по задачам:"); - foreach (var taskTime in taskTimes.OrderByDescending(f=>f.Time)) - { - var taskName = jira.GetTaskName(taskTime.Branch); - _log.Trace($"- {taskTime.Branch}: {taskName} - {taskTime.Time}"); - } - - break; + await _job.DoTheJob(settings, new MeetingProcessor(_log), _tokenSource.Token); } + LockUnlock(true); } private void label2_Click(object sender, EventArgs e) { } + + private void btnCancel_Click(object sender, EventArgs e) + { + _tokenSource.Cancel(); + } } }