From d267d6cbfcc49ca0166db7a73ed4cdb43634ab5e Mon Sep 17 00:00:00 2001 From: "Martin Hinshelwood nkdAgility.com" Date: Thu, 25 Jul 2024 10:32:31 +0100 Subject: [PATCH 1/3] =?UTF-8?q?=F0=9F=90=9B=20(WorkItemCloneCommand.cs):?= =?UTF-8?q?=20fix=20field=20access=20to=20use=20dictionary=20indexing=20?= =?UTF-8?q?=E2=99=BB=EF=B8=8F=20(WorkItemCloneCommand.cs):=20rename=20vari?= =?UTF-8?q?ables=20for=20clarity=20and=20consistency?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The changes fix the way fields are accessed in the `projectItem` object by using dictionary indexing (e.g., `projectItem.fields["System.Title"]`) instead of direct property access. This ensures compatibility with the data structure. Additionally, variable names are updated for better clarity and consistency, such as renaming `item` to `controlItem` in the `generateWorkItemsToBuildList` method. This improves code readability and maintainability. 📝 (Resources): add tst_jsonj_export_v20.json to Resources Introduce a new JSON file, `tst_jsonj_export_v20.json`, to the Resources directory. This file contains a list of work items with various fields such as `System.AreaPath`, `System.Tags`, `System.Title`, `Custom.Product`, `Microsoft.VSTS.Scheduling.Effort`, and `Custom.TRA_Milestone`. The addition of this file is intended to provide a sample dataset for testing and development purposes, ensuring that the application can handle and process work item data correctly. ✨ (data.json): add new tasks and milestones for engineering group New tasks and milestones are added to the data.json file to reflect the latest project requirements and scheduling efforts. This update ensures that all relevant tasks are tracked and managed effectively, improving project oversight and resource allocation. ♻️ (WorkItem.cs): change fields property type to Dictionary for flexibility The fields property is changed from a custom Fields type to a Dictionary. This change allows for more flexibility in handling various field types and structures that may be encountered in different work items. --- .../Commands/WorkItemCloneCommand.cs | 26 +- .../Resources/tst_jsonj_export_v20.json | 421 ++++++++++++++++++ .../DataContracts/WorkItem.cs | 2 +- 3 files changed, 433 insertions(+), 16 deletions(-) create mode 100644 AzureDevOps.WorkItemClone.ConsoleUI/Resources/tst_jsonj_export_v20.json diff --git a/AzureDevOps.WorkItemClone.ConsoleUI/Commands/WorkItemCloneCommand.cs b/AzureDevOps.WorkItemClone.ConsoleUI/Commands/WorkItemCloneCommand.cs index 5261299..9e465fe 100644 --- a/AzureDevOps.WorkItemClone.ConsoleUI/Commands/WorkItemCloneCommand.cs +++ b/AzureDevOps.WorkItemClone.ConsoleUI/Commands/WorkItemCloneCommand.cs @@ -230,8 +230,8 @@ await AnsiConsole.Progress() Dictionary queryParameters = new Dictionary() { { "@projectID", projectItem.id.ToString() }, - { "@projectTitle", projectItem.fields.SystemTitle }, - { "@projectTags", projectItem.fields.SystemTags }, + { "@projectTitle", projectItem.fields["System.Title"].ToString() }, + { "@projectTags", projectItem.fields["System.Tags"].ToString() }, { "@RunName", config.RunName } }; var query = await targetApi.CreateProjectQuery(config.targetQueryTitle, config.targetQueryFolder, config.targetQuery, queryParameters); @@ -250,13 +250,14 @@ await AnsiConsole.Progress() return 0; } + private async IAsyncEnumerable generateWorkItemsToBuildList(JArray jsonWorkItems, List templateWorkItems, WorkItemFull projectItem, string targetTeamProject) { - foreach (var item in jsonWorkItems) + foreach (var controlItem in jsonWorkItems) { WorkItemFull templateWorkItem = null; int jsonItemTemplateId = 0; - if (int.TryParse(item["id"].Value(), out jsonItemTemplateId)) + if (int.TryParse(controlItem["id"].Value(), out jsonItemTemplateId)) { templateWorkItem = templateWorkItems.Find(x => x.id == jsonItemTemplateId); } @@ -264,15 +265,9 @@ private async IAsyncEnumerable generateWorkItemsToBuildList(JAr newItem.guid = Guid.NewGuid(); newItem.hasComplexRelation = false; newItem.templateId = jsonItemTemplateId; - newItem.workItemType = templateWorkItem != null ? templateWorkItem.fields.SystemWorkItemType : "Deliverable"; + newItem.workItemType = templateWorkItem != null ? templateWorkItem.fields["System.WorkItemType"].ToString() : "Deliverable"; newItem.fields = new Dictionary(); - newItem.fields.Add("System.Description", templateWorkItem != null ? templateWorkItem.fields.SystemDescription : ""); - newItem.fields.Add("Microsoft.VSTS.Common.AcceptanceCriteria", templateWorkItem != null ? templateWorkItem.fields.MicrosoftVSTSCommonAcceptanceCriteria : ""); - //{ - // { "System.Tags", string.Join(";" , item.tags, item.area, item.fields.product, templateWorkItem != null? templateWorkItem.fields.SystemTags : "") }, - // { "System.AreaPath", string.Join("\\", targetTeamProject, item.area)}, - //}; - var fields = item["fields"].ToObject>(); + var fields = controlItem["fields"].ToObject>(); foreach (var field in fields) { switch (field.Key) @@ -281,14 +276,15 @@ private async IAsyncEnumerable generateWorkItemsToBuildList(JAr newItem.fields.Add(field.Key, string.Join("\\", targetTeamProject, field.Value)); break; default: - if (newItem.fields.ContainsKey(field.Key)) + if (templateWorkItem != null && templateWorkItem.fields.ContainsKey(field.Key) && (field.Value.Contains("${valuefromtemplate}") || field.Value.Contains("${fromtemplate}"))) { - newItem.fields[field.Key] = field.Value; + /// Add the value from the template + newItem.fields.Add(field.Key, templateWorkItem.fields[field.Key].ToString()); } else { + /// add value from control file newItem.fields.Add(field.Key, field.Value); - } break; } diff --git a/AzureDevOps.WorkItemClone.ConsoleUI/Resources/tst_jsonj_export_v20.json b/AzureDevOps.WorkItemClone.ConsoleUI/Resources/tst_jsonj_export_v20.json new file mode 100644 index 0000000..ab851b1 --- /dev/null +++ b/AzureDevOps.WorkItemClone.ConsoleUI/Resources/tst_jsonj_export_v20.json @@ -0,0 +1,421 @@ +[ + { + "id": 213928, + "fields": { + "System.AreaPath": "Engineering Group\\ECH Group\\ECH TPL 1", + "System.Tags": "Customer Document", + "System.Title": "Technical specification", + "Custom.Product": "CC", + "Microsoft.VSTS.Scheduling.Effort": 12, + "Custom.TRA_Milestone": "E0.1" + } + }, + { + "id": 251889, + "fields": { + "System.AreaPath": "Engineering Group\\ECH Group\\ECH TPL 1", + "System.Tags": "Customer Document", + "System.Title": "Technical specification", + "Custom.Product": "ESS", + "Microsoft.VSTS.Scheduling.Effort": 12, + "Custom.TRA_Milestone": "E0.1" + } + }, + { + "id": 213380, + "fields": { + "System.AreaPath": "Engineering Group\\ECH Group\\ECH TPL 1", + "System.Tags": "", + "System.Title": "Handover protocol", + "Custom.Product": "", + "Microsoft.VSTS.Scheduling.Effort": 4, + "Custom.TRA_Milestone": "E1" + } + + }, + { + "id": 214467, + "fields": { + "System.AreaPath": "Engineering Group\\ECH Group\\ECH TPL 1", + "System.Tags": "", + "System.Title": "Kick off protocol", + "Custom.Product": "", + "Microsoft.VSTS.Scheduling.Effort": 4, + "Custom.TRA_Milestone": "E1" + } + }, + { + "id": 213849, + "fields": { + "System.AreaPath": "Engineering Group\\ECH Group\\ECH TPL 1", + "System.Tags": "", + "System.Title": "Engineering cost estimation", + "Custom.Product": "", + "Microsoft.VSTS.Scheduling.Effort": 4, + "Custom.TRA_Milestone": "E1.1" + } + }, + { + "id": 213363, + "fields": { + "System.AreaPath": "Engineering Group\\ECH Group\\ECH TPL 1", + "System.Tags": "", + "System.Title": "Time schedule", + "Custom.Product": "", + "Microsoft.VSTS.Scheduling.Effort": 36.8, + "Custom.TRA_Milestone": "E1.1" + } + }, + { + "id": 213368, + "fields": { + "System.AreaPath": "Engineering Group\\ECH Group\\ECH TPL 1", + "System.Tags": "", + "System.Title": "Risk & Oppertunity Assement", + "Custom.Product": "", + "Microsoft.VSTS.Scheduling.Effort": 8, + "Custom.TRA_Milestone": "E1.2" + } + }, + { + "id": 213366, + "fields": { + "System.AreaPath": "Engineering Group\\ECH Group\\ECH TPL 1", + "System.Tags": "", + "System.Title": "Project management plan", + "Custom.Product": "", + "Microsoft.VSTS.Scheduling.Effort": 4, + "Custom.TRA_Milestone": "E2" + } + }, + { + "id": 213367, + "fields": { + "System.AreaPath": "Engineering Group\\ECH Group\\ECH TPL 1", + "System.Tags": "", + "System.Title": "Document list", + "Custom.Product": "", + "Microsoft.VSTS.Scheduling.Effort": 24, + "Custom.TRA_Milestone": "E2" + } + }, + { + "id": 213848, + "fields": { + "System.AreaPath": "Engineering Group\\ECH Group\\ECH TPL 1", + "System.Tags": "", + "System.Title": "Engineering Process Checklist", + "Custom.Product": "", + "Microsoft.VSTS.Scheduling.Effort": 8, + "Custom.TRA_Milestone": "E2" + } + }, + { + "id": "", + "fields": { + "System.AreaPath": "Engineering Group\\ECH Group\\ECH TPL 1", + "System.Tags": "", + "System.Title": "E2 Assessment", + "Custom.Product": "", + "Microsoft.VSTS.Scheduling.Effort": 2, + "Custom.TRA_Milestone": "E2" + } + }, + { + "id": "", + "fields": { + "System.AreaPath": "Engineering Group\\ECH Group\\ECH TPL 1", + "System.Tags": "", + "System.Title": "E2 Mgmt Meeting", + "Custom.Product": "", + "Microsoft.VSTS.Scheduling.Effort": 1, + "Custom.TRA_Milestone": "E2" + } + }, + { + "id": "", + "fields": { + "System.AreaPath": "Engineering Group\\ECH Group\\ECH TPL 1", + "System.Tags": "", + "System.Title": "Technical specification", + "Custom.Product": "CC", + "Microsoft.VSTS.Scheduling.Effort": 2, + "Custom.TRA_Milestone": "E3" + } + }, + { + "id": "", + "fields": { + "System.AreaPath": "Engineering Group\\ECH Group\\ECH TPL 1", + "System.Tags": "", + "System.Title": "Technical specification", + "Custom.Product": "ESS", + "Microsoft.VSTS.Scheduling.Effort": 2, + "Custom.TRA_Milestone": "E3" + } + }, + { + "id": 214486, + "fields": { + "System.AreaPath": "Engineering Group\\ECH Group\\ECH TPL 1", + "System.Tags": "", + "System.Title": "Rating plate", + "Custom.Product": "CC", + "Microsoft.VSTS.Scheduling.Effort": 4, + "Custom.TRA_Milestone": "E4.5" + } + }, + { + "id": 251898, + "fields": { + "System.AreaPath": "Engineering Group\\ECH Group\\ECH TPL 1", + "System.Tags": "", + "System.Title": "Rating plate", + "Custom.Product": "ESS", + "Microsoft.VSTS.Scheduling.Effort": 4, + "Custom.TRA_Milestone": "E4.5" + } + }, + { + "id": 251899, + "fields": { + "System.AreaPath": "Engineering Group\\ECH Group\\ECH TPL 1", + "System.Tags": "", + "System.Title": "Rating plate", + "Custom.Product": "eBox", + "Microsoft.VSTS.Scheduling.Effort": 4, + "Custom.TRA_Milestone": "E4.5" + } + }, + { + "id": 213374, + "fields": { + "System.AreaPath": "Engineering Group\\ECH Group\\ECH TPL 1", + "System.Tags": "Customer Document", + "System.Title": "Spare part list", + "Custom.Product": "CC", + "Microsoft.VSTS.Scheduling.Effort": 2.4, + "Custom.TRA_Milestone": "E4.5" + } + }, + { + "id": 251900, + "fields": { + "System.AreaPath": "Engineering Group\\ECH Group\\ECH TPL 1", + "System.Tags": "Customer Document", + "System.Title": "Spare part list", + "Custom.Product": "ESS", + "Microsoft.VSTS.Scheduling.Effort": 2.4, + "Custom.TRA_Milestone": "E4.5" + } + }, + { + "id": 214487, + "fields": { + "System.AreaPath": "Engineering Group\\ECH Group\\ECH TPL 1", + "System.Tags": "Customer Document", + "System.Title": "Spare part portfolio", + "Custom.Product": "CC", + "Microsoft.VSTS.Scheduling.Effort": 2.4, + "Custom.TRA_Milestone": "E4.6" + } + }, + { + "id": 251901, + "fields": { + "System.AreaPath": "Engineering Group\\ECH Group\\ECH TPL 1", + "System.Tags": "Customer Document", + "System.Title": "Spare part portfolio", + "Custom.Product": "ESS", + "Microsoft.VSTS.Scheduling.Effort": 2.4, + "Custom.TRA_Milestone": "E4.6" + } + }, + { + "id": "", + "fields": { + "System.AreaPath": "Engineering Group\\ECH Group\\ECH TPL 1", + "System.Tags": "", + "System.Title": "E4.8 Assessment", + "Custom.Product": "", + "Microsoft.VSTS.Scheduling.Effort": 2, + "Custom.TRA_Milestone": "E4.8" + } + }, + { + "id": "", + "fields": { + "System.AreaPath": "Engineering Group\\ECH Group\\ECH TPL 1", + "System.Tags": "", + "System.Title": "E4.8 Mgmt Meeting", + "Custom.Product": "", + "Microsoft.VSTS.Scheduling.Effort": 1, + "Custom.TRA_Milestone": "E4.8" + } + }, + { + "id": 214489, + "fields": { + "System.AreaPath": "Engineering Group\\ECH Group\\ECH TPL 1", + "System.Tags": "Customer Document", + "System.Title": "REACh_Compliance_Declaration", + "Custom.Product": "CC", + "Microsoft.VSTS.Scheduling.Effort": 12, + "Custom.TRA_Milestone": "E5" + } + }, + { + "id": 251905, + "fields": { + "System.AreaPath": "Engineering Group\\ECH Group\\ECH TPL 1", + "System.Tags": "Customer Document", + "System.Title": "REACh_Compliance_Declaration", + "Custom.Product": "eBox", + "Microsoft.VSTS.Scheduling.Effort": 12, + "Custom.TRA_Milestone": "E5" + } + }, + { + "id": 251904, + "fields": { + "System.AreaPath": "Engineering Group\\ECH Group\\ECH TPL 1", + "System.Tags": "Customer Document", + "System.Title": "REACh_Compliance_Declaration", + "Custom.Product": "ESS", + "Microsoft.VSTS.Scheduling.Effort": 12, + "Custom.TRA_Milestone": "E5" + } + }, + { + "id": "", + "fields": { + "System.AreaPath": "Engineering Group\\ECH Group\\ECH TPL 1", + "System.Tags": "", + "System.Title": "E6.7 Assessment", + "Custom.Product": "", + "Microsoft.VSTS.Scheduling.Effort": 2, + "Custom.TRA_Milestone": "E6.7" + } + }, + { + "id": "", + "fields": { + "System.AreaPath": "Engineering Group\\ECH Group\\ECH TPL 1", + "System.Tags": "", + "System.Title": "E6.7 Mgmt Meeting", + "Custom.Product": "", + "Microsoft.VSTS.Scheduling.Effort": 1, + "Custom.TRA_Milestone": "E6.7" + } + }, + { + "id": 213379, + "fields": { + "System.AreaPath": "Engineering Group\\ECH Group\\ECH TPL 1", + "System.Tags": "Customer Document", + "System.Title": "Operatiom Manual ", + "Custom.Product": "CC", + "Microsoft.VSTS.Scheduling.Effort": 40, + "Custom.TRA_Milestone": "E6.7" + } + }, + { + "id": 251902, + "fields": { + "System.AreaPath": "Engineering Group\\ECH Group\\ECH TPL 1", + "System.Tags": "Customer Document", + "System.Title": "Operatiom Manual ", + "Custom.Product": "ESS", + "Microsoft.VSTS.Scheduling.Effort": 40, + "Custom.TRA_Milestone": "E6.7" + } + }, + { + "id": "", + "fields": { + "System.AreaPath": "Engineering Group\\ECH Group\\ECH TPL 1", + "System.Tags": "", + "System.Title": "E7.2 Assessment", + "Custom.Product": "", + "Microsoft.VSTS.Scheduling.Effort": 2, + "Custom.TRA_Milestone": "E7.2" + } + }, + { + "id": "", + "fields": { + "System.AreaPath": "Engineering Group\\ECH Group\\ECH TPL 1", + "System.Tags": "", + "System.Title": "E7.2 Mgmt Meeting", + "Custom.Product": "", + "Microsoft.VSTS.Scheduling.Effort": 1, + "Custom.TRA_Milestone": "E7.2" + } + }, + { + "id": 214493, + "fields": { + "System.AreaPath": "Engineering Group\\ECH Group\\ECH TPL 1", + "System.Tags": "", + "System.Title": "Handover SER/PLCM prot.", + "Custom.Product": "", + "Microsoft.VSTS.Scheduling.Effort": 2.4, + "Custom.TRA_Milestone": "E7.5" + } + }, + { + "id": "", + "fields": { + "System.AreaPath": "Engineering Group\\ECH Group\\ECH TPL 1", + "System.Tags": "", + "System.Title": "Technical specification", + "Custom.Product": "CC", + "Microsoft.VSTS.Scheduling.Effort": 2, + "Custom.TRA_Milestone": "E8" + } + }, + { + "id": "", + "fields": { + "System.AreaPath": "Engineering Group\\ECH Group\\ECH TPL 1", + "System.Tags": "", + "System.Title": "Technical specification", + "Custom.Product": "ESS", + "Microsoft.VSTS.Scheduling.Effort": 2, + "Custom.TRA_Milestone": "E8" + } + }, + { + "id": "", + "fields": { + "System.AreaPath": "Engineering Group\\ECH Group\\ECH TPL 1", + "System.Tags": "", + "System.Title": "Engineering Process Checklist", + "Custom.Product": "", + "Microsoft.VSTS.Scheduling.Effort": 1, + "Custom.TRA_Milestone": "E8" + } + }, + { + "id": "", + "fields": { + "System.AreaPath": "Engineering Group\\ECH Group\\ECH TPL 1", + "System.Tags": "", + "System.Title": "E8 Assessment", + "Custom.Product": "", + "Microsoft.VSTS.Scheduling.Effort": 2, + "Custom.TRA_Milestone": "E8" + } + }, + { + "id": "", + "fields": { + "System.AreaPath": "Engineering Group\\ECH Group\\ECH TPL 1", + "System.Tags": "", + "System.Title": "E8 Mgmt Meeting", + "Custom.Product": "", + "Microsoft.VSTS.Scheduling.Effort": 1, + "Custom.TRA_Milestone": "E8" + } + } +] \ No newline at end of file diff --git a/AzureDevOps.WorkItemClone/DataContracts/WorkItem.cs b/AzureDevOps.WorkItemClone/DataContracts/WorkItem.cs index 84509c3..431b893 100644 --- a/AzureDevOps.WorkItemClone/DataContracts/WorkItem.cs +++ b/AzureDevOps.WorkItemClone/DataContracts/WorkItem.cs @@ -17,7 +17,7 @@ public class WorkItemFull { public int id { get; set; } public int rev { get; set; } - public Fields fields { get; set; } + public Dictionary fields { get; set; } public Relation[] relations { get; set; } public _Links3 _links { get; set; } public string url { get; set; } From bb957b5c81a6a815424cf500d6cdca0679d56135 Mon Sep 17 00:00:00 2001 From: "Martin Hinshelwood nkdAgility.com" Date: Thu, 25 Jul 2024 10:43:27 +0100 Subject: [PATCH 2/3] =?UTF-8?q?=F0=9F=93=9D=20(README.md):=20update=20exam?= =?UTF-8?q?ple=20work=20item=20fields=20to=20include=20description=20and?= =?UTF-8?q?=20acceptance=20criteria?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add `System.Description` and `Microsoft.VSTS.Common.AcceptanceCriteria` fields to the example work item JSON. This provides a more comprehensive example and ensures that users understand how to include these additional fields in their work items. --- README.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 6f9ffff..e1e6af7 100644 --- a/README.md +++ b/README.md @@ -127,7 +127,9 @@ The `fields` are the fields that will be used to create the work item. You can u "System.Title": "Technical specification", "Custom.Product": "CC", "Microsoft.VSTS.Scheduling.Effort": 12, - "Custom.TRA_Milestone": "E0.1" + "Custom.TRA_Milestone": "E0.1", + "System.Description": "${fromtemplate}", + "Microsoft.VSTS.Common.AcceptanceCriteria": "${fromtemplate}" } }, { @@ -139,6 +141,8 @@ The `fields` are the fields that will be used to create the work item. You can u "Custom.Product": "", "Microsoft.VSTS.Scheduling.Effort": 2, "Custom.TRA_Milestone": "E4.8" + "System.Description": "${fromtemplate}", + "Microsoft.VSTS.Common.AcceptanceCriteria": "${fromtemplate}" } ] ``` From b339983f23cccf1f4ea6a7da52228428e8522bd1 Mon Sep 17 00:00:00 2001 From: "Martin Hinshelwood nkdAgility.com" Date: Thu, 25 Jul 2024 12:17:14 +0100 Subject: [PATCH 3/3] =?UTF-8?q?=F0=9F=90=9B=20(WorkItemCloneCommand.cs):?= =?UTF-8?q?=20handle=20missing=20'System.Tags'=20field=20to=20prevent=20er?= =?UTF-8?q?rors=20=F0=9F=94=A7=20(launchSettings.json):=20update=20command?= =?UTF-8?q?LineArgs=20to=20use=20a=20lighter=20test=20JSON=20file=20?= =?UTF-8?q?=E2=9C=A8=20(Resources):=20add=20a=20new=20lightweight=20test?= =?UTF-8?q?=20JSON=20file=20for=20faster=20testing=20=E2=99=BB=EF=B8=8F=20?= =?UTF-8?q?(WorkItem.cs):=20remove=20unused=20Fields=20class=20to=20clean?= =?UTF-8?q?=20up=20the=20codebase=20=F0=9F=93=9D=20(README.md):=20update?= =?UTF-8?q?=20targetQuery=20example=20and=20add=20clarification=20on=20`${?= =?UTF-8?q?fromtemplate}`=20usage?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Handling the missing 'System.Tags' field prevents potential runtime errors when the field is not present. Updating the commandLineArgs to use a lighter test JSON file improves testing efficiency. Adding a new lightweight test JSON file provides a more efficient testing resource. Removing the unused Fields class cleans up the codebase, making it more maintainable. Updating the README.md provides clearer documentation on how to use the `${fromtemplate}` placeholder and updates the targetQuery example to reflect the latest query structure. --- .../Commands/WorkItemCloneCommand.cs | 2 +- .../Properties/launchSettings.json | 2 +- .../Resources/tst_jsonj_export_v20-lite.json | 15 +++++++++++++++ .../DataContracts/WorkItem.cs | 19 ------------------- README.md | 4 +++- TestData/tst_jsonj_export_v20-lite.json | 15 +++++++++++++++ 6 files changed, 35 insertions(+), 22 deletions(-) create mode 100644 AzureDevOps.WorkItemClone.ConsoleUI/Resources/tst_jsonj_export_v20-lite.json create mode 100644 TestData/tst_jsonj_export_v20-lite.json diff --git a/AzureDevOps.WorkItemClone.ConsoleUI/Commands/WorkItemCloneCommand.cs b/AzureDevOps.WorkItemClone.ConsoleUI/Commands/WorkItemCloneCommand.cs index 9e465fe..3132ae3 100644 --- a/AzureDevOps.WorkItemClone.ConsoleUI/Commands/WorkItemCloneCommand.cs +++ b/AzureDevOps.WorkItemClone.ConsoleUI/Commands/WorkItemCloneCommand.cs @@ -231,7 +231,7 @@ await AnsiConsole.Progress() { { "@projectID", projectItem.id.ToString() }, { "@projectTitle", projectItem.fields["System.Title"].ToString() }, - { "@projectTags", projectItem.fields["System.Tags"].ToString() }, + { "@projectTags", projectItem.fields.ContainsKey("System.Tags") ? projectItem.fields["System.Tags"].ToString() : "" }, { "@RunName", config.RunName } }; var query = await targetApi.CreateProjectQuery(config.targetQueryTitle, config.targetQueryFolder, config.targetQuery, queryParameters); diff --git a/AzureDevOps.WorkItemClone.ConsoleUI/Properties/launchSettings.json b/AzureDevOps.WorkItemClone.ConsoleUI/Properties/launchSettings.json index b1deeaf..ddef29f 100644 --- a/AzureDevOps.WorkItemClone.ConsoleUI/Properties/launchSettings.json +++ b/AzureDevOps.WorkItemClone.ConsoleUI/Properties/launchSettings.json @@ -6,7 +6,7 @@ }, "Clone": { "commandName": "Project", - "commandLineArgs": "clone --cachePath ..\\..\\..\\..\\..\\.cache\\ --configFile ..\\..\\..\\..\\..\\.cache\\configuration-test.json --jsonFile ..\\..\\..\\..\\..\\TestData\\tst_jsonj_export_v20.json --NonInteractive" + "commandLineArgs": "clone --cachePath ..\\..\\..\\..\\..\\.cache\\ --configFile ..\\..\\..\\..\\..\\.cache\\configuration-test.json --jsonFile ..\\..\\..\\..\\..\\TestData\\tst_jsonj_export_v20-lite.json --NonInteractive" }, "empty": { "commandName": "Project" diff --git a/AzureDevOps.WorkItemClone.ConsoleUI/Resources/tst_jsonj_export_v20-lite.json b/AzureDevOps.WorkItemClone.ConsoleUI/Resources/tst_jsonj_export_v20-lite.json new file mode 100644 index 0000000..9e76a24 --- /dev/null +++ b/AzureDevOps.WorkItemClone.ConsoleUI/Resources/tst_jsonj_export_v20-lite.json @@ -0,0 +1,15 @@ +[ + { + "id": 213928, + "fields": { + "System.AreaPath": "Engineering Group\\ECH Group\\ECH TPL 1", + "System.Tags": "Customer Document", + "System.Title": "Technical specification", + "Custom.Product": "CC", + "Microsoft.VSTS.Scheduling.Effort": 12, + "Custom.TRA_Milestone": "E0.1", + "System.Description": "${fromtemplate}", + "Microsoft.VSTS.Common.AcceptanceCriteria": "${fromtemplate}" + } + } +] \ No newline at end of file diff --git a/AzureDevOps.WorkItemClone/DataContracts/WorkItem.cs b/AzureDevOps.WorkItemClone/DataContracts/WorkItem.cs index 431b893..2a31615 100644 --- a/AzureDevOps.WorkItemClone/DataContracts/WorkItem.cs +++ b/AzureDevOps.WorkItemClone/DataContracts/WorkItem.cs @@ -23,25 +23,6 @@ public class WorkItemFull public string url { get; set; } } - public class Fields - { - [JsonProperty("System.Id")] - public int SystemId { get; set; } - [JsonProperty("System.WorkItemType")] - public string SystemWorkItemType { get; set; } - - [JsonProperty("System.Title")] - public string SystemTitle { get; set; } - [JsonProperty("System.Description")] - public string SystemDescription { get; set; } - [JsonProperty("Microsoft.VSTS.Common.AcceptanceCriteria")] - public string MicrosoftVSTSCommonAcceptanceCriteria { get; set; } - [JsonProperty("System.Tags")] - public string SystemTags { get; set; } - [JsonProperty("System.Parent")] - public int SystemParent { get; set; } - } - public class SystemCreatedby { public string displayName { get; set; } diff --git a/README.md b/README.md index e1e6af7..986e70b 100644 --- a/README.md +++ b/README.md @@ -104,7 +104,7 @@ Clones work items from a template project to a target project incorproating a JS "templateOrganization": "orgname", "templateProject": "template Project", "templateParentId": 212315, - "targetQuery": "SELECT [System.Id], [System.WorkItemType], [System.Title], [System.AreaPath],[System.AssignedTo],[System.State] FROM workitems WHERE [System.Parent] = @projectID", + "targetQuery": "SELECT [Custom.Product], [System.Title], [System.Description], [Custom.DeadlineDate], [System.AreaPath], [System.AssignedTo], [System.State], [Custom.Notes], [System.WorkItemType], [Custom.TRA_Milestone] FROM WorkItemLinks WHERE (Source.[System.Id] = @projectID or Source.[System.Parent] = @projectID) and ([System.Links.LinkType] = 'System.LinkTypes.Hierarchy-Forward') and (Target.[System.Parent] = @projectID) ORDER BY [Custom.DeadlineDate] mode(Recursive)", "targetQueryTitle": "Project-@RunName - @projectTitle", "targetQueryFolder": "Shared Queries" } @@ -117,6 +117,8 @@ The `id` is the ID of the template item. This will be used to specifiy Descripti The `fields` are the fields that will be used to create the work item. You can use any field ientifyer from Azure DevOps. +Use the `${fromtemplate}` to specify that the value should be taken from the template. This is used here for the Description and Acceptance Criteria, but can be used to pull data from any field. + ```json [ { diff --git a/TestData/tst_jsonj_export_v20-lite.json b/TestData/tst_jsonj_export_v20-lite.json new file mode 100644 index 0000000..9e76a24 --- /dev/null +++ b/TestData/tst_jsonj_export_v20-lite.json @@ -0,0 +1,15 @@ +[ + { + "id": 213928, + "fields": { + "System.AreaPath": "Engineering Group\\ECH Group\\ECH TPL 1", + "System.Tags": "Customer Document", + "System.Title": "Technical specification", + "Custom.Product": "CC", + "Microsoft.VSTS.Scheduling.Effort": 12, + "Custom.TRA_Milestone": "E0.1", + "System.Description": "${fromtemplate}", + "Microsoft.VSTS.Common.AcceptanceCriteria": "${fromtemplate}" + } + } +] \ No newline at end of file