Skip to content

Commit cf581ed

Browse files
authored
Truncate titles (#371)
* Fixes #370 * Rename helper function
1 parent 3d3dfc5 commit cf581ed

File tree

3 files changed

+50
-3
lines changed

3 files changed

+50
-3
lines changed

actions/sequester/Quest2GitHub.Tests/GetIterationTests.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,6 @@ public static void ValidIterationReturnsCorrectIteration()
5757
var actual = IssueExtensions.ProjectIteration("Feb", 2024, _allIterations);
5858
Assert.Equal("""Content\Germanium\FY24Q3\02 Feb""", actual?.Path);
5959
}
60-
6160
}
6261

6362

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
using Quest2GitHub.Models;
2+
3+
namespace Quest2GitHub.Tests;
4+
5+
public class QuestWorkItemTests
6+
{
7+
[Theory]
8+
[InlineData("short title")]
9+
[InlineData("A really long title, in fact, it's so long that we know it will exceed the max length of 255 characters imposed by the Azure DevOps API, thus proving our point, and being truncated in the object's .ctor. Isn't programming fun?! Wow, this title is really long...I hope we're done typing soon.")]
10+
public void QuestItemConstructorEnsuresTitleIsTruncated(string title)
11+
{
12+
var sut = new QuestWorkItem
13+
{
14+
Id = 777,
15+
ParentWorkItemId = 100,
16+
ParentRelationIndex = 1,
17+
Title = title, // Truncated on init
18+
State = "Wisconsin 🧀",
19+
Description = "Test description",
20+
AreaPath = "Test/Area",
21+
IterationPath = "Test/Path",
22+
AssignedToId = Guid.NewGuid(),
23+
StoryPoints = 1,
24+
Tags = []
25+
};
26+
27+
Assert.True(sut.Title.Length < 256);
28+
}
29+
}

actions/sequester/Quest2GitHub/Models/QuestWorkItem.cs

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ public class QuestWorkItem
1010
// fails, stop sending invalid requests.
1111
private static bool? s_linkedGitHubRepo;
1212

13+
private string _title = "";
14+
1315
/// <summary>
1416
/// The Work item ID
1517
/// </summary>
@@ -21,7 +23,11 @@ public class QuestWorkItem
2123
/// <remarks>
2224
/// This is retrieved as /fields/System.Title
2325
/// </remarks>
24-
public required string Title { get; init; }
26+
public required string Title
27+
{
28+
get => _title;
29+
init => _title = TruncateTitleWhenLongerThanMax(value);
30+
}
2531

2632
// /fields/System.Description
2733
public required string Description { get; init; }
@@ -139,7 +145,7 @@ public static async Task<QuestWorkItem> CreateWorkItemAsync(QuestIssueOrPullRequ
139145
Operation = Op.Add,
140146
Path = "/fields/System.Title",
141147
From = default,
142-
Value = issue.Title
148+
Value = TruncateTitleWhenLongerThanMax(issue.Title)
143149
},
144150
new() {
145151
Operation = Op.Add,
@@ -278,6 +284,19 @@ public static async Task<QuestWorkItem> CreateWorkItemAsync(QuestIssueOrPullRequ
278284
return newItem;
279285
}
280286

287+
private static string TruncateTitleWhenLongerThanMax(string title)
288+
{
289+
// https://learn.microsoft.com/azure/devops/boards/work-items/about-work-items?view=azure-devops&tabs=agile-process#common-work-tracking-fields
290+
const int MaxTitleLength = 255;
291+
292+
if (title is { Length: > MaxTitleLength })
293+
{
294+
return title[0..MaxTitleLength];
295+
}
296+
297+
return title;
298+
}
299+
281300
public static string BuildDescriptionFromIssue(QuestIssueOrPullRequest issue, string? requestLabelNodeId)
282301
{
283302
var body = new StringBuilder($"<p>Imported from: {issue.LinkText}</p>");

0 commit comments

Comments
 (0)