Compare commits

..
2 Commits
18 changed files with 314 additions and 248 deletions
+1 -1
View File
@@ -1 +1 @@
1.0.35
1.0.37
-1
View File
@@ -18,7 +18,6 @@
- Задача "учёта времени" - задача, куда будет списываться по 30 минут в день на "затраты на учет времени". Должна содержать знак '-'.
- Время запуска - время автоматического запуска бота. Если была установлена галочка "тестовый прогон" - она будет снята.
- Добавлять описание (Режим Mercurial) - добавлять ли в описание CommitMessage, если не установлено - добавляются стандартные фразы программистов (типа "написание кода").
- Заменять время за день - если галочка установлена, то время внесенное пользователем за день будет удалено и заменено на добавленное ботом.
# Скачать
Скачать актуальную версию можно тут: https://github.com/monster1025/JiraTimeBot/releases/latest
@@ -23,7 +23,6 @@ namespace JiraTimeBot.Configuration
public WorkType WorkType { get; set; }
public string JiraQuery { get; set; }
public string TimeControlTask { get; set; }
public bool RemoveWorklogsAddedByUser { get; set; }
public static Settings LoadAndCheck(Action settingsSource, Action<string> errorMessageReporter)
{
+3
View File
@@ -11,6 +11,7 @@ using System;
using System.Windows.Forms;
using JiraTimeBot.UI;
using JiraTimeBot.UI.Startup;
using JiraTimeBot.Update;
namespace JiraTimeBot.DI
{
@@ -38,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();
+8 -15
View File
@@ -76,13 +76,14 @@ namespace JiraTimeBot.JiraIntegration
{
if (!taskTimeItems.Any(f => f.Branch.Equals(issue.Key.Value, StringComparison.InvariantCulture)))
{
_log.Trace($"Удаляю добавленный руками WorkLog для задачи {issue.Key.Value}.");
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);
@@ -94,19 +95,11 @@ namespace JiraTimeBot.JiraIntegration
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;
//Удаляем добавленные вручную пользователем данные.
if (settings.AddCommentsToWorklog)
{
RemoveWorklogsAddedByUser(taskTimeItems, settings, date, dummy, cancellationToken);
}
RemoveWorklogsAddedByUser(taskTimeItems, settings, date, dummy, cancellationToken);
foreach (TaskTimeItem taskTimeItem in taskTimeItems)
{
@@ -126,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)
@@ -147,7 +140,7 @@ namespace JiraTimeBot.JiraIntegration
}
if (!dummy)
{
issue.DeleteWorklogAsync(workLog);
issue.DeleteWorklogAsync(workLog, token: cancellationToken);
}
hasTodayWorklog = false;
}
@@ -167,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}");
}
+2 -1
View File
@@ -122,7 +122,8 @@
<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>
+42 -27
View File
@@ -31,7 +31,7 @@ namespace JiraTimeBot
return Task.Run(() => DoTheJobImpl(settings, tasksProcessor, dummyMode, cancellationToken), cancellationToken);
}
private void DoTheJobImpl(Settings settings, ITasksProcessor tasksProcessor, bool dummyMode, CancellationToken cancellationToken)
{
int daysDiff = 0;
@@ -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, cancellationToken);
_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;
}
}
}
+31 -31
View File
@@ -1,31 +1,31 @@
using System.Reflection;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("JiraTimeBot")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("JiraTimeBot")]
[assembly: AssemblyCopyright("Copyright © 2019")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("f3b89316-c38c-4ce6-9d88-0b1373cfba1a")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// 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.35")]
[assembly: AssemblyFileVersion("1.0.35")]
[assembly: AssemblyInformationalVersion("1.0.35")]
using System.Reflection;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("JiraTimeBot")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("JiraTimeBot")]
[assembly: AssemblyCopyright("Copyright © 2019")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("f3b89316-c38c-4ce6-9d88-0b1373cfba1a")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// 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.37")]
[assembly: AssemblyFileVersion("1.0.37")]
[assembly: AssemblyInformationalVersion("1.0.37")]
@@ -8,6 +8,6 @@ namespace JiraTimeBot.TasksProcessors
{
interface ITasksProcessor
{
void Process(DateTime date, List<TaskTimeItem> taskTimes, Settings settings, bool dummyMode, CancellationToken cancellationToken = default(CancellationToken));
void Process(DateTime setForDate, DateTime realDate, List<TaskTimeItem> taskTimes, Settings settings, bool dummyMode, CancellationToken cancellationToken = default(CancellationToken));
}
}
@@ -19,9 +19,9 @@ namespace JiraTimeBot.TasksProcessors
_jiraApi = jiraApi;
}
public void Process(DateTime date, List<TaskTimeItem> taskTimes, Settings settings, bool dummyMode, CancellationToken cancellationToken = default(CancellationToken))
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))
{
@@ -18,15 +18,15 @@ namespace JiraTimeBot.TasksProcessors
_jiraApi = jiraApi;
}
public void Process(DateTime date, List<TaskTimeItem> taskTimes, Settings settings, bool dummyMode, CancellationToken cancellationToken = default(CancellationToken))
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, cancellationToken: cancellationToken);
_jiraApi.SetTodayWorklog(taskTimes, settings, date: setForDate, dummy: dummyMode, addCommentsToWorklog: settings.AddCommentsToWorklog, cancellationToken: cancellationToken);
}
}
}
+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;
}
}
+12 -68
View File
@@ -216,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)
@@ -257,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);
}
}
}
+4 -17
View File
@@ -49,7 +49,6 @@
this.label8 = new System.Windows.Forms.Label();
this.txtTimeControlTask = new System.Windows.Forms.TextBox();
this.chkAutostart = new System.Windows.Forms.CheckBox();
this.chkRemoveAddedByUser = new System.Windows.Forms.CheckBox();
this.SuspendLayout();
//
// label5
@@ -154,7 +153,7 @@
// chkAddComments
//
this.chkAddComments.AutoSize = true;
this.chkAddComments.Location = new System.Drawing.Point(56, 277);
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;
@@ -163,7 +162,7 @@
//
// btnSave
//
this.btnSave.Location = new System.Drawing.Point(92, 322);
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;
@@ -228,29 +227,18 @@
// chkAutostart
//
this.chkAutostart.AutoSize = true;
this.chkAutostart.Location = new System.Drawing.Point(56, 254);
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;
//
// chkRemoveAddedByUser
//
this.chkRemoveAddedByUser.AutoSize = true;
this.chkRemoveAddedByUser.Location = new System.Drawing.Point(56, 299);
this.chkRemoveAddedByUser.Name = "chkRemoveAddedByUser";
this.chkRemoveAddedByUser.Size = new System.Drawing.Size(153, 17);
this.chkRemoveAddedByUser.TabIndex = 41;
this.chkRemoveAddedByUser.Text = "Заменять время за день";
this.chkRemoveAddedByUser.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, 357);
this.Controls.Add(this.chkRemoveAddedByUser);
this.ClientSize = new System.Drawing.Size(243, 334);
this.Controls.Add(this.chkAutostart);
this.Controls.Add(this.label8);
this.Controls.Add(this.txtTimeControlTask);
@@ -306,6 +294,5 @@
private System.Windows.Forms.Label label8;
private System.Windows.Forms.TextBox txtTimeControlTask;
private System.Windows.Forms.CheckBox chkAutostart;
private System.Windows.Forms.CheckBox chkRemoveAddedByUser;
}
}
-2
View File
@@ -37,7 +37,6 @@ namespace JiraTimeBot.UI
txtRoundTo.Text = settings.RountToMinutes.ToString();
cboWorkType.SelectedIndex = (int) settings.WorkType;
txtTimeControlTask.Text = settings.TimeControlTask;
chkRemoveAddedByUser.Checked = settings.RemoveWorklogsAddedByUser;
txtJQL.Text = settings.JiraQuery;
txtJQL.Enabled = settings.WorkType == WorkType.JiraLogs;
}
@@ -61,7 +60,6 @@ namespace JiraTimeBot.UI
WorkType = (WorkType) cboWorkType.SelectedIndex,
JiraQuery = txtJQL.Text,
TimeControlTask = txtTimeControlTask.Text,
RemoveWorklogsAddedByUser = chkRemoveAddedByUser.Checked
};
//LockUnlock(false);
+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 "";
}
}
}
}