Skip to content

Commit a7165a3

Browse files
authored
Merge pull request #7 from gasparnagy/upgrade-gitext7
Upgrade to GitExtensions 7
2 parents 9acd7b3 + e9e1932 commit a7165a3

4 files changed

Lines changed: 83 additions & 40 deletions

File tree

‎Gitextensions.AzureDevOpsCommitMessageTests/Gitextensions.AzureDevOpsCommitMessageTests.csproj‎

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
<Project Sdk="Microsoft.NET.Sdk">
22

33
<PropertyGroup>
4-
<TargetFramework>net9.0-windows</TargetFramework>
4+
<TargetFramework>net10.0-windows</TargetFramework>
55
<ImplicitUsings>enable</ImplicitUsings>
66
<Nullable>enable</Nullable>
7-
7+
<GitExtensionsReferenceVersion>v7.2.1</GitExtensionsReferenceVersion>
88
<IsPackable>false</IsPackable>
99
</PropertyGroup>
1010

@@ -19,6 +19,7 @@
1919
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
2020
<PrivateAssets>all</PrivateAssets>
2121
</PackageReference>
22+
<PackageReference Include="GitExtensions.Extensibility" Version="7.0.0.135" />
2223
</ItemGroup>
2324

2425
<ItemGroup>

‎src/GitExtensions.AzureDevOpsCommitMessage/GitExtensions.AzureDevOpsCommitMessage.csproj‎

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,22 @@
11
<Project Sdk="Microsoft.NET.Sdk">
22

33
<PropertyGroup>
4-
<TargetFramework>net9.0-windows</TargetFramework>
4+
<TargetFramework>net10.0-windows</TargetFramework>
55
<!--Value useless because will be overwritten by release GitHub action. Keep '0.0.0' so that the release process work well!-->
66
<VersionPrefix>0.0.0</VersionPrefix>
77
<PublishRepositoryUrl>true</PublishRepositoryUrl>
88
<UseWindowsForms>true</UseWindowsForms>
99
<!-- Source: 'GitHub' or 'AppVeyor' -->
1010
<!--<GitExtensionsReferenceSource Condition="$(GitExtensionsReferenceSource) == ''">AppVeyor</GitExtensionsReferenceSource>-->
1111
<!-- Version: 'latest' or 'v3.1' (= tag from GitHub releases) or 'v3.1.0.5877' (= build number from AppVeyor)-->
12-
<GitExtensionsReferenceVersion>v6.0.1</GitExtensionsReferenceVersion>
12+
<GitExtensionsReferenceVersion>v7.2.1</GitExtensionsReferenceVersion>
1313
<!--<GitExtensionsReferenceVersion>latest</GitExtensionsReferenceVersion>-->
1414
<!-- Binaries path for local builds (no download if folder exists) -->
1515
<!--<GitExtensionsPath Condition="$(GitExtensionsPath) == ''">$([System.IO.Path]::Combine('$(ProjectDir)', '$(GitExtensionsDownloadPath)'))</GitExtensionsPath>-->
1616
</PropertyGroup>
1717

1818
<ItemGroup>
19-
<None Include="Resources\IconAzureDevOps.png" >
19+
<None Include="Resources\IconAzureDevOps.png">
2020
<Pack>True</Pack>
2121
<PackagePath>\</PackagePath>
2222
</None>
@@ -36,10 +36,9 @@
3636

3737
<ItemGroup>
3838
<PackageReference Include="System.ComponentModel.Composition" Version="6.0.0" />
39-
<PackageReference Include="GitExtensions.Extensibility" Version="0.4.0.*" />
39+
<PackageReference Include="GitExtensions.Extensibility" Version="7.0.0.135" />
4040
<PackageReference Include="Microsoft.VisualStudio.Threading" Version="17.13.61" />
41-
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
42-
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="8.0.0" PrivateAssets="All"/>
41+
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="10.0.401" PrivateAssets="All" />
4342
</ItemGroup>
4443

4544
<!-- Reference to GitExtensions dlls. -->

‎src/GitExtensions.AzureDevOpsCommitMessage/GitExtensions.AzureDevOpsCommitMessage.nuspec‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
<readme>README.md</readme>
1111
<tags>$tags$</tags>
1212
<dependencies>
13-
<dependency id="GitExtensions.Extensibility" version="[0.1.0, 1.0.0)" />
13+
<dependency id="GitExtensions.Extensibility" version="[7.0, 8.0)" />
1414
</dependencies>
1515
</metadata>
1616
<files>

‎src/GitExtensions.AzureDevOpsCommitMessage/Plugin.cs‎

