protected override QueryHierarchyItem DoNewItem() { var itemType = GetParameter <string>("ItemType").ToLower(); var isFolder = itemType.Equals("folder"); var item = isFolder? GetParameter <string>("Folder"): GetParameter <string>("Query"); var wiql = GetParameter <string>("Wiql"); var scope = GetParameter <string>("Scope").Equals("Personal") ? "My Queries" : "Shared Queries"; var force = GetParameter <bool>("Force"); var(_, tp) = GetCollectionAndProject(); var fullPath = NodeUtil.NormalizeNodePath(item, tp.Name, scope, includeScope: true, separator: '/'); var queryName = Path.GetFileName(fullPath); var parentPath = Path.GetDirectoryName(fullPath); var existingItem = GetItem <QueryHierarchyItem>(); if (existingItem != null && isFolder) { Log("Folder already exists."); if (!force) { throw new Exception($"A folder with the specified name '{fullPath}' already exists."); } return(existingItem); } if (!ShouldProcess(tp, $"{(existingItem == null ? "Create" : "Overwrite")} " + $"work item {itemType} '{fullPath}'")) { return(null); } var client = GetClient <WorkItemTrackingHttpClient>(); var newItem = new QueryHierarchyItem() { Name = queryName, Path = parentPath, IsFolder = isFolder, Wiql = wiql }; var parentFolder = GetItem <QueryHierarchyItem>(new{ Folder = parentPath, ItemType = "Folder" }) ?? NewItem <QueryHierarchyItem>(new { Folder = parentPath, ItemType = "Folder" }); this.Log($"Creating query '{queryName}' in folder '{parentPath}'"); var result = client.CreateQueryAsync(newItem, tp.Name, parentFolder.Id.ToString()) .GetResult($"Error creating new work item {itemType} '{fullPath}'"); return(result); }
//TODO: Inject TeamProject //TODO: Use NormalizePath protected override IEnumerable <WebApiFolder> DoGetItems() { var folder = GetParameter <object>("Folder"); var queryOrder = GetParameter <FolderPathQueryOrder>("QueryOrder"); while (true) { switch (folder) { case WebApiFolder f: { yield return(f); yield break; } case string s when s.IsWildcard(): { var client = GetClient <ReleaseHttpClient>(); var(_, tp) = GetCollectionAndProject(); s = NodeUtil.NormalizeNodePath(s, tp.Name); var folders = client.GetFoldersAsync(tp.Name, null, queryOrder) .GetResult($"Error getting folders matching {s}"); foreach (var i in folders .Where(f => f.Path.IsLike(s) || GetFolderName(f).IsLike(s))) { yield return(i); } yield break; } case string s: { var client = GetClient <ReleaseHttpClient>(); var(_, tp) = GetCollectionAndProject(); var f = client.GetFoldersAsync(tp.Name, NodeUtil.NormalizeNodePath(s, tp.Name), queryOrder) .GetResult($"Error getting folders matching {s}").FirstOrDefault(); if (f != null) { yield return(f); } yield break; } default: { throw new ArgumentException($"Invalid or non-existent pipeline folder '{folder}'"); } } } }
protected override IEnumerable <QueryHierarchyItem> DoGetItems() { var itemType = GetParameter <string>("ItemType").ToLower(); var isFolder = itemType.Equals("folder"); var item = isFolder ? GetParameter <string>("Folder") : GetParameter <string>("Query"); var scope = GetParameter <string>(nameof(GetWorkItemQuery.Scope)); var(_, tp) = GetCollectionAndProject(); var client = GetClient <Microsoft.TeamFoundation.WorkItemTracking.WebApi.WorkItemTrackingHttpClient>(); while (true) { switch (item) { case string s: { var result = client.GetQueriesAsync(tp.Name, QueryExpand.All, 2) .GetResult("Error getting work item query root folders") .Where(q => scope.Equals("Both") || q.IsPublic == scope.Equals("Shared")) .ToList(); foreach (var rootFolder in result) { if (rootFolder.Name.Equals(s) && isFolder) { yield return(rootFolder); yield break; } var path = NodeUtil.NormalizeNodePath(s, tp.Name, rootFolder.Name, includeScope: true, separator: '/'); foreach (var c in GetItemsRecursively(rootFolder, path, tp.Name, itemType.Equals("query"), client)) { yield return(c); } } yield break; } default: throw new ArgumentException($"Invalid or non-exixtent query/folder '{item}'"); } } }
protected override WebApiFolder DoNewItem() { var(_, tp) = GetCollectionAndProject(); var folder = GetParameter <string>(nameof(NewReleaseDefinitionFolder.Folder)); var description = GetParameter <string>(nameof(NewReleaseDefinitionFolder.Description)); if (!ShouldProcess(tp, $"Create release folder '{folder}'")) { return(null); } var client = GetClient <ReleaseHttpClient>(); var newFolder = new WebApiFolder() { Description = description, Path = NodeUtil.NormalizeNodePath(folder, tp.Name) }; return(client.CreateFolderAsync(newFolder, tp.Name) .GetResult($"Error creating folder '{folder}'")); }
protected override ClassificationNode DoNewItem() { var node = GetParameter <string>(nameof(NewClassificationNode.Node)); var structureGroup = GetParameter <TreeStructureGroup>("StructureGroup"); var force = GetParameter <bool>(nameof(NewClassificationNode.Force)); var(_, tp) = GetCollectionAndProject(); var nodePath = NodeUtil.NormalizeNodePath(node, tp.Name, structureGroup.ToString().TrimEnd('s'), false, false, true); var client = GetClient <WorkItemTrackingHttpClient>(); var parentPath = Path.GetDirectoryName(nodePath); var nodeName = Path.GetFileName(nodePath); if (!ShouldProcess($"Team Project {tp.Name}", $"Create node '{nodePath}'")) { return(null); } if (!TestItem <ClassificationNode>(new { Node = parentPath })) { if (!force) { this.Log($"Parent node '{parentPath}' does not exist"); throw new Exception($"Parent node '{parentPath}' does not exist. Check the path or use -Force the create any missing parent nodes."); } NewItem <ClassificationNode>(new { Node = parentPath }); } var patch = new WorkItemClassificationNode() { Name = nodeName }; var result = client.CreateOrUpdateClassificationNodeAsync(patch, tp.Name, structureGroup, parentPath) .GetResult($"Error creating node {nodePath}"); return(new ClassificationNode(result, tp.Name, client)); }
protected override TestPlan DoNewItem() { var testPlan = GetParameter <string>(nameof(NewTestPlan.TestPlan)); var owner = GetParameter <string>(nameof(NewTestPlan.Owner)); var areaPath = GetParameter <string>(nameof(NewTestPlan.AreaPath), "\\"); var iterationPath = GetParameter <string>(nameof(NewTestPlan.IterationPath), "\\"); var startDate = GetParameter <DateTime>(nameof(NewTestPlan.StartDate)); var endDate = GetParameter <DateTime>(nameof(NewTestPlan.EndDate)); var(_, tp) = GetCollectionAndProject(); var client = GetClient <TestPlanHttpClient>(); return(client.CreateTestPlanAsync(new TestPlanCreateParams() { AreaPath = NodeUtil.NormalizeNodePath(areaPath, tp.Name, "Areas", includeTeamProject: true), Iteration = NodeUtil.NormalizeNodePath(iterationPath, tp.Name, "Iterations", includeTeamProject: true), Name = testPlan, // TODO: Owner = owner, StartDate = (startDate == DateTime.MinValue? (DateTime?)null: startDate), EndDate = (endDate == DateTime.MinValue? (DateTime?)null: endDate) }, tp.Name).GetResult($"Error creating test plan '{testPlan}'")); }
protected override IEnumerable <ClassificationNode> DoGetItems() { var node = GetParameter <object>(nameof(GetClassificationNode.Node)); var structureGroup = GetParameter <TreeStructureGroup>("StructureGroup"); var(_, tp) = this.GetCollectionAndProject(); bool done = false; string path = null; while (!done) { switch (node) { case WorkItemClassificationNode n: { yield return(new ClassificationNode(n, tp.Name, null)); yield break; } case string s when s.Equals("\\") || s.Equals("/"): { path = "\\"; done = true; break; } case string s when !string.IsNullOrEmpty(s) && s.IsWildcard(): { path = NodeUtil.NormalizeNodePath(s, tp.Name, structureGroup.ToString().TrimEnd('s'), true, false, true, false, true); done = true; break; } case string s when !string.IsNullOrEmpty(s): { path = NodeUtil.NormalizeNodePath(s, tp.Name, structureGroup.ToString().TrimEnd('s'), false, false, true, false, false); done = true; break; } default: { throw new ArgumentException($"Invalid or non-existent node {node}"); } } } var client = GetClient <WorkItemTrackingHttpClient>(); int depth = 1; if (path.IsWildcard()) { depth = 2; Logger.Log($"Preparing to recursively search for pattern '{path}'"); var root = new ClassificationNode(client.GetClassificationNodeAsync(tp.Name, structureGroup, "\\", depth) .GetResult($"Error retrieving {structureGroup} from path '{path}'"), tp.Name, client); foreach (var n in root.GetChildren(path, true)) { yield return(n); } yield break; } Logger.Log($"Getting {structureGroup} under path '{path}'"); yield return(new ClassificationNode(client.GetClassificationNodeAsync(tp.Name, structureGroup, path, depth) .GetResult($"Error retrieving {structureGroup} from path '{path}'"), tp.Name, null)); }
protected override Models.Team DoSetItem() { var(tpc, tp, t) = GetCollectionProjectAndTeam(); var description = GetParameter <string>(nameof(SetTeam.Description)); var defaultTeam = GetParameter <bool>(nameof(SetTeam.Default)); var defaultAreaPath = GetParameter <string>(nameof(SetTeam.DefaultAreaPath)); var areaPaths = GetParameter <IEnumerable <string> >(nameof(SetTeam.AreaPaths)); var backlogIteration = GetParameter <string>(nameof(SetTeam.BacklogIteration)); var iterationPaths = GetParameter <IEnumerable <string> >(nameof(SetTeam.IterationPaths)); var defaultIteration = GetParameter <string>(nameof(SetTeam.DefaultIterationMacro)); var teamClient = GetClient <TeamHttpClient>(); var projectClient = GetClient <ProjectHttpClient>(); var workClient = GetClient <WorkHttpClient>(); // Set description if (HasParameter("Description") && ShouldProcess(t, $"Set team's description to '{description}'")) { teamClient.UpdateTeamAsync(new WebApiTeam() { Description = description ?? string.Empty }, tp.Id.ToString(), t.Id.ToString()) .GetResult($"Error setting team '{t.Name}''s description to '{description}'"); } // Set default team if (defaultTeam && ShouldProcess(tp, $"Set team '{t.Name} as default'")) { throw new NotImplementedException("Set team as default is currently not supported"); } // Set Team Field / Area Path settings var ctx = new TeamContext(tp.Name, t.Name); var teamFieldPatch = new TeamFieldValuesPatch(); if (!string.IsNullOrEmpty(defaultAreaPath) && ShouldProcess(t, $"Set team's default area path (team field) to '{defaultAreaPath}'")) { if (tpc.IsHosted) { this.Log("Conected to Azure DevOps Services. Treating Team Field Value as Area Path"); defaultAreaPath = NodeUtil.NormalizeNodePath(defaultAreaPath, tp.Name, "Areas", includeTeamProject: true); } if (areaPaths == null) { this.Log("AreaPaths is empty. Adding DefaultAreaPath (TeamFieldValue) to AreaPaths as default value."); areaPaths = new string[] { defaultAreaPath }; } var area = new { Node = defaultAreaPath }; if (!TestItem <Models.ClassificationNode>(area)) { NewItem <Models.ClassificationNode>(area); } this.Log($"Setting default area path (team field) to {defaultAreaPath}"); teamFieldPatch.DefaultValue = defaultAreaPath; } if (areaPaths != null && ShouldProcess(t, $"Set {string.Join(", ", areaPaths)} as team's area paths")) { var values = new List <TeamFieldValue>(); foreach (var a in areaPaths) { values.Add(new TeamFieldValue() { Value = NodeUtil.NormalizeNodePath(a.TrimEnd('\\', '*'), tp.Name, scope: "Areas", includeTeamProject: true), IncludeChildren = a.EndsWith("*") }); } teamFieldPatch.Values = values; workClient.UpdateTeamFieldValuesAsync(teamFieldPatch, ctx) .GetResult("Error applying team field value and/or area path settings"); } // Set backlog and iteration path settings bool isDirty = false; var iterationPatch = new TeamSettingsPatch(); if (backlogIteration != null && ShouldProcess(t, $"Set the team's backlog iteration to '{backlogIteration}'")) { this.Log($"Setting backlog iteration to {backlogIteration}"); var iteration = GetItem <Models.ClassificationNode>(new { Node = backlogIteration, StructureGroup = TreeStructureGroup.Iterations }); iterationPatch.BacklogIteration = iterationPatch.DefaultIteration = iteration.Identifier; isDirty = true; } if (!string.IsNullOrEmpty(defaultIteration) && ShouldProcess(t, $"Set the team's default iteration to '{defaultIteration}'")) { this.Log($"Setting default iteration to '{defaultIteration}'"); if (!defaultIteration.StartsWith("@")) { var iteration = GetItem <Models.ClassificationNode>(new { Node = defaultIteration, StructureGroup = TreeStructureGroup.Iterations }); iterationPatch.DefaultIteration = iteration.Identifier; } else { iterationPatch.DefaultIteration = null; iterationPatch.DefaultIterationMacro = defaultIteration; } isDirty = true; } if (isDirty) { workClient.UpdateTeamSettingsAsync(iterationPatch, ctx) .GetResult("Error applying iteration and/or board settings"); } // TODO: Finish migration // if (BacklogVisibilities && ShouldProcess(Team, $"Set the team"s backlog visibilities to {_DumpObj {BacklogVisibilities}}")) // { // this.Log($"Setting backlog iteration to {BacklogVisibilities}"); // patch.BacklogVisibilities = _NewDictionary @([string], [bool]) BacklogVisibilities // isDirty = true // } // if (DefaultIterationMacro && ShouldProcess(Team, $"Set the team"s default iteration macro to {DefaultIterationMacro}")) // { // this.Log($"Setting default iteration macro to {DefaultIterationMacro}"); // patch.DefaultIterationMacro = DefaultIterationMacro // isDirty = true // } // if (WorkingDays && ShouldProcess(Team, $"Set the team"s working days to {_DumpObj {WorkingDays}}")) // { // this.Log($"Setting working days to {{WorkingDays}|ConvertTo=-Json -Compress}"); // patch.WorkingDays = WorkingDays // isDirty = true // } // if(BugsBehavior && ShouldProcess(Team, $"Set the team"s bugs behavior to {_DumpObj {BugsBehavior}}")) // { // this.Log($"Setting bugs behavior to {_DumpObj {BugsBehavior}}"); // patch.BugsBehavior = BugsBehavior // isDirty = true // } // if(isDirty) // { // task = client.UpdateTeamSettingsAsync(patch, ctx) // result = task.Result; if(task.IsFaulted) { _throw new Exception("Error applying iteration settings" task.Exception.InnerExceptions }) // } // if(Passthru.IsPresent) // { // WriteObject(t); return; // } // } // } return(GetItem <Models.Team>()); }