Compare commits

...
11 Commits
11 changed files with 154 additions and 105 deletions
+1 -1
View File
@@ -1 +1 @@
1.0.20
1.0.23
+13
View File
@@ -5,5 +5,18 @@
- Предполагается что все Ваши репозитории находятся в одной папке (к которой вы указываете путь в настройках).
- Предполагается что ветки в JIRA имеют название эквивалентное имени бранча в Mercurial.
# Настройки
- Режим работы:
- Mercurial - по коммитам в Mercurial, можем определять множественные коммиты в одну задачу (ветку) и пропорционально списывать время.
- Jira - выполняем JQL и равномерно распределяем время.
- Путь до репо (Режим Mercurial) - путь до папки, в которую клонируются исходники.
- Логин Jira - Логин в Jira (от этого пользователя будем выполнять запросы и вносить время).
- Пароль Jira - шифруется через DPAPI.
- Mercurial Name (Режим Mercurial) - обязателен к указанию для режима Mercurial - имя пользователя Mercurial, от которого проходят коммиты.
- Округление времени - Для красоты распределения времени тут устанавливается округление. По умолчанию - 15 минут, получим время 1:15, 0:30 итд. Остаток нераспределенного времени будет внесен в самую долгую задачу или же если это невозможно - количество рабочего времени будет увеличено или уменьшено.
- JQL (Режим Jira) - можно задать свой JQL для поиска задачь. Возможные замены: %USER% - Логин Jira, %DATE% дата на которую формируем список. Значнеие по умолчанию: status changed by '%USER%' during ("%DATE%","%DATE%")
- Время запуска - время автоматического запуска бота. Если была установлена галочка "тестовый прогон" - она будет снята.
- Добавлять описание (Режим Mercurial) - добавлять ли в описание CommitMessage, если не установлено - добавляются стандартные фразы программистов (типа "написание кода").
# Скачать
Скачать актуальную версию можно тут: https://github.com/monster1025/JiraTimeBot/releases/latest
+13 -3
View File
@@ -1,5 +1,4 @@
using System.Windows.Forms;
using Autofac;
using Autofac;
using Autofac.Extras.AggregateService;
using JiraTimeBot.JiraIntegration;
using JiraTimeBot.JiraIntegration.Comments;
@@ -8,6 +7,8 @@ using JiraTimeBot.Mercurial.Modifiers;
using JiraTimeBot.TasksProcessors;
using JiraTimeBot.TaskTime;
using JiraTimeBot.UI.Tray;
using System;
using System.Windows.Forms;
namespace JiraTimeBot.DI
{
@@ -21,7 +22,16 @@ namespace JiraTimeBot.DI
public IContainer Build(TextBox logTextBox)
{
_builder.Register(f => new Logger(logTextBox)).As<ILog>().AsSelf();
_builder.Register(c => logTextBox).AsSelf();
_builder.Register(f =>
{
var txt = f.Resolve<TextBox>();
return new Logger(message =>
{
txt.Invoke(new Action<string>(text => txt.AppendText(text)), message + Environment.NewLine);
});
}).As<ILog>().AsSelf();
_builder.Register(f => new TrayMenu()).As<ITrayMenu>().AsSelf();
_builder.Register(c => new CommitSkipper()).As<ICommitSkipper>();
@@ -1,8 +1,8 @@
using System;
using JiraTimeBot.Configuration;
using JiraTimeBot.TaskTime.Objects;
using System;
using System.Collections.Generic;
using System.Linq;
using JiraTimeBot.Configuration;
using JiraTimeBot.TaskTime.Objects;
namespace JiraTimeBot.JiraIntegration.Comments
{
+14 -7
View File
@@ -34,14 +34,13 @@ namespace JiraTimeBot.JiraIntegration
}
}
public List<Issue> GetTodayIssues(Settings settings, DateTime? date = null, CancellationToken cancellationToken = default(CancellationToken))
public List<Issue> GetIssuesByJQL(string jql, Settings settings, DateTime? date = null, CancellationToken cancellationToken = default(CancellationToken))
{
var jira = Jira.CreateRestClient(settings.JiraUrl, settings.JiraUserName, settings.JiraPassword);
date = date.GetValueOrDefault(DateTime.Now.Date);
var userName = settings.JiraUserName;
var jql = settings.JiraQuery;
if (string.IsNullOrEmpty(jql))
{
jql = $"status changed by '%USER%' during (\"%DATE%\",\"%DATE%\")";
@@ -53,7 +52,7 @@ namespace JiraTimeBot.JiraIntegration
try
{
List<Issue> affectedIssues =
jira.Issues.GetIssuesFromJqlAsync(jql, 50, 0, cancellationToken).Result.ToList();
jira.Issues.GetIssuesFromJqlAsync(jql, 100, 0, cancellationToken).Result.ToList();
return affectedIssues;
}
catch (Exception ex)
@@ -92,15 +91,24 @@ namespace JiraTimeBot.JiraIntegration
var hasTodayWorklog = false;
var workLogs = issue.GetWorklogsAsync().Result;
foreach (var workLog in workLogs)
var userWorklogs = workLogs.Where(w =>
w.CreateDate.GetValueOrDefault().Date == date && w.Author.Equals(settings.JiraUserName,
StringComparison.InvariantCultureIgnoreCase)).ToList();
foreach (var workLog in userWorklogs)
{
var timeSpent = TimeSpan.FromSeconds(workLog.TimeSpentInSeconds);
if (workLog.CreateDate.GetValueOrDefault().Date == date && workLog.Author == settings.JiraUserName)
{
var timeDiff = Math.Abs((timeSpent - taskTimeItem.Time).TotalMinutes);
if (timeDiff > 1 || userWorklogs.Count > 1)
{
if (timeDiff > 1)
{
_log.Trace($"Время отличается на {timeDiff} минут, удаляю worklog: {taskTimeItem.Branch} {workLog.Author} {workLog.CreateDate}: {workLog.TimeSpent}");
}
else
{
_log.Trace($"Найдено более одного ворклога на задачу, удаляю worklog: {taskTimeItem.Branch} {workLog.Author} {workLog.CreateDate}: {workLog.TimeSpent}");
}
if (!dummy)
{
issue.DeleteWorklogAsync(workLog);
@@ -113,7 +121,6 @@ namespace JiraTimeBot.JiraIntegration
hasTodayWorklog = true;
}
}
}
if (!hasTodayWorklog)
{
@@ -1,6 +1,8 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using Atlassian.Jira;
using JiraTimeBot.Configuration;
using JiraTimeBot.Mercurial;
using JiraTimeBot.Mercurial.Objects;
@@ -24,9 +26,32 @@ namespace JiraTimeBot.JiraIntegration
{
date = date.GetValueOrDefault(DateTime.Now.Date);
var workTasks = new List<MercurialCommitItem>();
var issues = _jiraApi.GetTodayIssues(settings, date, cancellationToken);
var issues = _jiraApi.GetIssuesByJQL(settings.JiraQuery, settings, date, cancellationToken);
foreach (var issue in issues)
{
if (cancellationToken.IsCancellationRequested)
{
return new List<MercurialCommitItem>();
}
List<Comment> comments = new List<Comment>();
if (issue.Type?.Name != "Дубликат")
{
_log.Trace($"Получаю комментарии по задаче {issue.Key} ({issue.Type?.Name}).");
comments = issue.GetCommentsAsync(cancellationToken).Result?.ToList() ?? new List<Comment>();
}
else
{
_log.Trace($"Пропускаю комментарии по задаче {issue.Key} ({issue.Type?.Name}).");
}
var user = settings.JiraUserName;
var userComments = comments.Where(f => f.Author.Equals(user, StringComparison.InvariantCultureIgnoreCase)).ToList();
if (userComments.Any())
{
foreach (var comment in userComments)
{
workTasks.Add(new MercurialCommitItem
{
@@ -36,6 +61,18 @@ namespace JiraTimeBot.JiraIntegration
FilesAffected = 1
});
}
}
else
{
workTasks.Add(new MercurialCommitItem
{
Description = issue.Summary,
Time = issue.Updated.GetValueOrDefault(date.Value),
Branch = issue.Key.Value,
FilesAffected = 1
});
}
}
return workTasks;
}
+4 -10
View File
@@ -1,29 +1,23 @@
using System;
using System.ComponentModel;
using System.Windows.Forms;
namespace JiraTimeBot
{
public class Logger : ILog
{
private readonly TextBox _txt;
private readonly AppendLog _safeAppender;
private readonly Action<string> _logAction;
public Logger(TextBox txt)
public Logger(Action<string> logAction)
{
_txt = txt;
_safeAppender = text => _txt.AppendText(text);
_logAction = logAction;
}
private void AppendText(string message)
{
message = $"{DateTime.Now:HH:mm} {message}";
_txt.Invoke(_safeAppender, message + Environment.NewLine);
_logAction(message);
}
private delegate void AppendLog(string text);
public void Info([Localizable(false)] string message)
{
AppendText(message);
+8 -23
View File
@@ -1,45 +1,30 @@
using System;
using System.Diagnostics;
using JiraTimeBot.UI;
using System;
using System.Threading;
using System.Windows.Forms;
using JiraTimeBot.UI;
namespace JiraTimeBot
{
static class Program
{
private static Mutex _mutex = new Mutex(true, "{44426B3E-B901-4792-ACEA-1385D79DBAD1}");
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
if (PriorProcess() != null)
if (_mutex.WaitOne(TimeSpan.Zero, true))
{
MessageBox.Show("Another instance of the app is already running.");
return;
}
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new frmMain());
_mutex.ReleaseMutex();
}
public static Process PriorProcess()
// Returns a System.Diagnostics.Process pointing to
// a pre-existing process with the same name as the
// current one, if any; or null if the current process
// is unique.
else
{
Process curr = Process.GetCurrentProcess();
Process[] procs = Process.GetProcessesByName(curr.ProcessName);
foreach (Process p in procs)
{
if ((p.Id != curr.Id) &&
(p.MainModule.FileName == curr.MainModule.FileName))
return p;
MessageBox.Show("Another instance of the app is already running.");
}
return null;
}
}
}
+3 -3
View File
@@ -26,6 +26,6 @@ using System.Runtime.InteropServices;
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
[assembly: AssemblyVersion("1.0.20")]
[assembly: AssemblyFileVersion("1.0.20")]
[assembly: AssemblyInformationalVersion("1.0.20")]
[assembly: AssemblyVersion("1.0.23")]
[assembly: AssemblyFileVersion("1.0.23")]
[assembly: AssemblyInformationalVersion("1.0.23")]
@@ -78,8 +78,11 @@ namespace JiraTimeBot.TaskTime
_log.Trace($"Погрешность распределения времени: {remainMinutes}. Добавляю к первой задаче.");
}
if (workTimeItems.First().Time.TotalMinutes > Math.Abs(remainMinutes) && remainMinutes < 0)
{
//если переборщили или не достаточно добавили до 8 часов - скореектируем остаток в первой задаче (она самая трудозатратная).
workTimeItems.First().Time += TimeSpan.FromMinutes(remainMinutes);
}
return workTimeItems;
}
+7 -7
View File
@@ -1,16 +1,16 @@
using System;
using Autofac;
using JiraTimeBot.Configuration;
using JiraTimeBot.DI;
using JiraTimeBot.TasksProcessors;
using JiraTimeBot.UI.Tray;
using JiraTimeBot.Update;
using System;
using System.Collections.Generic;
using System.IO;
using System.IO.Compression;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using Autofac;
using JiraTimeBot.Configuration;
using JiraTimeBot.DI;
using JiraTimeBot.TasksProcessors;
using JiraTimeBot.UI.Tray;
using JiraTimeBot.Update;
// This is the code for your desktop app.
// Press Ctrl+F5 (or go to Debug > Start Without Debugging) to run your app.