Lines changed: 74 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,8 @@
1717
using GitUIPluginInterfaces;
1818
using GitExtensions.Extensibility.Plugins;
1919
using GitExtensions.Extensibility.Settings;
20-
using Newtonsoft.Json.Linq;
20+
using System.Text.Json;
21+
using System.Text.Json.Nodes;
2122
using ResourceManager;
2223
using GitExtensions.Extensibility.Git;
2324
using GitExtensions.Extensibility.Settings.UserControls;
@@ -85,8 +86,8 @@ public class Plugin : GitPluginBase, IGitPluginForRepository, IGitPluginForCommi
8586
private readonly BoolSetting _enabledSettings = new BoolSetting("Enabled", false);
8687
private readonly StringSetting _projectUrlSettings = new StringSetting("AzureDevOps project URL", @"https://dev.azure.com/{organization}/{project}");
8788
private readonly CredentialsSetting _credentialsSettings;
88-
private readonly StringSetting _wiqlQuerySettings = new StringSetting("WIQL Query", AzureDevOpsQueryLabel.Text, "Select [System.Id] From WorkItems Where ( [System.WorkItemType] = 'Product Backlog Item' OR [System.WorkItemType] = 'Bug' ) AND [State] <> 'Closed' AND [State] <> 'Removed' AND [System.AssignedTo] = @Me AND [System.IterationPath] = @CurrentIteration order by [Microsoft.VSTS.Common.Priority] asc, [System.CreatedDate] desc", true);
89-
private readonly StringSetting _stringTemplateSetting = new StringSetting("AzureDevOps Message Template", MessageTemplateLabel.Text, DefaultFormat, true);
89+
private readonly StringSetting _wiqlQuerySettings = new StringSetting("WIQL Query", AzureDevOpsQueryLabel.Text, "Select [System.Id] From WorkItems Where ( [System.WorkItemType] = 'Product Backlog Item' OR [System.WorkItemType] = 'Bug' ) AND [State] <> 'Closed' AND [State] <> 'Removed' AND [System.AssignedTo] = @Me AND [System.IterationPath] = @CurrentIteration order by [Microsoft.VSTS.Common.Priority] asc, [System.CreatedDate] desc");
90+
private readonly StringSetting _stringTemplateSetting = new StringSetting("AzureDevOps Message Template", MessageTemplateLabel.Text, DefaultFormat);
9091
private readonly PseudoSetting _allFieldsAndValuesSetting = new PseudoSetting(HowToRetrieveWorkItemsFieldsValues.Text, WorkItemsFieldsValuesCaption.Text, DpiUtil.Scale(200), t => t.ScrollBars = ScrollBars.Both);
9192

9293
private IGitModule _gitModule;
@@ -397,16 +398,23 @@ private async Task<IList<CommitTemplate>> GetCommitTemplatesAsync(HttpClient cli
397398
return new[] { new CommitTemplate($"{Description} {Error}", ex.ToString()) };
398399
}
399400
}
400-
401401
private IEnumerable<(string id, string url)> GetWorkitems(string jsonWorkitems)
402402
{
403-
var workItems = JObject.Parse(jsonWorkitems)["workItems"];
404-
if (workItems == null)
403+
using var doc = JsonDocument.Parse(jsonWorkitems);
404+
if (!doc.RootElement.TryGetProperty("workItems", out var workItemsElement) || workItemsElement.ValueKind != JsonValueKind.Array)
405405
{
406406
return Enumerable.Empty<(string id, string url)>();
407407
}
408408

409-
return workItems.Select(w => (w["id"].ToString(), w["url"].ToString()));
409+
var result = new List<(string id, string url)>();
410+
foreach (var item in workItemsElement.EnumerateArray())
411+
{
412+
var id = item.TryGetProperty("id", out var idEl) ? (idEl.ValueKind == JsonValueKind.String ? idEl.GetString() : idEl.GetRawText()) : string.Empty;
413+
var url = item.TryGetProperty("url", out var urlEl) ? urlEl.GetString() ?? urlEl.GetRawText() : string.Empty;
414+
result.Add((id ?? string.Empty, url ?? string.Empty));
415+
}
416+
417+
return result;
410418
}
411419

