Compare commits

...
6 Commits
21 changed files with 422 additions and 238 deletions
+1 -1
View File
@@ -1 +1 @@
1.0.33
1.0.37
+2 -2
View File
@@ -12,12 +12,12 @@
- Путь до репо (Режим Mercurial) - путь до папки, в которую клонируются исходники.
- Логин Jira - Логин в Jira (от этого пользователя будем выполнять запросы и вносить время).
- Пароль Jira - шифруется через DPAPI.
- Mercurial Name (Режим Mercurial) - обязателен к указанию для режима Mercurial - имя пользователя Mercurial, от которого проходят коммиты.
- Mercurial Name (Режим Mercurial) - обязателен к указанию для режима Mercurial - имя пользователя Mercurial, от которого проходят коммиты (именно UserName, не E-Mail).
- Округление времени - Для красоты распределения времени тут устанавливается округление. По умолчанию - 15 минут, получим время 1:15, 0:30 итд. Остаток нераспределенного времени будет внесен в самую долгую задачу или же если это невозможно - количество рабочего времени будет увеличено или уменьшено.
- JQL (Режим Jira) - можно задать свой JQL для поиска задач. Возможные замены: %USER% - Логин Jira, %DATE% дата на которую формируем список. Значнеие по умолчанию: status changed by '%USER%' during ("%DATE%","%DATE%")
- Задача "учёта времени" - задача, куда будет списываться по 30 минут в день на "затраты на учет времени". Должна содержать знак '-'.
- Время запуска - время автоматического запуска бота. Если была установлена галочка "тестовый прогон" - она будет снята.
- Добавлять описание (Режим Mercurial) - добавлять ли в описание CommitMessage, если не установлено - добавляются стандартные фразы программистов (типа "написание кода").
- Задача "учёта времени" - задача, куда будет списываться по 30 минут в день на "затраты на учет времени". Должна содержать знак '-'.
# Скачать
Скачать актуальную версию можно тут: https://github.com/monster1025/JiraTimeBot/releases/latest
+8
View File
@@ -9,6 +9,9 @@ using JiraTimeBot.TaskTime;
using JiraTimeBot.UI.Tray;
using System;
using System.Windows.Forms;
using JiraTimeBot.UI;
using JiraTimeBot.UI.Startup;
using JiraTimeBot.Update;
namespace JiraTimeBot.DI
{
@@ -36,6 +39,8 @@ namespace JiraTimeBot.DI
_builder.Register(f => new TrayMenu()).As<ITrayMenu>().AsSelf();
_builder.Register(c => new CommitSkipper()).As<ICommitSkipper>();
_builder.RegisterType<Updater>().As<IUpdater>();
_builder.RegisterType<TechnicalInfoSkipper>().As<ITechnicalInfoSkipper>().AsSelf();
_builder.RegisterType<MercurialLog>().As<IMercurialLog>().AsSelf();
@@ -53,6 +58,9 @@ namespace JiraTimeBot.DI
_builder.Register(c => new Job(c.Resolve<IAllMercurialProviders>(), c.Resolve<ITaskTimeCalculator>(), c.Resolve<ILog>())).AsSelf();
_builder.RegisterType<AutoStartUp>().AsSelf().AsImplementedInterfaces();
_builder.RegisterType<frmSettings>().AsSelf().AsImplementedInterfaces();
var container = _builder.Build();
return container;
}
+39 -10
View File
@@ -62,15 +62,44 @@ namespace JiraTimeBot.JiraIntegration
}
}
public void SetTodayWorklog(List<TaskTimeItem> taskTimeItems, Settings settings, DateTime? date = null, bool dummy = false, bool addCommentsToWorklog = false)
public List<Issue> GetWorkloggedIssuesByDate(Settings settings, DateTime? date = null, CancellationToken cancellationToken = default(CancellationToken))
{
date = date.GetValueOrDefault(DateTime.Now.Date);
var jql = "issueFunction in workLogged(\"on %DATE% by '%USER%'\")";
return GetIssuesByJQL(jql, settings, date, cancellationToken);
}
private void RemoveWorklogsAddedByUser(List<TaskTimeItem> taskTimeItems, Settings settings, DateTime? date = null, bool dummy = false, CancellationToken cancellationToken = default(CancellationToken))
{
var alreadyLoggedToday = GetWorkloggedIssuesByDate(settings, date);
foreach (var issue in alreadyLoggedToday)
{
if (!taskTimeItems.Any(f => f.Branch.Equals(issue.Key.Value, StringComparison.InvariantCulture)))
{
var workLogs = issue.GetWorklogsAsync(cancellationToken).Result;
var userWorklogs = workLogs.Where(w =>
w.CreateDate.GetValueOrDefault().Date == date && w.Author.Equals(settings.JiraUserName,
StringComparison.InvariantCultureIgnoreCase)).ToList();
foreach (var userWorklog in userWorklogs)
{
_log.Trace($"Удаляю добавленный руками WorkLog для задачи {issue.Key.Value}: {userWorklog.TimeSpent}, {userWorklog.Comment}.");
if (!dummy)
{
issue.DeleteWorklogAsync(userWorklog, token: cancellationToken);
}
}
}
}
}
public void SetTodayWorklog(List<TaskTimeItem> taskTimeItems, Settings settings, DateTime? date = null, bool dummy = false, bool addCommentsToWorklog = false, CancellationToken cancellationToken = default(CancellationToken))
{
date = date.GetValueOrDefault(DateTime.Now.Date).Date;
var jira = Jira.CreateRestClient(settings.JiraUrl, settings.JiraUserName, settings.JiraPassword);
if (date == null)
{
date = DateTime.Now.Date;
}
date = date.Value.Date;
//Удаляем добавленные вручную пользователем данные.
RemoveWorklogsAddedByUser(taskTimeItems, settings, date, dummy, cancellationToken);
foreach (TaskTimeItem taskTimeItem in taskTimeItems)
{
@@ -90,9 +119,9 @@ namespace JiraTimeBot.JiraIntegration
}
var hasTodayWorklog = false;
var workLogs = issue.GetWorklogsAsync().Result;
var workLogs = issue.GetWorklogsAsync(cancellationToken).Result;
var userWorklogs = workLogs.Where(w =>
w.CreateDate.GetValueOrDefault().Date == date && w.Author.Equals(settings.JiraUserName,
w.StartDate.GetValueOrDefault().Date == date && w.Author.Equals(settings.JiraUserName,
StringComparison.InvariantCultureIgnoreCase)).ToList();
foreach (var workLog in userWorklogs)
@@ -111,7 +140,7 @@ namespace JiraTimeBot.JiraIntegration
}
if (!dummy)
{
issue.DeleteWorklogAsync(workLog);
issue.DeleteWorklogAsync(workLog, token: cancellationToken);
}
hasTodayWorklog = false;
}
@@ -131,7 +160,7 @@ namespace JiraTimeBot.JiraIntegration
Worklog workLogToAdd = new Worklog(timeSpentJira, date.Value, comment);
if (!dummy)
{
workLogToAdd = issue.AddWorklogAsync(workLogToAdd).Result;
workLogToAdd = issue.AddWorklogAsync(workLogToAdd, token: cancellationToken).Result;
}
_log.Trace($"Добавили Worklog для {taskTimeItem.Branch}: {workLogToAdd.Author} {workLogToAdd.CreateDate}: {workLogToAdd.TimeSpent}");
}
@@ -37,6 +37,7 @@ namespace JiraTimeBot.JiraIntegration
var comments = issue.GetCommentsAsync(cancellationToken).Result?.ToList() ?? new List<Comment>();
var user = settings.JiraUserName;
//user = "Zoya.Aleksandridi";
var userComments = comments.Where(f => f.Author.Equals(user, StringComparison.InvariantCultureIgnoreCase)).ToList();
_log.Trace($"Получены комментарии по задаче {issue.Key} ({issue.Type?.Name}): {userComments.Count}.");
+3 -1
View File
@@ -116,12 +116,14 @@
<Compile Include="UI\frmSettings.Designer.cs">
<DependentUpon>frmSettings.cs</DependentUpon>
</Compile>
<Compile Include="UI\Startup\AutoStartUp.cs" />
<Compile Include="UI\Tray\SingleInstance.cs" />
<Compile Include="UI\Tray\ITrayMenu.cs" />
<Compile Include="UI\Tray\RestoreFromTray.cs" />
<Compile Include="UI\Tray\TrayMenu.cs" />
<Compile Include="Update\GitHubDataObjects.cs" />
<Compile Include="Update\UpdateChecker.cs" />
<Compile Include="Update\IUpdater.cs" />
<Compile Include="Update\Updater.cs" />
<EmbeddedResource Include="UI\frmMain.resx">
<DependentUpon>frmMain.cs</DependentUpon>
</EmbeddedResource>
+41 -26
View File
@@ -40,43 +40,58 @@ namespace JiraTimeBot
daysDiff = -1;
}
var setForDate = DateTime.Now.Date;
while (true)
{
DateTime date = DateTime.Now.Date.AddDays(daysDiff);
DateTime realDate = DateTime.Now.Date.AddDays(daysDiff);
IMercurialLog mercurial = _mercurialProviders.MercurialLog;
if (settings.WorkType == WorkType.JiraLogs)
{
_log.Info("Использую Jira как источник информации.");
mercurial = _mercurialProviders.JiraCommitEmulator;
}
List<MercurialCommitItem> commits = mercurial.GetMercurialLog(settings, date, cancellationToken);
List<TaskTimeItem> taskTimes = _taskTimeDiscoverer.CalculateTaskTime(commits, settings, cancellationToken);
if (cancellationToken.IsCancellationRequested)
if (SetTaskTimesForDateImpl(setForDate, realDate, settings, tasksProcessor, dummyMode, cancellationToken))
{
return;
}
if (!taskTimes.Any())
_log.Warn($"{realDate:dd.MM.yyyy} вы не сделали ничего полезного =) Использую предыдущий день.");
daysDiff--;
if (daysDiff < -7)
{
_log.Warn($"{date:dd.MM.yyyy} вы не сделали ничего полезного =) Использую предыдущий день.");
daysDiff--;
if (daysDiff < -7)
{
_log.Error("Не нашли ни одного коммита за предыдущие 7 дней. Возможно вы в отпуске? Выхожу.");
return;
}
continue;
_log.Error("Не нашли ни одного коммита за предыдущие 7 дней. Возможно вы в отпуске? Выхожу.");
return;
}
tasksProcessor.Process(date, taskTimes, settings, dummyMode);
_log.Info("Готово.");
return;
}
}
public Task SetTaskTimesForDate(DateTime setForDate, DateTime realDate, Settings settings, ITasksProcessor tasksProcessor, bool dummyMode, CancellationToken cancellationToken)
{
_log.Info("Начинаем работу");
return Task.Run(() => SetTaskTimesForDateImpl(setForDate, realDate, settings, tasksProcessor, dummyMode, cancellationToken), cancellationToken);
}
private bool SetTaskTimesForDateImpl(DateTime setForDate, DateTime realDate, Settings settings, ITasksProcessor tasksProcessor, bool dummyMode, CancellationToken cancellationToken)
{
IMercurialLog mercurial = _mercurialProviders.MercurialLog;
if (settings.WorkType == WorkType.JiraLogs)
{
_log.Info("Использую Jira как источник информации.");
mercurial = _mercurialProviders.JiraCommitEmulator;
}
List<MercurialCommitItem> commits = mercurial.GetMercurialLog(settings, realDate, cancellationToken);
List<TaskTimeItem> taskTimes = _taskTimeDiscoverer.CalculateTaskTime(commits, settings, cancellationToken);
if (cancellationToken.IsCancellationRequested)
{
return false;
}
if (!taskTimes.Any())
{
return false;
}
tasksProcessor.Process(setForDate, realDate, taskTimes, settings, dummyMode, cancellationToken);
_log.Info("Готово.");
return true;
}
}
}
-2
View File
@@ -1,7 +1,5 @@
using JiraTimeBot.UI;
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Threading;
using System.Windows.Forms;
using JiraTimeBot.UI.Tray;
+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.33")]
[assembly: AssemblyFileVersion("1.0.33")]
[assembly: AssemblyInformationalVersion("1.0.33")]
[assembly: AssemblyVersion("1.0.37")]
[assembly: AssemblyFileVersion("1.0.37")]
[assembly: AssemblyInformationalVersion("1.0.37")]
@@ -3,7 +3,6 @@ using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Web.UI.WebControls.WebParts;
using JiraTimeBot.Configuration;
using JiraTimeBot.Mercurial.Objects;
using JiraTimeBot.TaskTime.Objects;
@@ -105,9 +104,21 @@ namespace JiraTimeBot.TaskTime
workTimeItems.First().Time += TimeSpan.FromMinutes(remainMinutes);
}
PrintTotal(workTimeItems);
return workTimeItems;
}
private void PrintTotal(List<TaskTimeItem> workTimeItems)
{
var totalTime = TimeSpan.Zero;
foreach (var workTimeItem in workTimeItems)
{
totalTime += workTimeItem.Time;
}
_log.Trace($"Итоговое реально проставляемое время: {totalTime}");
}
private decimal RoundTo(decimal value, decimal to = 15, bool up = true)
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.Threading;
using JiraTimeBot.Configuration;
using JiraTimeBot.TaskTime.Objects;
@@ -7,6 +8,6 @@ namespace JiraTimeBot.TasksProcessors
{
interface ITasksProcessor
{
void Process(DateTime date, List<TaskTimeItem> taskTimes, Settings settings, bool dummyMode);
void Process(DateTime setForDate, DateTime realDate, List<TaskTimeItem> taskTimes, Settings settings, bool dummyMode, CancellationToken cancellationToken = default(CancellationToken));
}
}
@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using JiraTimeBot.Configuration;
using JiraTimeBot.JiraIntegration;
using JiraTimeBot.TaskTime.Objects;
@@ -18,9 +19,9 @@ namespace JiraTimeBot.TasksProcessors
_jiraApi = jiraApi;
}
public void Process(DateTime date, List<TaskTimeItem> taskTimes, Settings settings, bool dummyMode)
public void Process(DateTime setForDate, DateTime realDate, List<TaskTimeItem> taskTimes, Settings settings, bool dummyMode, CancellationToken cancellationToken = default(CancellationToken))
{
_log.Trace($"На реальную дату {date:dd.MM.yyyy} распределение по задачам:");
_log.Trace($"На реальную дату {realDate:dd.MM.yyyy} распределение по задачам:");
foreach (var taskTime in taskTimes.OrderByDescending(f => f.Time))
{
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.Threading;
using JiraTimeBot.Configuration;
using JiraTimeBot.JiraIntegration;
using JiraTimeBot.TaskTime.Objects;
@@ -17,15 +18,15 @@ namespace JiraTimeBot.TasksProcessors
_jiraApi = jiraApi;
}
public void Process(DateTime date, List<TaskTimeItem> taskTimes, Settings settings, bool dummyMode)
public void Process(DateTime setForDate, DateTime realDate, List<TaskTimeItem> taskTimes, Settings settings, bool dummyMode, CancellationToken cancellationToken = default(CancellationToken))
{
_log.Trace($"На реальную дату {date:dd.MM.yyyy} распределение по задачам:");
_log.Trace($"На реальную дату {realDate:dd.MM.yyyy} распределение по задачам:");
foreach (var taskTime in taskTimes)
{
_log.Trace($"- {taskTime.Branch} (коммитов {taskTime.Commits}): {taskTime.Time}");
}
_jiraApi.SetTodayWorklog(taskTimes, settings, dummy: dummyMode, addCommentsToWorklog: settings.AddCommentsToWorklog);
_jiraApi.SetTodayWorklog(taskTimes, settings, date: setForDate, dummy: dummyMode, addCommentsToWorklog: settings.AddCommentsToWorklog, cancellationToken: cancellationToken);
}
}
}
+27
View File
@@ -0,0 +1,27 @@
using System.Windows.Forms;
using Microsoft.Win32;
namespace JiraTimeBot.UI.Startup
{
public class AutoStartUp
{
readonly RegistryKey _rkApp = Registry.CurrentUser.OpenSubKey("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run", true);
public bool Get()
{
return _rkApp.GetValue(Application.ProductName) != null;
}
public void Set(bool autoStart)
{
if (autoStart)
{
_rkApp.SetValue(Application.ProductName, Application.ExecutablePath);
}
else
{
_rkApp.DeleteValue(Application.ProductName, false);
}
}
}
}
+27
View File
@@ -39,6 +39,8 @@
this.btnCancel = new System.Windows.Forms.Button();
this.btnSettings = new System.Windows.Forms.Button();
this.tmrUpdate = new System.Windows.Forms.Timer(this.components);
this.dteForDay = new System.Windows.Forms.DateTimePicker();
this.btnDoForDate = new System.Windows.Forms.Button();
this.SuspendLayout();
//
// txtLog
@@ -117,11 +119,34 @@
this.tmrUpdate.Interval = 1000;
this.tmrUpdate.Tick += new System.EventHandler(this.tmrUpdate_Tick);
//
// dteForDay
//
this.dteForDay.CustomFormat = "dd.MM.yyyy";
this.dteForDay.Format = System.Windows.Forms.DateTimePickerFormat.Short;
this.dteForDay.Location = new System.Drawing.Point(12, 69);
this.dteForDay.MinDate = new System.DateTime(2019, 1, 1, 0, 0, 0, 0);
this.dteForDay.Name = "dteForDay";
this.dteForDay.ShowUpDown = true;
this.dteForDay.Size = new System.Drawing.Size(113, 20);
this.dteForDay.TabIndex = 17;
//
// btnDoForDate
//
this.btnDoForDate.Location = new System.Drawing.Point(13, 96);
this.btnDoForDate.Name = "btnDoForDate";
this.btnDoForDate.Size = new System.Drawing.Size(112, 36);
this.btnDoForDate.TabIndex = 18;
this.btnDoForDate.Text = "Проставить на дату";
this.btnDoForDate.UseVisualStyleBackColor = true;
this.btnDoForDate.Click += new System.EventHandler(this.btnDoForDate_Click);
//
// frmMain
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(740, 320);
this.Controls.Add(this.btnDoForDate);
this.Controls.Add(this.dteForDay);
this.Controls.Add(this.btnSettings);
this.Controls.Add(this.btnCancel);
this.Controls.Add(this.btnMeeting);
@@ -151,6 +176,8 @@
private System.Windows.Forms.Button btnCancel;
private System.Windows.Forms.Button btnSettings;
private System.Windows.Forms.Timer tmrUpdate;
private System.Windows.Forms.DateTimePicker dteForDay;
private System.Windows.Forms.Button btnDoForDate;
}
}
+16 -71
View File
@@ -11,6 +11,7 @@ using System.IO.Compression;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using JiraTimeBot.UI.Startup;
// This is the code for your desktop app.
// Press Ctrl+F5 (or go to Debug > Start Without Debugging) to run your app.
@@ -69,7 +70,7 @@ namespace JiraTimeBot.UI
_settingsWindowShow = () =>
{
var frmSettings = new frmSettings();
var frmSettings = new frmSettings(_container.Resolve<AutoStartUp>());
frmSettings.ShowDialog(this);
};
_settingsErrorReporter = msg => MessageBox.Show(msg, "Загрузка настроек", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);;
@@ -102,7 +103,7 @@ namespace JiraTimeBot.UI
private void Form1_Load(object sender, EventArgs e)
{
this.Text = this.Text + " v." + Application.ProductVersion;
this.Text = this.Text + " v" + Application.ProductVersion;
PrintStartMessage();
tmrStart.Enabled = true;
@@ -201,7 +202,7 @@ namespace JiraTimeBot.UI
private void btnSettings_Click(object sender, EventArgs e)
{
var frm = new frmSettings();
var frm = _container.Resolve<frmSettings>();
frm.ShowDialog();
PrintStartMessage();
@@ -215,38 +216,11 @@ namespace JiraTimeBot.UI
_updateChecked = true;
tmrUpdate.Interval = 1 * 60 * 60 * 1000;
var checker = new UpdateChecker();
var release = checker.GetRelease();
if (release == null)
var updater = _container.Resolve<IUpdater>();
if (updater.UpdateToNewVersion(firstTime))
{
return;
}
var gitVersionStr = checker.GetLatestVersion(release);
var gitVersion = new Version(gitVersionStr);
var appVersion = new Version(Application.ProductVersion);
if (gitVersion > appVersion)
{
var downloadUrl = checker.GetDownloadUrl(release);
_log.Info($"Доступна новая версия: {gitVersion} {downloadUrl}");
var success = checker.DownloadFile(downloadUrl, "update.zip");
if (!success)
{
return;
}
var result = InstallUpdate(gitVersion, "update.zip");
if (result)
{
//если обновились - отключаем до рестарта
tmrUpdate.Enabled = false;
}
}
else if (firstTime)
{
_log.Info($"Вы используете актуальную версию.");
//если обновились - отключаем до рестарта
tmrUpdate.Enabled = false;
}
}
catch (Exception ex)
@@ -256,46 +230,17 @@ namespace JiraTimeBot.UI
}
}
private bool InstallUpdate(Version gitVersion, string updateFile)
private async void btnDoForDate_Click(object sender, EventArgs e)
{
try
var settings = ReadSettingsAndLock();
using (_tokenSource = GetTokenSource())
{
_log.Info($"Устанавливаю обновление до версии {gitVersion}.");
//Rename he executing file
System.IO.FileInfo appFile = new System.IO.FileInfo(System.Reflection.Assembly.GetExecutingAssembly().Location);
var bkpDir = Path.Combine(appFile.DirectoryName, "bkp");
if (!Directory.Exists(bkpDir))
{
Directory.CreateDirectory(bkpDir);
}
using (ZipArchive archive = ZipFile.OpenRead(Path.Combine(appFile.DirectoryName, updateFile)))
{
foreach (ZipArchiveEntry entry in archive.Entries)
{
var zipEntryPath = Path.Combine(appFile.DirectoryName, entry.FullName);
if (File.Exists(zipEntryPath))
{
System.IO.FileInfo zipEntryFile = new System.IO.FileInfo(zipEntryPath);
if (File.Exists(bkpDir + "\\" + zipEntryFile.Name))
{
File.Delete(bkpDir + "\\" + zipEntryFile.Name);
}
System.IO.File.Move(zipEntryFile.FullName, bkpDir + "\\" + zipEntryFile.Name);
}
entry.ExtractToFile(zipEntryPath);
}
}
_log.Info("Обновление установлено. Перезапустите программу для применения изменений.");
return true;
}
catch (Exception)
{
_log.Error($"Что-то пошло не так при обновлении.");
return false;
await _job.SetTaskTimesForDate(dteForDay.Value, dteForDay.Value, settings, _tasksProcessors.WorkLogTasksProcessor, txtDummyMode.Checked, _tokenSource.Token);
}
LockUnlock(true);
}
}
}
+15 -2
View File
@@ -48,6 +48,7 @@
this.txtJQL = new System.Windows.Forms.TextBox();
this.label8 = new System.Windows.Forms.Label();
this.txtTimeControlTask = new System.Windows.Forms.TextBox();
this.chkAutostart = new System.Windows.Forms.CheckBox();
this.SuspendLayout();
//
// label5
@@ -152,7 +153,7 @@
// chkAddComments
//
this.chkAddComments.AutoSize = true;
this.chkAddComments.Location = new System.Drawing.Point(56, 267);
this.chkAddComments.Location = new System.Drawing.Point(65, 277);
this.chkAddComments.Name = "chkAddComments";
this.chkAddComments.Size = new System.Drawing.Size(133, 17);
this.chkAddComments.TabIndex = 31;
@@ -161,7 +162,7 @@
//
// btnSave
//
this.btnSave.Location = new System.Drawing.Point(72, 299);
this.btnSave.Location = new System.Drawing.Point(86, 300);
this.btnSave.Name = "btnSave";
this.btnSave.Size = new System.Drawing.Size(75, 23);
this.btnSave.TabIndex = 32;
@@ -223,11 +224,22 @@
this.txtTimeControlTask.Size = new System.Drawing.Size(99, 20);
this.txtTimeControlTask.TabIndex = 38;
//
// chkAutostart
//
this.chkAutostart.AutoSize = true;
this.chkAutostart.Location = new System.Drawing.Point(65, 254);
this.chkAutostart.Name = "chkAutostart";
this.chkAutostart.Size = new System.Drawing.Size(96, 17);
this.chkAutostart.TabIndex = 40;
this.chkAutostart.Text = "Автозагрузка";
this.chkAutostart.UseVisualStyleBackColor = true;
//
// frmSettings
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(243, 334);
this.Controls.Add(this.chkAutostart);
this.Controls.Add(this.label8);
this.Controls.Add(this.txtTimeControlTask);
this.Controls.Add(this.label7);
@@ -281,5 +293,6 @@
private System.Windows.Forms.TextBox txtJQL;
private System.Windows.Forms.Label label8;
private System.Windows.Forms.TextBox txtTimeControlTask;
private System.Windows.Forms.CheckBox chkAutostart;
}
}
+9 -4
View File
@@ -1,13 +1,17 @@
using System;
using System.Windows.Forms;
using JiraTimeBot.Configuration;
using JiraTimeBot.UI.Startup;
namespace JiraTimeBot.UI
{
public partial class frmSettings : Form
{
public frmSettings()
private readonly AutoStartUp _autoStart;
public frmSettings(AutoStartUp autoStart)
{
_autoStart = autoStart;
InitializeComponent();
}
@@ -18,6 +22,8 @@ namespace JiraTimeBot.UI
{
SetSettings(settings);
}
chkAutostart.Checked = _autoStart.Get();
}
private void SetSettings(Settings settings)
@@ -27,7 +33,6 @@ namespace JiraTimeBot.UI
txtMercurialEmail.Text = settings.MercurialAuthorEmail;
txtRepoPath.Text = settings.RepositoryPath;
actTime.Text = settings.ActivationTime.ToString("hh\\:mm\\:ss");
//txtDummyMode.Checked = settings.DummyMode;
chkAddComments.Checked = settings.AddCommentsToWorklog;
txtRoundTo.Text = settings.RountToMinutes.ToString();
cboWorkType.SelectedIndex = (int) settings.WorkType;
@@ -50,12 +55,11 @@ namespace JiraTimeBot.UI
MercurialAuthorEmail = txtMercurialEmail.Text,
ActivationTime = TimeSpan.Parse(actTime.Text),
RepositoryPath = txtRepoPath.Text,
//DummyMode = txtDummyMode.Checked,
AddCommentsToWorklog = chkAddComments.Checked,
RountToMinutes = roundTo,
WorkType = (WorkType) cboWorkType.SelectedIndex,
JiraQuery = txtJQL.Text,
TimeControlTask = txtTimeControlTask.Text
TimeControlTask = txtTimeControlTask.Text,
};
//LockUnlock(false);
@@ -67,6 +71,7 @@ namespace JiraTimeBot.UI
{
var settings = ReadSettingsAndLock();
settings.Save();
_autoStart.Set(chkAutostart.Checked);
MessageBox.Show("Настройки сохранены.");
+9
View File
@@ -0,0 +1,9 @@
using System;
namespace JiraTimeBot.Update
{
internal interface IUpdater
{
bool UpdateToNewVersion(bool firstTime);
}
}
-78
View File
@@ -1,78 +0,0 @@
using System;
using System.IO;
using System.Linq;
using System.Net;
using Newtonsoft.Json;
namespace JiraTimeBot.Update
{
class UpdateChecker
{
private const string GithubUser = "monster1025";
private const string GithubRepo = "JiraTimeBot";
public string GetLatestVersion(GitHubReleaseResponse release)
{
var version = release?.TagName?.TrimStart('v');
return version;
}
public string GetDownloadUrl(GitHubReleaseResponse release)
{
var downloadUrl = release?.Assets?.FirstOrDefault()?.BrowserDownloadUrl?.ToString();
return downloadUrl ?? "";
}
public GitHubReleaseResponse GetRelease()
{
var latestReleasePage = Get($"https://api.github.com/repos/{GithubUser}/{GithubRepo}/releases/latest");
if (string.IsNullOrEmpty(latestReleasePage))
{
return null;
}
var release = JsonConvert.DeserializeObject<GitHubReleaseResponse>(latestReleasePage);
return release;
}
public bool DownloadFile(string url, string to)
{
try
{
using (var client = new WebClient())
{
client.Headers.Add("User-Agent",
"Mozilla/5.0 (X11; Linux i686; rv:64.0) Gecko/20100101 Firefox/64.0");
client.DownloadFile(url, to);
return true;
}
}
catch (Exception)
{
return false;
}
}
private string Get(string uri)
{
try
{
HttpWebRequest request = (HttpWebRequest) WebRequest.Create(uri);
request.AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate;
request.UserAgent = "Mozilla/5.0 (X11; Linux i686; rv:64.0) Gecko/20100101 Firefox/64.0";
using (HttpWebResponse response = (HttpWebResponse) request.GetResponse())
using (Stream stream = response.GetResponseStream())
using (StreamReader reader = new StreamReader(stream))
{
return reader.ReadToEnd();
}
}
catch (Exception)
{
return "";
}
}
}
}
+169
View File
@@ -0,0 +1,169 @@
using System;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Net;
using System.Windows.Forms;
using Newtonsoft.Json;
namespace JiraTimeBot.Update
{
public class Updater : IUpdater
{
private readonly ILog _log;
public Updater(ILog log)
{
_log = log;
}
private const string GithubUser = "monster1025";
private const string GithubRepo = "JiraTimeBot";
public string GetLatestVersion(GitHubReleaseResponse release)
{
var version = release?.TagName?.TrimStart('v');
return version;
}
public string GetDownloadUrl(GitHubReleaseResponse release)
{
var downloadUrl = release?.Assets?.FirstOrDefault()?.BrowserDownloadUrl?.ToString();
return downloadUrl ?? "";
}
public GitHubReleaseResponse GetRelease()
{
var latestReleasePage = Get($"https://api.github.com/repos/{GithubUser}/{GithubRepo}/releases/latest");
if (string.IsNullOrEmpty(latestReleasePage))
{
return null;
}
var release = JsonConvert.DeserializeObject<GitHubReleaseResponse>(latestReleasePage);
return release;
}
public bool UpdateToNewVersion(bool firstTime)
{
var release = GetRelease();
if (release == null)
{
return false;
}
var gitVersionStr = GetLatestVersion(release);
var gitVersion = new Version(gitVersionStr);
var appVersion = new Version(Application.ProductVersion);
if (gitVersion > appVersion)
{
var downloadUrl = GetDownloadUrl(release);
_log.Info($"Доступна новая версия: {gitVersion} {downloadUrl}");
var success = DownloadFile(downloadUrl, "update.zip");
if (!success)
{
return false;
}
var result = InstallUpdate(gitVersion, "update.zip");
if (result)
{
return true;
}
return false;
}
if (firstTime)
{
_log.Info($"Вы используете актуальную версию.");
}
return false;
}
public bool InstallUpdate(Version gitVersion, string updateFile)
{
try
{
_log.Info($"Устанавливаю обновление до версии {gitVersion}.");
//Rename he executing file
System.IO.FileInfo appFile = new System.IO.FileInfo(System.Reflection.Assembly.GetExecutingAssembly().Location);
var bkpDir = Path.Combine(appFile.DirectoryName, "bkp");
if (!Directory.Exists(bkpDir))
{
Directory.CreateDirectory(bkpDir);
}
using (ZipArchive archive = ZipFile.OpenRead(Path.Combine(appFile.DirectoryName, updateFile)))
{
foreach (ZipArchiveEntry entry in archive.Entries)
{
var zipEntryPath = Path.Combine(appFile.DirectoryName, entry.FullName);
if (File.Exists(zipEntryPath))
{
System.IO.FileInfo zipEntryFile = new System.IO.FileInfo(zipEntryPath);
if (File.Exists(bkpDir + "\\" + zipEntryFile.Name))
{
File.Delete(bkpDir + "\\" + zipEntryFile.Name);
}
System.IO.File.Move(zipEntryFile.FullName, bkpDir + "\\" + zipEntryFile.Name);
}
entry.ExtractToFile(zipEntryPath);
}
}
_log.Info("Обновление установлено. Перезапустите программу для применения изменений.");
return true;
}
catch (Exception)
{
_log.Error($"Что-то пошло не так при обновлении.");
return false;
}
}
private bool DownloadFile(string url, string to)
{
try
{
using (var client = new WebClient())
{
client.Headers.Add("User-Agent",
"Mozilla/5.0 (X11; Linux i686; rv:64.0) Gecko/20100101 Firefox/64.0");
client.DownloadFile(url, to);
return true;
}
}
catch (Exception)
{
return false;
}
}
private string Get(string uri)
{
try
{
HttpWebRequest request = (HttpWebRequest) WebRequest.Create(uri);
request.AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate;
request.UserAgent = "Mozilla/5.0 (X11; Linux i686; rv:64.0) Gecko/20100101 Firefox/64.0";
using (HttpWebResponse response = (HttpWebResponse) request.GetResponse())
using (Stream stream = response.GetResponseStream())
using (StreamReader reader = new StreamReader(stream))
{
return reader.ReadToEnd();
}
}
catch (Exception)
{
return "";
}
}
}
}