Skip to content

Commit 86a036e

Browse files
authored
Fix Set-TfsWorkItem (#175)
* Fix #174 * Add handling for System.Tags * Add handling for identity fields * Add WorkItemPatchBuilder service * Add WorkItemFieldAttribute * Change return type for Team property * Expose cmdlet * Add null value handling for bound params * Add IWorkItemPatchBuilder * Change GetProject/GetTeam to return only current * Update release notes * Add AssignedTo field * Add logic to ignore WorkItem argument * Change logic to use WorkItemPatchBuilder * Finish implementing New/SetWorkItem * Update release notes
1 parent 16b4a4f commit 86a036e

28 files changed

+356
-295
lines changed

CSharp/TfsCmdlets.Common/Attributes.cs

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1-
namespace TfsCmdlets
1+
using Microsoft.TeamFoundation.WorkItemTracking.WebApi.Models;
2+
3+
namespace TfsCmdlets
24
{
35
[AttributeUsage(System.AttributeTargets.Class, Inherited = true, AllowMultiple = false)]
46
public class CmdletControllerAttribute: ExportAttribute
@@ -34,6 +36,19 @@ public ModelAttribute(Type dataType)
3436
}
3537
}
3638

39+
[AttributeUsage(System.AttributeTargets.Property, Inherited = true, AllowMultiple = false)]
40+
public sealed class WorkItemFieldAttribute: Attribute
41+
{
42+
public string Name { get; }
43+
public FieldType Type { get; }
44+
45+
public WorkItemFieldAttribute(string name, FieldType type)
46+
{
47+
Name = name;
48+
Type = type;
49+
}
50+
}
51+
3752
// [AttributeUsage(System.AttributeTargets.Class, Inherited = false, AllowMultiple = false)]
3853
// public sealed class DesktopOnlyAttribute : Attribute
3954
// {

CSharp/TfsCmdlets.Common/Services/ICurrentConnections.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ public interface ICurrentConnections
1010

1111
WebApiTeamProject Project { get; set; }
1212

13-
WebApiTeam Team { get; set; }
13+
Models.Team Team { get; set; }
1414

1515
T Get<T>(string name);
1616

CSharp/TfsCmdlets.Common/Services/IDataManager.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,13 +34,13 @@ public interface IDataManager
3434

3535
bool TryGetCollection(out Models.Connection collection, object overridingParameters = null);
3636

37-
WebApiTeamProject GetProject(object overridingParameters = null, string contextValue = null);
37+
WebApiTeamProject GetProject();
3838

3939
bool TryGetProject(out WebApiTeamProject project, object overridingParameters = null);
4040

41-
Models.Team GetTeam(object overridingParameters = null, string contextValue = null);
41+
Models.Team GetTeam(bool includeSettings = false, bool includeMembers = false);
4242

43-
bool TryGetTeam(out WebApiTeam team, object overridingParameters = null);
43+
bool TryGetTeam(out WebApiTeam returnTeam, bool includeSettings = false, bool includeMembers = false);
4444

4545
T GetClient<T>(object overridingParameters = null);
4646

CSharp/TfsCmdlets.Common/Services/IPowerShellService.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
using System.Management.Automation;
22
using System.Management.Automation.Runspaces;
33
using Microsoft.TeamFoundation.Core.WebApi;
4+
using TfsCmdlets.Cmdlets;
45
using TfsCmdlets.Models;
56

67
namespace TfsCmdlets.Services
@@ -35,6 +36,8 @@ public interface IPowerShellService
3536

3637
string CurrentCommand {get;}
3738

39+
CmdletBase CurrentCmdlet { get; }
40+
3841
string CurrentCommandLine {get;}
3942

4043
bool ShouldProcess(string target, string action);
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
using Microsoft.VisualStudio.Services.WebApi.Patch.Json;
2+
3+
namespace TfsCmdlets.Services
4+
{
5+
public interface IWorkItemPatchBuilder
6+
{
7+
JsonPatchDocument GetJson(WebApiWorkItem wi);
8+
}
9+
}

CSharp/TfsCmdlets.Common/Services/Impl/CurrentConnectionsImpl.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ public class CurrentConnectionsImpl: ICurrentConnections
1212

1313
public WebApiTeamProject Project {get;set;}
1414

15-
public WebApiTeam Team {get;set;}
15+
public Models.Team Team {get;set;}
1616

