diff --git a/src/JiraTimeBot/App.config b/src/JiraTimeBot/App.config index 4abcc95..c107c34 100644 --- a/src/JiraTimeBot/App.config +++ b/src/JiraTimeBot/App.config @@ -10,12 +10,16 @@ - - + + - - + + + + + + diff --git a/src/JiraTimeBot/Configuration/Settings.cs b/src/JiraTimeBot/Configuration/Settings.cs index e13ca68..24ddbcf 100644 --- a/src/JiraTimeBot/Configuration/Settings.cs +++ b/src/JiraTimeBot/Configuration/Settings.cs @@ -144,5 +144,6 @@ namespace JiraTimeBot.Configuration { Mercurial = 0, JiraLogs = 1, + GitLogs = 2 } } diff --git a/src/JiraTimeBot/DI/ContainerBuilder.cs b/src/JiraTimeBot/DI/ContainerBuilder.cs index 3686d0b..2cca8fe 100644 --- a/src/JiraTimeBot/DI/ContainerBuilder.cs +++ b/src/JiraTimeBot/DI/ContainerBuilder.cs @@ -43,8 +43,9 @@ namespace JiraTimeBot.DI _builder.RegisterType().As().AsSelf(); - _builder.RegisterType().As().AsSelf(); - _builder.RegisterType().As().AsSelf(); + _builder.RegisterType().As().AsSelf(); + _builder.RegisterType().As().AsSelf(); + _builder.RegisterType().As().AsSelf(); _builder.RegisterAggregateService(); _builder.RegisterType().As().AsSelf(); diff --git a/src/JiraTimeBot/JiraIntegration/JiraApi.cs b/src/JiraTimeBot/JiraIntegration/JiraApi.cs index 10d1521..3e83029 100644 --- a/src/JiraTimeBot/JiraIntegration/JiraApi.cs +++ b/src/JiraTimeBot/JiraIntegration/JiraApi.cs @@ -72,7 +72,8 @@ namespace JiraTimeBot.JiraIntegration public List GetWorkloggedIssuesByDate(Settings settings, DateTime? date = null, CancellationToken cancellationToken = default) { date = date.GetValueOrDefault(DateTime.Now.Date); - var jql = "issueFunction in workLogged(\"on %DATE% by '%USER%'\")"; + //var jql = "issueFunction in workLogged(\"on %DATE% by '%USER%'\")"; + var jql = "worklogAuthor = '%USER%' && worklogDate = \"%DATE%\""; return GetIssuesByJQL(jql, settings, date, cancellationToken); } diff --git a/src/JiraTimeBot/JiraIntegration/JiraCommitEmulator.cs b/src/JiraTimeBot/JiraIntegration/JiraCommitEmulator.cs index 068b77c..b692aca 100644 --- a/src/JiraTimeBot/JiraIntegration/JiraCommitEmulator.cs +++ b/src/JiraTimeBot/JiraIntegration/JiraCommitEmulator.cs @@ -10,7 +10,7 @@ using JiraTimeBot.TaskTime.Objects; namespace JiraTimeBot.JiraIntegration { - public class JiraCommitEmulator : IMercurialLog + public class JiraCommitEmulator : IRepositoryLog { private readonly ILog _log; private readonly JiraApi _jiraApi; @@ -21,7 +21,7 @@ namespace JiraTimeBot.JiraIntegration _jiraApi = jiraApi; } - public List GetMercurialLog(Settings settings, + public List GetRepositoryLog(Settings settings, DateTime? date = null, CancellationToken cancellationToken = default(CancellationToken)) { diff --git a/src/JiraTimeBot/JiraTimeBot.csproj b/src/JiraTimeBot/JiraTimeBot.csproj index d4e2687..380ae66 100644 --- a/src/JiraTimeBot/JiraTimeBot.csproj +++ b/src/JiraTimeBot/JiraTimeBot.csproj @@ -1,5 +1,6 @@  + Debug @@ -11,6 +12,8 @@ v4.6.1 512 true + + AnyCPU @@ -36,36 +39,49 @@ app.ico - - ..\packages\Atlassian.SDK.10.4.0\lib\net452\Atlassian.Jira.dll + + ..\packages\Atlassian.SDK.12.1.0\lib\net452\Atlassian.Jira.dll - - ..\packages\Autofac.4.9.1\lib\net45\Autofac.dll + + ..\packages\Autofac.5.1.2\lib\net461\Autofac.dll - - ..\packages\Autofac.Extras.AggregateService.4.1.0\lib\net45\Autofac.Extras.AggregateService.dll + + ..\packages\Autofac.Extras.AggregateService.5.0.0\lib\netstandard2.0\Autofac.Extras.AggregateService.dll - ..\packages\Castle.Core.4.3.1\lib\net45\Castle.Core.dll + ..\packages\Castle.Core.4.4.0\lib\net45\Castle.Core.dll + + + ..\packages\LibGit2Sharp.0.27.0-preview-0034\lib\net46\LibGit2Sharp.dll ..\packages\Mercurial.Net.1.1.1.607\lib\net35-Client\Mercurial.Net.dll - - ..\packages\Newtonsoft.Json.12.0.1\lib\net45\Newtonsoft.Json.dll + + ..\packages\Microsoft.Bcl.AsyncInterfaces.1.1.0\lib\net461\Microsoft.Bcl.AsyncInterfaces.dll - - ..\packages\RestSharp.106.6.9\lib\net452\RestSharp.dll + + ..\packages\Newtonsoft.Json.12.0.3\lib\net45\Newtonsoft.Json.dll + + + ..\packages\RestSharp.106.10.1\lib\net452\RestSharp.dll + + + ..\packages\System.Runtime.CompilerServices.Unsafe.4.7.1\lib\net461\System.Runtime.CompilerServices.Unsafe.dll + + + ..\packages\System.Threading.Tasks.Extensions.4.5.4\lib\net461\System.Threading.Tasks.Extensions.dll + @@ -87,11 +103,12 @@ + - + @@ -161,4 +178,10 @@ + + + This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. + + + \ No newline at end of file diff --git a/src/JiraTimeBot/Job.cs b/src/JiraTimeBot/Job.cs index d5d4605..7731d1d 100644 --- a/src/JiraTimeBot/Job.cs +++ b/src/JiraTimeBot/Job.cs @@ -72,17 +72,22 @@ namespace JiraTimeBot private bool SetTaskTimesForDateImpl(DateTime setForDate, DateTime realDate, Settings settings, ITasksProcessor tasksProcessor, bool dummyMode, CancellationToken cancellationToken) { - IMercurialLog mercurial = _mercurialProviders.MercurialLog; + IRepositoryLog mercurial = _mercurialProviders.MercurialLog; if (settings.WorkType == WorkType.JiraLogs) { _log.Info("Использую Jira как источник информации."); mercurial = _mercurialProviders.JiraCommitEmulator; } + else if (settings.WorkType == WorkType.GitLogs) + { + _log.Info("Использую Git как источник информации."); + mercurial = _mercurialProviders.GitLog; + } List taskTimes; if (!(tasksProcessor is MeetingProcessor)) { - List commits = mercurial.GetMercurialLog(settings, realDate, cancellationToken); + List commits = mercurial.GetRepositoryLog(settings, realDate, cancellationToken); taskTimes = _taskTimeDiscoverer.CalculateTaskTime(commits, settings, cancellationToken); } else diff --git a/src/JiraTimeBot/Mercurial/GitLog.cs b/src/JiraTimeBot/Mercurial/GitLog.cs new file mode 100644 index 0000000..08b320e --- /dev/null +++ b/src/JiraTimeBot/Mercurial/GitLog.cs @@ -0,0 +1,210 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading; +using JiraTimeBot.Configuration; +using JiraTimeBot.Mercurial.Modifiers; +using JiraTimeBot.TaskTime.Objects; +using LibGit2Sharp; +using LibGit2Sharp.Handlers; + +namespace JiraTimeBot.Mercurial +{ + public class GitLog : IRepositoryLog + { + private readonly ILog _log; + private readonly ICommitSkipper _commitSkipper; + private readonly ITechnicalInfoSkipper _technicalInfoSkipper; + + public GitLog(ILog log, ICommitSkipper commitSkipper, ITechnicalInfoSkipper technicalInfoSkipper) + { + _log = log; + _commitSkipper = commitSkipper; + _technicalInfoSkipper = technicalInfoSkipper; + } + + public List GetRepositoryLog(Settings settings, DateTime? date = null, CancellationToken cancellationToken = default) + { + if (string.IsNullOrEmpty(settings.RepositoryPath) || !Directory.Exists(settings.RepositoryPath)) + { + _log.Error("Папка с репо не сушествует."); + return new List(); + } + + date = date.GetValueOrDefault(DateTime.Now.Date); + + var workTasks = new List(); + foreach (var repoDirectory in Directory.GetDirectories(settings.RepositoryPath)) + { + if (cancellationToken.IsCancellationRequested) + { + return new List(); + } + + //var project = new DirectoryInfo(repoDirectory).Name; + if (!Directory.Exists(Path.Combine(repoDirectory, ".git"))) + { + continue; + } + + var directoryInfo = new DirectoryInfo(repoDirectory); + + + var repo = new LibGit2Sharp.Repository(repoDirectory); + + if (settings.PullBeforeProcess) + { + try + { + // Credential information to fetch + LibGit2Sharp.PullOptions options = new LibGit2Sharp.PullOptions(); + options.FetchOptions = new FetchOptions(); + + // User information to create a merge commit + var signature = new LibGit2Sharp.Signature(new Identity("MERGE_USER_NAME", "MERGE_USER_EMAIL"), DateTimeOffset.Now); + + // Pull + Commands.Pull(repo, signature, options); + } + catch (Exception ex) + { + _log?.Trace($" - Не получается сделать pull для репозитория: {directoryInfo.Name} - {ex.Message}"); + } + } + var filter = new CommitFilter { SortBy = CommitSortStrategies.Time }; + + foreach (Commit commit in repo.Commits.QueryBy(filter).Take(200)) + { + if (cancellationToken.IsCancellationRequested) + { + return new List(); + } + if (commit.Author.When.DateTime.Date != date || commit.Author.Email != settings.MercurialAuthorEmail) + { + continue; + } + + var branch = ListBranchesContaininingCommit(repo, commit.Sha).Select(f => f.FriendlyName) + .Where(f => f.Contains("-") && !f.Contains("/")).Distinct().FirstOrDefault(); + if (branch == null) + { + continue; + } + + var commitMessage = commit.MessageShort; + if (_commitSkipper.IsNeedToSkip(branch, commitMessage)) + { + continue; + } + commitMessage = _technicalInfoSkipper.StripTechnicalInfo(commitMessage); + + var task = new TaskTimeItem(branch, + commitMessage, + directoryInfo.Name, + commit.Committer.When.DateTime, + TimeSpan.Zero, + 1, + 1, //changeset.PathActions.Count, + "", + GetCommitType(branch)); + workTasks.Add(task); + + _log?.Trace($" - Найден commit: {commit.Committer.When.DateTime} - {branch} - {commit.Author.Email} - {commitMessage}"); + } + + //foreach (var changeset in log) + //{ + + // var commitMessage = FixEncoding(changeset.CommitMessage); + // if (_commitSkipper.IsNeedToSkip(changeset.Branch, commitMessage)) + // { + // continue; + // } + // commitMessage = _technicalInfoSkipper.StripTechnicalInfo(commitMessage); + + // var task = new TaskTimeItem(changeset.Branch, + // commitMessage, + // directoryInfo.Name, + // changeset.Timestamp, + // TimeSpan.Zero, + // 1, + // changeset.PathActions.Count, + // "", + // GetCommitType(changeset.Branch)); + + // if (task.Type == CommitType.Release && task.Description.StartsWith("Merge with", StringComparison.CurrentCultureIgnoreCase)) + // { + // var description = task.Description; + // if (description.Contains("\n")) + // { + // description = description.Split('\n')[0]; + // } + // var branch = description.Replace("Merge with", "").Replace(" ", ""); + // var release = task.Branch.Replace("release", ""); + + // task.Branch = branch; + // task.Description = $"Подготовка и публикация версии {task.Project} {release}."; + // task.ReleaseVersion = release; + // } + // workTasks.Add(task); + // _log?.Trace($" - Найден changeset: {changeset.Timestamp} - {changeset.Branch} - {changeset.AuthorEmailAddress} - {commitMessage}"); + //} + } + if (!workTasks.Any()) + { + return new List(); + } + + return workTasks; + } + + private CommitType GetCommitType(string branch) + { + return branch.StartsWith("release") ? CommitType.Release : CommitType.Task; + } + + 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 IEnumerable ListBranchesContaininingCommit(Repository repo, string commitSha) + { + bool directBranchHasBeenFound = false; + foreach (var branch in repo.Branches) + { + if (branch.Tip.Sha != commitSha) + { + continue; + } + + directBranchHasBeenFound = true; + yield return branch; + } + + if (directBranchHasBeenFound) + { + yield break; + } + + foreach (var branch in repo.Branches) + { + var commits = repo.Commits.QueryBy(new CommitFilter { IncludeReachableFrom = branch }).Where(c => c.Sha == commitSha); + + if (!commits.Any()) + { + continue; + } + + yield return branch; + } + } + } +} \ No newline at end of file diff --git a/src/JiraTimeBot/Mercurial/IAllMercurialProviders.cs b/src/JiraTimeBot/Mercurial/IAllMercurialProviders.cs index d87cc38..d0bc0e8 100644 --- a/src/JiraTimeBot/Mercurial/IAllMercurialProviders.cs +++ b/src/JiraTimeBot/Mercurial/IAllMercurialProviders.cs @@ -5,6 +5,7 @@ namespace JiraTimeBot.Mercurial public interface IAllMercurialProviders { MercurialLog MercurialLog { get; } + GitLog GitLog { get; } JiraCommitEmulator JiraCommitEmulator { get; } IJiraHistory JiraHistory { get; } } diff --git a/src/JiraTimeBot/Mercurial/IMercurialLog.cs b/src/JiraTimeBot/Mercurial/IRepositoryLog.cs similarity index 50% rename from src/JiraTimeBot/Mercurial/IMercurialLog.cs rename to src/JiraTimeBot/Mercurial/IRepositoryLog.cs index 1459319..e2b21ad 100644 --- a/src/JiraTimeBot/Mercurial/IMercurialLog.cs +++ b/src/JiraTimeBot/Mercurial/IRepositoryLog.cs @@ -6,8 +6,8 @@ using JiraTimeBot.TaskTime.Objects; namespace JiraTimeBot.Mercurial { - public interface IMercurialLog + public interface IRepositoryLog { - List GetMercurialLog(Settings settings, DateTime? date = null, CancellationToken cancellationToken = default(CancellationToken)); + List GetRepositoryLog(Settings settings, DateTime? date = null, CancellationToken cancellationToken = default(CancellationToken)); } } \ No newline at end of file diff --git a/src/JiraTimeBot/Mercurial/MercurialLog.cs b/src/JiraTimeBot/Mercurial/MercurialLog.cs index 390d6ad..ad61f75 100644 --- a/src/JiraTimeBot/Mercurial/MercurialLog.cs +++ b/src/JiraTimeBot/Mercurial/MercurialLog.cs @@ -11,7 +11,7 @@ using Mercurial; namespace JiraTimeBot.Mercurial { - public class MercurialLog: IMercurialLog + public class MercurialLog: IRepositoryLog { private readonly ILog _log; private readonly ICommitSkipper _commitSkipper; @@ -24,7 +24,7 @@ namespace JiraTimeBot.Mercurial _technicalInfoSkipper = technicalInfoSkipper; } - public List GetMercurialLog(Settings settings, DateTime? date = null, CancellationToken cancellationToken = default) + public List GetRepositoryLog(Settings settings, DateTime? date = null, CancellationToken cancellationToken = default) { if (string.IsNullOrEmpty(settings.RepositoryPath) || !Directory.Exists(settings.RepositoryPath)) { diff --git a/src/JiraTimeBot/Mercurial/Modifiers/CommitSkipper.cs b/src/JiraTimeBot/Mercurial/Modifiers/CommitSkipper.cs index 53c5d2d..132a7b9 100644 --- a/src/JiraTimeBot/Mercurial/Modifiers/CommitSkipper.cs +++ b/src/JiraTimeBot/Mercurial/Modifiers/CommitSkipper.cs @@ -10,6 +10,7 @@ namespace JiraTimeBot.Mercurial.Modifiers { return false; } + if (!branch.Contains("-")) { return true; @@ -17,7 +18,8 @@ namespace JiraTimeBot.Mercurial.Modifiers //Пропускаем Close и Merge коммиты if (commitMessage.StartsWith($"Close {branch}", StringComparison.InvariantCultureIgnoreCase) || - commitMessage.StartsWith($"Merge with", StringComparison.InvariantCultureIgnoreCase)) + commitMessage.StartsWith($"Merge with", StringComparison.InvariantCultureIgnoreCase) || + commitMessage.StartsWith($"Merge branch", StringComparison.InvariantCultureIgnoreCase)) { return true; } diff --git a/src/JiraTimeBot/UI/frmSettings.Designer.cs b/src/JiraTimeBot/UI/frmSettings.Designer.cs index 71f88e8..30e83dc 100644 --- a/src/JiraTimeBot/UI/frmSettings.Designer.cs +++ b/src/JiraTimeBot/UI/frmSettings.Designer.cs @@ -183,7 +183,8 @@ this.cboWorkType.FormattingEnabled = true; this.cboWorkType.Items.AddRange(new object[] { "Mercurial", - "Jira"}); + "Jira", + "Git"}); this.cboWorkType.Location = new System.Drawing.Point(133, 18); this.cboWorkType.Name = "cboWorkType"; this.cboWorkType.Size = new System.Drawing.Size(99, 21); diff --git a/src/JiraTimeBot/UI/frmSettings.cs b/src/JiraTimeBot/UI/frmSettings.cs index 23987b1..601361e 100644 --- a/src/JiraTimeBot/UI/frmSettings.cs +++ b/src/JiraTimeBot/UI/frmSettings.cs @@ -102,7 +102,7 @@ namespace JiraTimeBot.UI private void cboWorkType_SelectedIndexChanged(object sender, EventArgs e) { txtJQL.Enabled = (cboWorkType.SelectedIndex == 1); - txtRepoPath.Enabled = (cboWorkType.SelectedIndex == 0); + txtRepoPath.Enabled = (cboWorkType.SelectedIndex == 0 || cboWorkType.SelectedIndex == 2); } } } diff --git a/src/JiraTimeBot/packages.config b/src/JiraTimeBot/packages.config index 2e5c5e6..0b3bef3 100644 --- a/src/JiraTimeBot/packages.config +++ b/src/JiraTimeBot/packages.config @@ -1,10 +1,15 @@  - - - - + + + + + + - - + + + + + \ No newline at end of file