Sprint 정보를 DB에 저장하는 기능 추가.

This commit is contained in:
2025-12-25 09:42:24 +09:00
committed by seungmuk.oh
parent 64a758a701
commit 1f2c6c6d37
5 changed files with 64 additions and 7 deletions

View File

@@ -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;
}
}

View File

@@ -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; }
}

View File

@@ -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;
}

View File

@@ -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);

View File

@@ -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"