1717
public T Get<T>(string name)
1818
{

CSharp/TfsCmdlets.Common/Services/Impl/DataManagerImpl.cs

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -116,8 +116,8 @@ public bool TryGetCollection(out Models.Connection collection, object overriding
116116
return collection != null;
117117
}
118118

119-
public WebApiTeamProject GetProject(object overridingParameters = null, string contextValue = null)
120-
=> GetItems<WebApiTeamProject>(overridingParameters).FirstOrDefault() ??
119+
public WebApiTeamProject GetProject()
120+
=> GetItems<WebApiTeamProject>().FirstOrDefault() ??
121121
throw new ArgumentException("No team project information available. Either supply a valid -Project argument or use Connect-TfsTeamProject prior to invoking this cmdlet.");
122122

123123
public bool TryGetProject(out WebApiTeamProject project, object overridingParameters = null)
@@ -130,15 +130,20 @@ public bool TryGetProject(out WebApiTeamProject project, object overridingParame
130130
return project != null;
131131
}
132132

133-
public Models.Team GetTeam(object overridingParameters = null, string contextValue = null)
134-
=> GetItems<Models.Team>(overridingParameters).FirstOrDefault() ??
133+
public Models.Team GetTeam(bool includeSettings = false, bool includeMembers = false)
134+
=> GetItems<Models.Team>(new {
135+
Team = Parameters.Get<object>("Team", string.Empty),
136+
IncludeSettings = includeSettings,
137+
IncludeMembers = includeMembers,
138+
Default = false
139+
}).FirstOrDefault() ??
135140
throw new ArgumentException("No team information available. Either supply a valid -Team argument or use Connect-TfsTeam prior to invoking this cmdlet.");
136141

137-
public bool TryGetTeam(out WebApiTeam team, object overridingParameters = null)
142+
public bool TryGetTeam(out WebApiTeam team, bool includeSettings = false, bool includeMembers = false)
138143
{
139144
team = null;
140145

141-
try { team = GetItem<Models.Team>(overridingParameters); }
146+
try { team = GetTeam(includeSettings, includeMembers); }
142147
catch { }
143148

144149
return team != null;
@@ -331,4 +336,4 @@ public DataManagerImpl(
331336
CurrentConnections = currentConnections;
332337
}
333338
}
334-
}
339+
}

CSharp/TfsCmdlets.Common/Services/Impl/ParameterManagerImpl.cs

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ public void Initialize(Cmdlet cmdlet)
3333
var value = prop.GetValue(cmdlet);
3434
value = value is PSObject psObject ? psObject.BaseObject : value;
3535

36-
if (value != null) _parameterValues.Add(name, value);
36+
if (value != null || _boundParameters.Contains(name)) _parameterValues.Add(name, value);
3737
}
3838

3939
if (cmdlet is PSCmdlet psCmdlet)
@@ -62,7 +62,7 @@ public T Get<T>(string name, T defaultValue = default)
6262
_ => _parameterValues[name]
6363
};
6464

65-
return (T)val;
65+
return (val is T tVal)? tVal : defaultValue;
6666
}
6767

6868
/// <summary>
@@ -148,11 +148,8 @@ public void PopContext(string contextName = null)
148148
var value = prop.GetValue(overridingParameters);
149149
value = value is PSObject psObject ? psObject.BaseObject : value;
150150

151-
if (value != null)
152-
{
153-
overridden[name] = value;
154-
if (!boundParams.Contains(name)) boundParams.Add(name);
155-
}
151+
overridden[name] = value;
152+
if (!boundParams.Contains(name)) boundParams.Add(name);
156153
}
157154
break;
158155
}

CSharp/TfsCmdlets.Common/Services/Impl/PowerShellServiceImpl.cs

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ public class PowerShellServiceImpl : IPowerShellService
1919
private static PropertyInfo _CurrentCommandProcessor;
2020
private static PropertyInfo _Command;
2121

22-
private CmdletBase Cmdlet
22+
public CmdletBase CurrentCmdlet
2323
{
2424
get
2525
{
@@ -39,22 +39,22 @@ private CmdletBase Cmdlet
3939
}
4040
}
4141

42-
public string CurrentCommand => Cmdlet.DisplayName;
42+
public string CurrentCommand => CurrentCmdlet.DisplayName;
4343

44-
public string CurrentCommandLine => Cmdlet.MyInvocation.Line.Trim();
44+
public string CurrentCommandLine => CurrentCmdlet.MyInvocation.Line.Trim();
4545

46-
public string WindowTitle { get => Cmdlet.Host.UI.RawUI.WindowTitle; set => Cmdlet.Host.UI.RawUI.WindowTitle = value; }
46+
public string WindowTitle { get => CurrentCmdlet.Host.UI.RawUI.WindowTitle; set => CurrentCmdlet.Host.UI.RawUI.WindowTitle = value; }
4747

