diff --git a/VTSFetcher/Helpers/SprintHelper.cs b/VTSFetcher/Helpers/SprintHelper.cs new file mode 100644 index 0000000..2161975 --- /dev/null +++ b/VTSFetcher/Helpers/SprintHelper.cs @@ -0,0 +1,53 @@ +using System.Text.RegularExpressions; + +namespace VTSFetcher.Helpers; + +public static class SprintHelper +{ + public static string ExtractActiveSprintName(string[] sprintData) + { + if (sprintData == null || sprintData.Length == 0) + return string.Empty; + + // 먼저 ACTIVE 스프린트 찾기 + foreach (var sprint in sprintData) + { + if (sprint.Contains("state=ACTIVE")) + { + var match = Regex.Match(sprint, @"name=([^,]+)"); + if (match.Success) + { + return match.Groups[1].Value; + } + } + } + + // Fallback - ACTIVE 스프린트가 없으면 가장 최근 CLOSED 스프린트 찾기 + DateTime latestEndDate = DateTime.MinValue; + string latestSprintName = string.Empty; + + foreach (var sprint in sprintData) + { + if (sprint.Contains("state=CLOSED")) + { + var endDateMatch = Regex.Match(sprint, @"endDate=([^,\]]+)"); + var nameMatch = Regex.Match(sprint, @"name=([^,]+)"); + + if (endDateMatch.Success && nameMatch.Success) + { + // endDate 파싱 (예: 2025-12-19T09:18:00.000+09:00) + if (DateTime.TryParse(endDateMatch.Groups[1].Value, out DateTime endDate)) + { + if (endDate > latestEndDate) + { + latestEndDate = endDate; + latestSprintName = nameMatch.Groups[1].Value; + } + } + } + } + } + + return latestSprintName; + } +} diff --git a/VTSFetcher/Models/VtsResponse.cs b/VTSFetcher/Models/VtsResponse.cs index bbb12f4..32ffdac 100644 --- a/VTSFetcher/Models/VtsResponse.cs +++ b/VTSFetcher/Models/VtsResponse.cs @@ -16,6 +16,7 @@ public class Issue public string self { get; set; } public string key { get; set; } // RYXMARUV1-NNNN public Fields fields { get; set; } + public string Sprint { get; set; } } public class Fields @@ -38,6 +39,7 @@ public class Fields public DateTime? duedate { get; set; } public Issue parent { get; set; } public string customfield_10808 { get; set; } // Epic key + public string[] customfield_10806 { get; set; } // Splint } public class Assignee @@ -101,4 +103,3 @@ public class Issuetype public bool subtask { get; set; } public int avatarId { get; set; } } - diff --git a/VTSFetcher/Repositories/Entities/VtsIssue.cs b/VTSFetcher/Repositories/Entities/VtsIssue.cs index 11cc44c..e660815 100644 --- a/VTSFetcher/Repositories/Entities/VtsIssue.cs +++ b/VTSFetcher/Repositories/Entities/VtsIssue.cs @@ -17,4 +17,5 @@ public class VtsIssue public DateTimeOffset Published { get; set; } public string? ObjectId { get; set; } public int NeedNotify { get; set; } + public string? Sprint { get; set; } = string.Empty; } \ No newline at end of file diff --git a/VTSFetcher/Services/VtsService.cs b/VTSFetcher/Services/VtsService.cs index 05d07cd..b4ac19b 100644 --- a/VTSFetcher/Services/VtsService.cs +++ b/VTSFetcher/Services/VtsService.cs @@ -27,8 +27,8 @@ public class VtsService var request = new HttpRequestMessage(HttpMethod.Get, uri); request.Headers.Add("Accept", "application/json"); request.Headers.Add("Authorization", $"Bearer {_appSettings.VTS.AccessToken}"); - Log.Debug("Fetch VTS issues ready. Fetch the issues updated after {last_fetch_time} in Project {target_project}.", - lastFetchTime.ToString("yyyy-MM-dd HH:mm"), targetProject); + Log.Debug("Fetch VTS issues ready. Fetch the issues updated after {last_fetch_time} in Project {target_project}. ({fetch_url})", + lastFetchTime.ToString("yyyy-MM-dd HH:mm"), targetProject, uri); using var client = new HttpClient(); var response = await client.SendAsync(request, ct).ConfigureAwait(false); diff --git a/VTSFetcher/ViewModels/MainViewModel.cs b/VTSFetcher/ViewModels/MainViewModel.cs index 20eba8e..07fe20b 100644 --- a/VTSFetcher/ViewModels/MainViewModel.cs +++ b/VTSFetcher/ViewModels/MainViewModel.cs @@ -10,6 +10,7 @@ using System.Runtime.Intrinsics.X86; using System.Windows.Input; using System.Windows.Threading; using VTSFetcher.Commands; +using VTSFetcher.Helpers; using VTSFetcher.Models; using VTSFetcher.Repositories; using VTSFetcher.Repositories.Entities; @@ -119,10 +120,10 @@ public class MainViewModel : INotifyPropertyChanged _slackTimer.Tick += SlackTick; _slackTimer.Start(); - //_statusTimer = new DispatcherTimer(); - //_statusTimer.Interval = TimeSpan.FromSeconds(30); - //_statusTimer.Tick += StatusTick; - //_statusTimer.Start(); + _statusTimer = new DispatcherTimer(); + _statusTimer.Interval = TimeSpan.FromSeconds(30); + _statusTimer.Tick += StatusTick; + _statusTimer.Start(); FetchNowCommand = new RelayCommand(_ => FetchNow()); SaveStatusCommand = new RelayCommand(_ => { @@ -215,6 +216,7 @@ public class MainViewModel : INotifyPropertyChanged Due = i.fields.duedate ?? new DateTime(1999, 12, 23, 23, 59, 59), Updated = i.fields.UpdatedAt, Parent = i.fields.parent?.key, + Sprint = SprintHelper.ExtractActiveSprintName(i.fields.customfield_10806) })).ToList(); _sw.Stop(); Log.Information("Fetched {issue_count} issues from VTS in {operation_time}ms"