412420
private async Task<CommitTemplate> GetWorkItemAsync(HttpClient client, string id, string url, string template)
@@ -433,7 +441,12 @@ private async Task<CommitTemplate> GetWorkItemAsync(HttpClient client, string id
433441

434442
private CommitTemplate GetCommitTemplateFromWorkitemData(string id, string template, string jsonWorkitem)
435443
{
436-
var workItemData = JObject.Parse(jsonWorkitem)["fields"];
444+
using var doc = JsonDocument.Parse(jsonWorkitem);
445+
if (!doc.RootElement.TryGetProperty("fields", out var workItemData))
446+
{
447+
workItemData = default;
448+
}
449+
437450
if (_btnPreview != null)
438451
{
439452
_allFieldsAndValues = ExtractAllFields(workItemData);
@@ -459,81 +472,96 @@ private string Elide(string value)
459472
return value.Length > 80 ? value.Substring(0, 80) + "[...]" : value;
460473
}
461474

462-
private string ExtractAllFields(JToken fields)
475+
private string ExtractAllFields(JsonElement fields)
463476
{
464-
List<string> allFields = new List<string>();
465-
foreach (var pair in (JObject)fields)
477+
var allFields = new List<string>();
478+
if (fields.ValueKind != JsonValueKind.Object)
466479
{
467-
if (!pair.Value.HasValues)
480+
return string.Empty;
481+
}
482+
483+
foreach (var prop in fields.EnumerateObject())
484+
{
485+
if (prop.Value.ValueKind != JsonValueKind.Object)
468486
{
469-
allFields.Add($"{{{pair.Key}}}: {Elide(pair.Value.ToString())}");
487+
allFields.Add($"{{{prop.Name}}}: {Elide(ElementToString(prop.Value))}");
470488
}
471489
else
472490
{
473-
allFields.AddRange(FlattenFieldsHierarchy(pair.Key, pair.Value));
491+
allFields.AddRange(FlattenFieldsHierarchy(prop.Name, prop.Value));
474492
}
475493
}
476494

477495
return string.Join(Environment.NewLine, allFields.OrderBy(s => s));
478496
}
479497

480-
private IEnumerable<string> FlattenFieldsHierarchy(string key, JToken fields)
498+
private IEnumerable<string> FlattenFieldsHierarchy(string key, JsonElement fields)
481499
{
482-
foreach (var pair in (JObject)fields)
500+
if (fields.ValueKind != JsonValueKind.Object)
501+
{
502+
yield break;
503+
}
504+
505+
foreach (var prop in fields.EnumerateObject())
483506
{
484-
if (!pair.Value.HasValues)
507+
if (prop.Value.ValueKind != JsonValueKind.Object)
485508
{
486-
yield return $"{{{key}|{pair.Key}}}: {Elide(pair.Value.ToString())}";
509+
yield return $"{{{key}|{prop.Name}}}: {Elide(ElementToString(prop.Value))}";
487510
}
488511
else
489512
{
490-
foreach (string value in FlattenFieldsHierarchy(key + "|" + pair.Key, pair.Value))
513+
foreach (var value in FlattenFieldsHierarchy(key + "|" + prop.Name, prop.Value))
491514
{
492515
yield return value;
493516
}
494517
}
495518
}
496519
}
497520

498-
private string PopulateTemplate(string titleTemplate, string id, JToken workitem)
521+
private string PopulateTemplate(string titleTemplate, string id, JsonElement workitem)
499522
{
500523
return ExtractWorkItemField(titleTemplate.Replace("{id}", id), workitem);
501524
}
502525

503-
private static bool TryGetWorkItemValue(JToken workitem, string workItemField, out string value)
526+
private static bool TryGetWorkItemValue(JsonElement workitem, string workItemField, out string value)
504527
{
528+
value = null;
505529
if (workItemField.Contains('|'))
506530
{
507531
var fields = workItemField.Split('|');
532+
var current = workitem;
508533
foreach (var field in fields)
509534
{
510-
var foundValue = workitem[field];
511-
if (foundValue == null)
535+
if (current.ValueKind != JsonValueKind.Object || !current.TryGetProperty(field, out var foundValue))
512536
{
513537
value = null;
514538
return false;
515539
}
516540

517-
workitem = foundValue;
541+
current = foundValue;
518542
}
519543

520-
value = workitem.ToString();
544+
value = ElementToString(current);
521545
return true;
522546
}
523547
else
524548
{
525-
var foundValue = workitem[workItemField];
526-
value = foundValue?.ToString();
527-
if (workItemField == "System.Description")
549+
if (workitem.ValueKind == JsonValueKind.Object && workitem.TryGetProperty(workItemField, out var foundValue))
528550
{
529-
value = ExtractTextFromHtml(value);
551+
value = ElementToString(foundValue);
552+
if (workItemField == "System.Description")
553+
{
554+
value = ExtractTextFromHtml(value);
555+
}
556+
557+
return value != null;
530558
}
531559

532-
return value != null;
560+
return false;
533561
}
534562
}
535563

536-
public static string ExtractWorkItemField(string pattern, JToken workitem)
564+
public static string ExtractWorkItemField(string pattern, JsonElement workitem)
537565
{
538566
if (string.IsNullOrWhiteSpace(pattern))
539567
{
@@ -557,6 +585,21 @@ public static string ExtractWorkItemField(string pattern, JToken workitem)
557585
return pattern;
558586
}
559587

588+
private static string ElementToString(JsonElement el)
589+
{
590+
if (el.ValueKind == JsonValueKind.String)
591+
{
592+
return el.GetString();
593+
}
594+
595+
if (el.ValueKind == JsonValueKind.Null || el.ValueKind == JsonValueKind.Undefined)
596+
{
597+
return null;
598+
}
599+
600+
return el.GetRawText();
601+
}
602+
560603
public static string ExtractTextFromHtml(string html)
561604
{
562605
if (string.IsNullOrWhiteSpace(html))

0 commit comments

Comments
 (0)