Skip to content

Commit b6090e8

Browse files
authored
Implement default exclude list for work item type validation (#2971)
This PR solves the second item in [improve work item type validation list](#2951). PR is only a draft for now. What needs to be changed is the place of default excluded WITs. I have it directly in source now, but it is not good. This list should be somewhere in configuration file. But I do not know where to write it, to make this list default in configuration. So I need your help here @MrHinsh. Also check the list itself, of you are happy with these WITs to be excluded by default. I kept in configuration `IncludeWorkItemtypes` list, but both lists can not be set at the same time. I do not want to remove this list, because it means to make some configuration upgrade. But if you think that it will be better, just navigate me how to do it. In longer run, I believe, that only the `ExcludeWorkItemtypes` will be used, mailny because I expect it to be defined by default in configuration, so people will just use this and not include list. ## Other changes I made a small change in `ExecuteMigrationCommand`. The value of `ex.OptionsName` in log was always empty. `OptionsName` is used only, whe we use _named options_ – which we are not. We use just simple options pattern, where the options have default name of empty string.
2 parents 46d3fb8 + eaedf7d commit b6090e8

File tree

9 files changed

+113
-44
lines changed

9 files changed

+113
-44
lines changed

appsettings.json

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -180,7 +180,17 @@
180180
}
181181
},
182182
"TfsWorkItemTypeValidatorTool": {
183-
"Enabled": true
183+
"Enabled": true,
184+
"ExcludeWorkItemtypes": [
185+
"Code Review Request",
186+
"Code Review Response",
187+
"Feedback Request",
188+
"Feedback Response",
189+
"Shared Parameter",
190+
"Shared Steps"
191+
],
192+
"SourceFieldMappings": [],
193+
"FixedTargetFields": []
184194
}
185195
},
186196
"CommonToolSamples": {
@@ -192,14 +202,7 @@
192202
},
193203
"TfsWorkItemTypeValidatorTool": {
194204
"Enabled": true,
195-
"IncludeWorkItemtypes": [
196-
"Bug",
197-
"Task",
198-
"User Story",
199-
"Product Backlog Item",
200-
"Feature",
201-
"Epic",
202-
"Risk"
205+
"ExcludeWorkItemtypes": [
203206
],
204207
"SourceFieldMappings": {
205208
"User Story": {

docs/data/classes/reference.tools.tfsworkitemtypevalidatortool.yaml

Lines changed: 32 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,17 @@ configurationSamples:
1010
"Version": "16.0",
1111
"CommonTools": {
1212
"TfsWorkItemTypeValidatorTool": {
13-
"Enabled": "True"
13+
"Enabled": "True",
14+
"ExcludeWorkItemtypes": [
15+
"Code Review Request",
16+
"Code Review Response",
17+
"Feedback Request",
18+
"Feedback Response",
19+
"Shared Parameter",
20+
"Shared Steps"
21+
],
22+
"FixedTargetFields": null,
23+
"SourceFieldMappings": null
1424
}
1525
}
1626
}
@@ -26,20 +36,12 @@ configurationSamples:
2636
"CommonTools": {
2737
"TfsWorkItemTypeValidatorTool": {
2838
"Enabled": "True",
39+
"ExcludeWorkItemtypes": null,
2940
"FixedTargetFields": {
3041
"User Story": [
3142
"Custom.Prirucka"
3243
]
3344
},
34-
"IncludeWorkItemtypes": [
35-
"Bug",
36-
"Task",
37-
"User Story",
38-
"Product Backlog Item",
39-
"Feature",
40-
"Epic",
41-
"Risk"
42-
],
4345
"SourceFieldMappings": {
4446
"User Story": {
4547
"Microsoft.VSTS.Common.Prirucka": "Custom.Prirucka"
@@ -57,14 +59,14 @@ configurationSamples:
5759
{
5860
"$type": "TfsWorkItemTypeValidatorToolOptions",
5961
"Enabled": true,
60-
"IncludeWorkItemtypes": [
61-
"Bug",
62-
"Task",
63-
"User Story",
64-
"Product Backlog Item",
65-
"Feature",
66-
"Epic",
67-
"Risk"
62+
"IncludeWorkItemtypes": [],
63+
"ExcludeWorkItemtypes": [
64+
"Code Review Request",
65+
"Code Review Response",
66+
"Feedback Request",
67+
"Feedback Response",
68+
"Shared Parameter",
69+
"Shared Steps"
6870
],
6971
"SourceFieldMappings": {
7072
"User Story": {
@@ -90,17 +92,23 @@ options:
9092
defaultValue: true
9193
isRequired: false
9294
dotNetType: System.Boolean, System.Private.CoreLib, Version=8.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e
95+
- parameterName: ExcludeWorkItemtypes
96+
type: List
97+
description: List of work item types which will be excluded from validation.
98+
defaultValue: missing XML code comments
99+
isRequired: false
100+
dotNetType: System.Collections.Generic.List`1[[System.String, System.Private.CoreLib, Version=8.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]], System.Private.CoreLib, Version=8.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e
93101
- parameterName: FixedTargetFields
94102
type: Dictionary
95103
description: >-
96-
List of target fields that are considered as `fixed`.
97-
A field marked as fixed will not stop the migration if differences are found.
98-
Instead of a warning, only an informational message will be logged.
104+
List of target fields that are considered as `fixed`.
105+
A field marked as fixed will not stop the migration if differences are found.
106+
Instead of a warning, only an informational message will be logged.
99107
100-
Use this list when you already know about the differences and have resolved them,
101-
for example by using `FieldMappingTool`.
108+
Use this list when you already know about the differences and have resolved them,
109+
for example by using `FieldMappingTool`.
102110
103-
The key is the target work item type name.
111+
The key is the target work item type name.
104112
You can also use `*` to define fixed fields that apply to all work item types.
105113
defaultValue: null
106114
isRequired: false

docs/static/schema/configuration.schema.json

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2468,8 +2468,17 @@
24682468
"type": "boolean",
24692469
"default": "true"
24702470
},
2471+
"ExcludeWorkItemtypes": {
2472+
"description": "List of work item types which will be excluded from validation.",
2473+
"type": "array",
2474+
"prefixItems": [
2475+
{
2476+
"type": "string"
2477+
}
2478+
]
2479+
},
24712480
"FixedTargetFields": {
2472-
"description": "List of target fields that are considered as `fixed`. \r\n A field marked as fixed will not stop the migration if differences are found. \r\n Instead of a warning, only an informational message will be logged. \r\n\n Use this list when you already know about the differences and have resolved them, \r\n for example by using `FieldMappingTool`. \r\n\n The key is the target work item type name. \r\n You can also use `*` to define fixed fields that apply to all work item types.",
2481+
"description": "List of target fields that are considered as `fixed`.\r\n A field marked as fixed will not stop the migration if differences are found.\r\n Instead of a warning, only an informational message will be logged.\r\n\n Use this list when you already know about the differences and have resolved them,\r\n for example by using `FieldMappingTool`.\r\n\n The key is the target work item type name.\r\n You can also use `*` to define fixed fields that apply to all work item types.",
24732482
"type": "object",
24742483
"default": "null",
24752484
"additionalProperties": {

docs/static/schema/schema.tools.tfsworkitemtypevalidatortool.json

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,12 @@
1010
"type": "boolean",
1111
"default": "true"
1212
},
13+
"ExcludeWorkItemtypes": {
14+
"description": "List of work item types which will be excluded from validation.",
15+
"type": "array"
16+
},
1317
"FixedTargetFields": {
14-
"description": "List of target fields that are considered as `fixed`. \r\n A field marked as fixed will not stop the migration if differences are found. \r\n Instead of a warning, only an informational message will be logged. \r\n\n Use this list when you already know about the differences and have resolved them, \r\n for example by using `FieldMappingTool`. \r\n\n The key is the target work item type name. \r\n You can also use `*` to define fixed fields that apply to all work item types.",
18+
"description": "List of target fields that are considered as `fixed`.\r\n A field marked as fixed will not stop the migration if differences are found.\r\n Instead of a warning, only an informational message will be logged.\r\n\n Use this list when you already know about the differences and have resolved them,\r\n for example by using `FieldMappingTool`.\r\n\n The key is the target work item type name.\r\n You can also use `*` to define fixed fields that apply to all work item types.",
1519
"type": "object",
1620
"default": "null"
1721
},

src/MigrationTools.Clients.TfsObjectModel/ServiceCollectionExtensions.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ public static void AddMigrationToolServicesForClientTfs_Tools(this IServiceColle
2626
context.AddSingleton<TfsRevisionManagerTool>().AddMigrationToolsOptions<TfsRevisionManagerToolOptions>(configuration);
2727
context.AddSingleton<TfsTeamSettingsTool>().AddMigrationToolsOptions<TfsTeamSettingsToolOptions>(configuration);
2828
context.AddSingleton<TfsChangeSetMappingTool>().AddMigrationToolsOptions<TfsChangeSetMappingToolOptions>(configuration);
29-
context.AddSingleton<TfsWorkItemTypeValidatorTool>().AddMigrationToolsOptions<TfsWorkItemTypeValidatorToolOptions>(configuration);
29+
context.AddSingleton<TfsWorkItemTypeValidatorTool>().AddMigrationToolsOptions<TfsWorkItemTypeValidatorToolOptions, TfsWorkItemTypeValidatorToolOptionsValidator>(configuration);
3030
}
3131

3232
public static void AddMigrationToolServicesForClientTfs_Processors(this IServiceCollection context)

src/MigrationTools.Clients.TfsObjectModel/Tools/TfsWorkItemTypeValidatorTool.cs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -254,6 +254,14 @@ private bool ShouldValidateWorkItemType(string workItemTypeName)
254254
workItemTypeName);
255255
return false;
256256
}
257+
else if ((Options.ExcludeWorkItemtypes.Count > 0)
258+
&& Options.ExcludeWorkItemtypes.Contains(workItemTypeName, StringComparer.OrdinalIgnoreCase))
259+
{
260+
Log.LogInformation(
261+
"Skipping validation of work item type '{sourceWit}' because it is excluded from validation list.",
262+
workItemTypeName);
263+
return false;
264+
}
257265
return true;
258266
}
259267

src/MigrationTools.Clients.TfsObjectModel/Tools/TfsWorkItemTypeValidatorToolOptions.cs

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,11 @@ public class TfsWorkItemTypeValidatorToolOptions : ToolOptions
2121
/// <default>null</default>
2222
public List<string> IncludeWorkItemtypes { get; set; } = [];
2323

24+
/// <summary>
25+
/// List of work item types which will be excluded from validation.
26+
/// </summary>
27+
public List<string> ExcludeWorkItemtypes { get; set; } = [];
28+
2429
/// <summary>
2530
/// Field reference name mappings. Key is work item type name, value is dictionary of mapping source filed name to
2631
/// target field name. Target field name can be empty string to indicate that this field will not be validated in target.
@@ -31,17 +36,17 @@ public class TfsWorkItemTypeValidatorToolOptions : ToolOptions
3136

3237
/// <summary>
3338
/// <para>
34-
/// List of target fields that are considered as <c>fixed</c>.
35-
/// A field marked as fixed will not stop the migration if differences are found.
36-
/// Instead of a warning, only an informational message will be logged.
39+
/// List of target fields that are considered as <c>fixed</c>.
40+
/// A field marked as fixed will not stop the migration if differences are found.
41+
/// Instead of a warning, only an informational message will be logged.
3742
/// </para>
3843
/// <para>
39-
/// Use this list when you already know about the differences and have resolved them,
40-
/// for example by using <see cref="FieldMappingTool"/>.
44+
/// Use this list when you already know about the differences and have resolved them,
45+
/// for example by using <see cref="FieldMappingTool"/>.
4146
/// </para>
4247
/// <para>
43-
/// The key is the target work item type name.
44-
/// You can also use <c>*</c> to define fixed fields that apply to all work item types.
48+
/// The key is the target work item type name.
49+
/// You can also use <c>*</c> to define fixed fields that apply to all work item types.
4550
/// </para>
4651
/// </summary>
4752
/// <default>null</default>
@@ -84,6 +89,7 @@ public void Normalize()
8489
}
8590

8691
IncludeWorkItemtypes ??= [];
92+
ExcludeWorkItemtypes ??= [];
8793
FixedTargetFields = newFixedFields;
8894
SourceFieldMappings = newMappings;
8995
_isNormalized = true;
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
using Microsoft.Extensions.Options;
2+
3+
namespace MigrationTools.Tools
4+
{
5+
public class TfsWorkItemTypeValidatorToolOptionsValidator : IValidateOptions<TfsWorkItemTypeValidatorToolOptions>
6+
{
7+
public ValidateOptionsResult Validate(string name, TfsWorkItemTypeValidatorToolOptions options)
8+
{
9+
int includedCount = options.IncludeWorkItemtypes?.Count ?? 0;
10+
int excludedCount = options.ExcludeWorkItemtypes?.Count ?? 0;
11+
12+
if ((includedCount > 0) && (excludedCount > 0))
13+
{
14+
const string msg = $"'{nameof(options.IncludeWorkItemtypes)}' and '{nameof(options.ExcludeWorkItemtypes)}'"
15+
+ $" cannot be set both at the same time.";
16+
return ValidateOptionsResult.Fail(msg);
17+
}
18+
return ValidateOptionsResult.Success;
19+
}
20+
}
21+
}

src/MigrationTools.Host/Commands/ExecuteMigrationCommand.cs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ internal override Task<int> ExecuteInternalAsync(CommandContext context, Execute
6565
CommandActivity.RecordException(ex);
6666
_logger.LogCritical("The config contains some invalid options. Please check the list below and refer to https://devopsmigration.io/ for the specific configration options.");
6767
_logger.LogCritical("------------");
68-
_logger.LogCritical("OptionName: {OptionsName}", ex.OptionsName);
68+
_logger.LogCritical("OptionName: {OptionsName}", GetOptionsName(ex));
6969
_logger.LogCritical("The following options are invalid:");
7070
foreach (var failure in ex.Failures)
7171
{
@@ -89,6 +89,16 @@ internal override Task<int> ExecuteInternalAsync(CommandContext context, Execute
8989
}
9090
return Task.FromResult(_exitCode);
9191
}
92+
93+
private string GetOptionsName(OptionsValidationException ex)
94+
{
95+
IOptions options = Activator.CreateInstance(ex.OptionsType) as IOptions;
96+
if (options is not null)
97+
{
98+
return options.ConfigurationMetadata.OptionFor;
99+
}
100+
return string.Empty;
101+
}
92102
}
93103
}
94104

0 commit comments

Comments
 (0)