48-
public PSModuleInfo Module => Cmdlet.MyInvocation.MyCommand.Module;
48+
public PSModuleInfo Module => CurrentCmdlet.MyInvocation.MyCommand.Module;
4949

5050
public void WriteObject(object items, bool enumerateCollection = true)
51-
=> Cmdlet.WriteObject(items, enumerateCollection);
51+
=> CurrentCmdlet.WriteObject(items, enumerateCollection);
5252

5353
public void WriteVerbose(string message)
54-
=> Cmdlet.WriteVerbose(message);
54+
=> CurrentCmdlet.WriteVerbose(message);
5555

5656
public void WriteWarning(string message)
57-
=> Cmdlet.WriteWarning(message);
57+
=> CurrentCmdlet.WriteWarning(message);
5858

5959
public void WriteError(string message)
6060
=> WriteError(new Exception(message));
@@ -63,19 +63,19 @@ public void WriteError(Exception ex)
6363
=> WriteError(new ErrorRecord(ex, "", ErrorCategory.NotSpecified, null));
6464

6565
public void WriteError(ErrorRecord errorRecord)
66-
=> Cmdlet.WriteError(errorRecord);
66+
=> CurrentCmdlet.WriteError(errorRecord);
6767

6868
public IReadOnlyDictionary<string, object> GetBoundParameters()
69-
=> new Dictionary<string, object>(Cmdlet.MyInvocation.BoundParameters);
69+
=> new Dictionary<string, object>(CurrentCmdlet.MyInvocation.BoundParameters);
7070

7171
public object GetVariableValue(string name)
72-
=> Cmdlet.GetVariableValue(name);
72+
=> CurrentCmdlet.GetVariableValue(name);
7373

7474
// public void SetVariableValue(string name, object value)
7575
// => ...;
7676

7777
public bool ShouldProcess(string target, string action)
78-
=> Cmdlet.ShouldProcess(target, action);
78+
=> CurrentCmdlet.ShouldProcess(target, action);
7979

8080
public bool ShouldProcess(Connection collection, string action)
8181
=> ShouldProcess($"{(collection.IsHosted ? "Organization" : "Team Project Collection")} '{collection.DisplayName}'", action);
@@ -87,7 +87,7 @@ public bool ShouldProcess(WebApiTeam t, string action)
8787
=> ShouldProcess($"Team '{t.Name}'", action);
8888

8989
public bool ShouldContinue(string query, string caption = null)
90-
=> Cmdlet.ShouldContinue(query, caption);
90+
=> CurrentCmdlet.ShouldContinue(query, caption);
9191

9292
/// <summary>
9393
/// Executes a PowerShell script in the current session context
@@ -96,7 +96,7 @@ public bool ShouldContinue(string query, string caption = null)
9696
/// <param name="arguments">Arguments passed to the script, represented as an array named <c>$args</c></param>
9797
/// <returns>The output of the script, if any</returns>
9898
public virtual object InvokeScript(string script, params object[] arguments)
99-
=> Cmdlet.InvokeCommand.InvokeScript(script, arguments);
99+
=> CurrentCmdlet.InvokeCommand.InvokeScript(script, arguments);
100100

101101
/// <summary>
102102
/// Executes a PowerShell script in the current session context
@@ -115,17 +115,17 @@ public virtual object InvokeScript(string script, Dictionary<string, object> var
115115
/// <typeparam name="T">The expected type of the objects outputted by the script</typeparam>
116116
/// <returns>The output of the script, if any</returns>
117117
public T InvokeScript<T>(string script, params object[] arguments)
118-
=> (T)Cmdlet.InvokeCommand.InvokeScript(script, arguments)?.FirstOrDefault()?.BaseObject;
118+
=> (T)CurrentCmdlet.InvokeCommand.InvokeScript(script, arguments)?.FirstOrDefault()?.BaseObject;
119119

120120
public object InvokeScript(string script, bool useNewScope, PipelineResultTypes writeToPipeline, IList input, params object[] args)
121-
=> Cmdlet.InvokeCommand.InvokeScript(script, useNewScope, writeToPipeline, input, args);
121+
=> CurrentCmdlet.InvokeCommand.InvokeScript(script, useNewScope, writeToPipeline, input, args);
122122

123123
/// <summary>
124124
/// Gets the current directory in PowerShell
125125
/// </summary>
126126
public string GetCurrentDirectory()
127127
{
128-
return Cmdlet.SessionState.Path.CurrentFileSystemLocation.Path;
128+
return CurrentCmdlet.SessionState.Path.CurrentFileSystemLocation.Path;
129129
}
130130

131131
/// <summary>

0 commit comments

Comments
 (0)