Skip to content

Commit 48d9590

Browse files
committed
Add a scenario test for Move and Set. Accept legacy property object. Fix an issue with Gallery client
1 parent 75eb0fe commit 48d9590

File tree

23 files changed

+1823
-31
lines changed

23 files changed

+1823
-31
lines changed

src/Common/Commands.ScenarioTests.Common/PowerShellExtensions.cs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -206,7 +206,10 @@ private static void LogPowerShellStream<T>(ICollection<T> stream, string name)
206206
Console.WriteLine("---------------------------------------------------------------\n");
207207
foreach (T item in stream)
208208
{
209-
Console.WriteLine("{0}\n", item.ToString());
209+
if(item != null)
210+
{
211+
Console.WriteLine("{0}\n", item.ToString());
212+
}
210213
}
211214
Console.WriteLine("---------------------------------------------------------------\n");
212215
Console.WriteLine("");

src/ResourceManager/ResourceManager/Commands.ResourceManager/Cmdlets/Commands.ResourceManager.Cmdlets.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,7 @@
109109
<Compile Include="Entities\Providers\ResourceTypeDefinition.cs" />
110110
<Compile Include="Entities\ResourceGroup\ResourceBatchMoveParameters.cs" />
111111
<Compile Include="Entities\Resources\Resource.cs" />
112+
<Compile Include="Entities\Resources\ResourceObjectFormat.cs" />
112113
<Compile Include="Entities\Resources\ResourcePlan.cs" />
113114
<Compile Include="Entities\Resources\TerminalProvisioningStates.cs" />
114115
<Compile Include="Extensions\AsyncExtensions.cs" />
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
// ----------------------------------------------------------------------------------
2+
//
3+
// Copyright Microsoft Corporation
4+
// Licensed under the Apache License, Version 2.0 (the "License");
5+
// you may not use this file except in compliance with the License.
6+
// You may obtain a copy of the License at
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
// Unless required by applicable law or agreed to in writing, software
9+
// distributed under the License is distributed on an "AS IS" BASIS,
10+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11+
// See the License for the specific language governing permissions and
12+
// limitations under the License.
13+
// ----------------------------------------------------------------------------------
14+
15+
namespace Microsoft.Azure.Commands.ResourceManager.Cmdlets.Entities.Resources
16+
{
17+
/// <summary>
18+
/// The resource object format
19+
/// </summary>
20+
public enum ResourceObjectFormat
21+
{
22+
/// <summary>
23+
/// The legacy format.
24+
/// </summary>
25+
Legacy = 0,
26+
27+
/// <summary>
28+
/// The new format.
29+
/// </summary>
30+
New = 1
31+
}
32+
}

src/ResourceManager/ResourceManager/Commands.ResourceManager/Cmdlets/Extensions/JTokenExtensions.cs

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -49,8 +49,9 @@ internal static class JTokenExtensions
4949
/// Converts a <see cref="JObject"/> to a <see cref="PSObject"/>
5050
/// </summary>
5151
/// <param name="jtoken">The <see cref="JObject"/></param>
52+
/// <param name="objectFormat">The <see cref="ResourceObjectFormat"/></param>
5253
/// <param name="objectType">The type of the object.</param>
53-
internal static PSObject ToPsObject(this JToken jtoken, string objectType = null)
54+
internal static PSObject ToPsObject(this JToken jtoken, ResourceObjectFormat objectFormat, string objectType = null)
5455
{
5556
if (jtoken == null)
5657
{
@@ -59,15 +60,15 @@ internal static PSObject ToPsObject(this JToken jtoken, string objectType = null
5960

6061
if (jtoken.Type != JTokenType.Object)
6162
{
62-
return new PSObject(JTokenExtensions.ConvertPropertyValueForPsObject(propertyValue: jtoken));
63+
return new PSObject(JTokenExtensions.ConvertPropertyValueForPsObject(propertyValue: jtoken, objectFormat: objectFormat));
6364
}
6465

6566
var jobject = (JObject)jtoken;
6667
var psObject = new PSObject();
6768

6869
if (jobject.CanConvertTo<Resource<JToken>>())
6970
{
70-
return jobject.ToResource().ToPsObject();
71+
return jobject.ToResource().ToPsObject(objectFormat);
7172
}
7273

7374
if (!string.IsNullOrWhiteSpace(objectType))
@@ -79,7 +80,7 @@ internal static PSObject ToPsObject(this JToken jtoken, string objectType = null
7980
{
8081
psObject.Properties.Add(new PSNoteProperty(
8182
name: JTokenExtensions.ConvertToPascalCase(propertyName: property.Name),
82-
value: JTokenExtensions.ConvertPropertyValueForPsObject(propertyValue: property.Value)));
83+
value: JTokenExtensions.ConvertPropertyValueForPsObject(propertyValue: property.Value, objectFormat: objectFormat)));
8384
}
8485

8586
return psObject;
@@ -90,11 +91,12 @@ internal static PSObject ToPsObject(this JToken jtoken, string objectType = null
9091
/// used as the value of a <see cref="PSNoteProperty"/>.
9192
/// </summary>
9293
/// <param name="propertyValue">The <see cref="JToken"/> value.</param>
93-
internal static object ConvertPropertyValueForPsObject(JToken propertyValue)
94+
/// <param name="objectFormat">The <see cref="ResourceObjectFormat"/></param>
95+
internal static object ConvertPropertyValueForPsObject(JToken propertyValue, ResourceObjectFormat objectFormat)
9496
{
9597
if (propertyValue.Type == JTokenType.Object)
9698
{
97-
return propertyValue.ToPsObject();
99+
return propertyValue.ToPsObject(objectFormat);
98100
}
99101

100102
if (propertyValue.Type == JTokenType.Array)
@@ -105,7 +107,7 @@ internal static object ConvertPropertyValueForPsObject(JToken propertyValue)
105107

106108
for (int i = 0; i < array.Length; ++i)
107109
{
108-
array[i] = JTokenExtensions.ConvertPropertyValueForPsObject(jArray[i]);
110+
array[i] = JTokenExtensions.ConvertPropertyValueForPsObject(jArray[i], objectFormat);
109111
}
110112

111113
return array;

src/ResourceManager/ResourceManager/Commands.ResourceManager/Cmdlets/Extensions/PsObjectExtensions.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,9 +67,9 @@ private static JToken ToJToken(object value)
6767
if (valueAsPsObject != null)
6868
{
6969
JObject obj = new JObject();
70-
if (valueAsPsObject.TypeNames.Any(typeName => typeName.EqualsInsensitively("System.Collections.Hashtable")) && valueAsPsObject.BaseObject is Hashtable)
70+
if (valueAsPsObject.BaseObject != null && valueAsPsObject.BaseObject is IDictionary)
7171
{
72-
foreach (var dictionaryEntry in ((Hashtable)valueAsPsObject.BaseObject).OfType<DictionaryEntry>())
72+
foreach (var dictionaryEntry in ((IDictionary)valueAsPsObject.BaseObject).OfType<DictionaryEntry>())
7373
{
7474
obj.Add(dictionaryEntry.Key.ToString(), PsObjectExtensions.ToJToken(dictionaryEntry.Value));
7575
}

src/ResourceManager/ResourceManager/Commands.ResourceManager/Cmdlets/Extensions/ResourceExtensions.cs

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ namespace Microsoft.Azure.Commands.ResourceManager.Cmdlets.Extensions
1919
using System.Management.Automation;
2020
using Microsoft.Azure.Commands.ResourceManager.Cmdlets.Components;
2121
using Microsoft.Azure.Commands.ResourceManager.Cmdlets.Entities.Resources;
22+
using Microsoft.Azure.Common.Authentication;
2223
using Microsoft.WindowsAzure.Commands.Utilities.Common;
2324
using Newtonsoft.Json.Linq;
2425

@@ -31,7 +32,8 @@ internal static class ResourceExtensions
3132
/// Converts a <see cref="Resource{JToken}"/> object into a <see cref="PSObject"/> object.
3233
/// </summary>
3334
/// <param name="resource">The <see cref="Resource{JToken}"/> object.</param>
34-
internal static PSObject ToPsObject(this Resource<JToken> resource)
35+
/// <param name="objectFormat">The <see cref="ResourceObjectFormat"/></param>
36+
internal static PSObject ToPsObject(this Resource<JToken> resource, ResourceObjectFormat objectFormat)
3537
{
3638
var resourceType = ResourceIdUtility.GetResourceType(resource.Id);
3739
var extensionResourceType = ResourceIdUtility.GetExtensionResourceType(resource.Id);
@@ -49,8 +51,8 @@ internal static PSObject ToPsObject(this Resource<JToken> resource)
4951
{ "Location", resource.Location },
5052
{ "SubscriptionId", ResourceIdUtility.GetSubscriptionId(resource.Id) },
5153
{ "Tags", TagsHelper.GetTagsHashtables(resource.Tags) },
52-
{ "Plan", resource.Plan.ToJToken().ToPsObject() },
53-
{ "Properties", resource.Properties.ToPsObject() },
54+
{ "Plan", resource.Plan.ToJToken().ToPsObject(objectFormat) },
55+
{ "Properties", ResourceExtensions.GetProperties(resource, objectFormat) },
5456
{ "CreatedTime", resource.CreatedTime },
5557
{ "ChangedTime", resource.ChangedTime },
5658
{ "ETag", resource.ETag },
@@ -64,6 +66,23 @@ internal static PSObject ToPsObject(this Resource<JToken> resource)
6466
return psObject;
6567
}
6668

69+
/// <summary>
70+
/// Gets the properties object
71+
/// </summary>
72+
/// <param name="resource">The <see cref="Resource{JToken}"/> object.</param>
73+
/// <param name="objectFormat">The <see cref="ResourceObjectFormat"/></param>
74+
private static object GetProperties(Resource<JToken> resource, ResourceObjectFormat objectFormat)
75+
{
76+
if (resource.Properties == null)
77+
{
78+
return null;
79+
}
80+
81+
return objectFormat == ResourceObjectFormat.Legacy
82+
? JsonUtilities.DeserializeJson(resource.Properties.ToString())
83+
: (object)resource.Properties.ToPsObject(objectFormat);
84+
}
85+
6786
/// <summary>
6887
/// Converts a <see cref="JToken"/> to a <see cref="Resource{JToken}"/>.
6988
/// </summary>

src/ResourceManager/ResourceManager/Commands.ResourceManager/Cmdlets/Extensions/StringExtensions.cs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,16 @@ public static bool EqualsInsensitively(this string original, string otherString)
4242
return string.Equals(original, otherString, StringComparison.InvariantCultureIgnoreCase);
4343
}
4444

45+
/// <summary>
46+
/// Compares two string values insensitively.
47+
/// </summary>
48+
/// <param name="original">The original string.</param>
49+
/// <param name="otherString">The other string.</param>
50+
public static bool StartsWithInsensitively(this string original, string otherString)
51+
{
52+
return original.CoalesceString().StartsWith(otherString.CoalesceString(), StringComparison.InvariantCultureIgnoreCase);
53+
}
54+
4555
/// <summary>
4656
/// Splits the string with given separators and removes empty entries.
4757
/// </summary>

src/ResourceManager/ResourceManager/Commands.ResourceManager/Cmdlets/Implementation/GetAzureResourceCmdlet.cs

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,20 @@ public sealed class GetAzureResourceCmdlet : ResourceManagerCmdletBase
212212
[Parameter(ParameterSetName = GetAzureResourceCmdlet.ListTenantResourcesParameterSet, Mandatory = true, HelpMessage = "Indicates that this is a tenant level operation.")]
213213
public SwitchParameter TenantLevel { get; set; }
214214

215+
/// <summary>
216+
/// Gets or sets the resource property object format.
217+
/// </summary>
218+
[Parameter(Mandatory = false, HelpMessage = "The output format of the resource properties.")]
219+
public ResourceObjectFormat OutputObjectFormat { get; set; }
220+
221+
/// <summary>
222+
/// Initializes a new instance of the <see cref="GetAzureResourceCmdlet" /> class.
223+
/// </summary>
224+
public GetAzureResourceCmdlet()
225+
{
226+
this.OutputObjectFormat = ResourceObjectFormat.Legacy;
227+
}
228+
215229
/// <summary>
216230
/// Collects subscription ids from the pipeline.
217231
/// </summary>
@@ -242,6 +256,11 @@ protected override void OnEndProcessing()
242256
/// </summary>
243257
private void RunCmdlet()
244258
{
259+
if(this.OutputObjectFormat == ResourceObjectFormat.Legacy)
260+
{
261+
this.WriteWarning("This cmdlet is using the legacy properties object format. This format is being deprecated. Please use '-OutputObjectFormat New' and update your scripts.");
262+
}
263+
245264
PaginatedResponseHelper.ForEach(
246265
getFirstPage: () => this.GetResources(),
247266
getNextPage: nextLink => this.GetNextLink<JObject>(nextLink),
@@ -261,7 +280,7 @@ private void RunCmdlet()
261280
items = this.GetPopulatedResource(batch).Result;
262281
}
263282

264-
var powerShellObjects = items.SelectArray(genericResource => genericResource.ToPsObject());
283+
var powerShellObjects = items.SelectArray(genericResource => genericResource.ToPsObject(this.OutputObjectFormat));
265284
if (this.ExpandPermissions)
266285
{
267286
this.PopulatePermissions(powerShellObjects).Wait();
@@ -272,7 +291,7 @@ private void RunCmdlet()
272291
}
273292
else
274293
{
275-
this.WriteObject(sendToPipeline: resources.CoalesceEnumerable().SelectArray(res => res.ToPsObject()), enumerateCollection: true);
294+
this.WriteObject(sendToPipeline: resources.CoalesceEnumerable().SelectArray(res => res.ToPsObject(this.OutputObjectFormat)), enumerateCollection: true);
276295
}
277296
});
278297

src/ResourceManager/ResourceManager/Commands.ResourceManager/Cmdlets/Implementation/GetAzureResourceGroupDeploymentOperationCmdlet.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ namespace Microsoft.Azure.Commands.ResourceManager.Cmdlets.Implementation
1818
using System.Management.Automation;
1919
using System.Threading.Tasks;
2020
using Microsoft.Azure.Commands.ResourceManager.Cmdlets.Components;
21+
using Microsoft.Azure.Commands.ResourceManager.Cmdlets.Entities.Resources;
2122
using Microsoft.Azure.Commands.ResourceManager.Cmdlets.Extensions;
2223
using Newtonsoft.Json.Linq;
2324

@@ -73,7 +74,7 @@ private void RunCmdlet()
7374
getFirstPage: () => this.GetResources(),
7475
getNextPage: nextLink => this.GetNextLink<JObject>(nextLink),
7576
cancellationToken: this.CancellationToken,
76-
action: resources => this.WriteObject(sendToPipeline: resources.CoalesceEnumerable().SelectArray(resource => resource.ToPsObject()), enumerateCollection: true));
77+
action: resources => this.WriteObject(sendToPipeline: resources.CoalesceEnumerable().SelectArray(resource => resource.ToPsObject(ResourceObjectFormat.New)), enumerateCollection: true));
7778
}
7879

7980
/// <summary>

src/ResourceManager/ResourceManager/Commands.ResourceManager/Cmdlets/Implementation/GetAzureResourceLockCmdlet.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ namespace Microsoft.Azure.Commands.ResourceManager.Cmdlets.Implementation
1717
using System.Management.Automation;
1818
using System.Threading.Tasks;
1919
using Microsoft.Azure.Commands.ResourceManager.Cmdlets.Components;
20+
using Microsoft.Azure.Commands.ResourceManager.Cmdlets.Entities.Resources;
2021
using Microsoft.Azure.Commands.ResourceManager.Cmdlets.Extensions;
2122
using Newtonsoft.Json.Linq;
2223

@@ -79,7 +80,7 @@ private void RunCmdlet()
7980
getFirstPage: () => this.GetResources(),
8081
getNextPage: nextLink => this.GetNextLink<JObject>(nextLink),
8182
cancellationToken: this.CancellationToken,
82-
action: resources => this.WriteObject(sendToPipeline: resources.CoalesceEnumerable().SelectArray(resource => resource.ToPsObject()), enumerateCollection: true));
83+
action: resources => this.WriteObject(sendToPipeline: resources.CoalesceEnumerable().SelectArray(resource => resource.ToPsObject(ResourceObjectFormat.New)), enumerateCollection: true));
8384
}
8485

8586
/// <summary>

src/ResourceManager/ResourceManager/Commands.ResourceManager/Cmdlets/Implementation/InvokeAzureResourceActionCmdlet.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ namespace Microsoft.Azure.Commands.ResourceManager.Cmdlets.Implementation
1616
{
1717
using System.Collections;
1818
using System.Management.Automation;
19+
using Microsoft.Azure.Commands.ResourceManager.Cmdlets.Entities.Resources;
1920
using Microsoft.Azure.Commands.ResourceManager.Cmdlets.Extensions;
2021
using Microsoft.WindowsAzure.Commands.Common;
2122
using Newtonsoft.Json.Linq;
@@ -82,7 +83,7 @@ protected override void OnProcessRecord()
8283
var result = this.GetLongRunningOperationTracker(activityName: activity, isResourceCreateOrUpdate: false)
8384
.WaitOnOperation(operationResult: operationResult);
8485

85-
this.WriteObject(result);
86+
this.WriteObject(result, ResourceObjectFormat.New);
8687
});
8788
}
8889

src/ResourceManager/ResourceManager/Commands.ResourceManager/Cmdlets/Implementation/MoveAzureResourceCmdlet.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ namespace Microsoft.Azure.Commands.ResourceManager.Cmdlets.Implementation
2020
using System.Management.Automation;
2121
using Microsoft.Azure.Commands.ResourceManager.Cmdlets.Components;
2222
using Microsoft.Azure.Commands.ResourceManager.Cmdlets.Entities.ResourceGroups;
23+
using Microsoft.Azure.Commands.ResourceManager.Cmdlets.Entities.Resources;
2324
using Microsoft.Azure.Commands.ResourceManager.Cmdlets.Extensions;
2425
using Newtonsoft.Json.Linq;
2526

@@ -172,7 +173,7 @@ private void RunCmdlet()
172173
isResourceCreateOrUpdate: false)
173174
.WaitOnOperation(operationResult: operationResult);
174175

175-
this.WriteObject(result);
176+
this.WriteObject(result, ResourceObjectFormat.New);
176177
}
177178
else
178179
{

src/ResourceManager/ResourceManager/Commands.ResourceManager/Cmdlets/Implementation/NewAzureResourceCmdlet.cs

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -46,10 +46,10 @@ public sealed class NewAzureResourceCmdlet : ResourceManipulationCmdletBase
4646
/// <summary>
4747
/// Gets or sets the property object.
4848
/// </summary>
49-
[Alias("Object")]
49+
[Alias("Object", "PropertyObject")]
5050
[Parameter(Mandatory = true, HelpMessage = "A hash table which represents resource properties.")]
5151
[ValidateNotNullOrEmpty]
52-
public Hashtable PropertyObject { get; set; }
52+
public PSObject Properties { get; set; }
5353

5454
/// <summary>
5555
/// Gets or sets the plan object.
@@ -71,6 +71,20 @@ public sealed class NewAzureResourceCmdlet : ResourceManipulationCmdletBase
7171
[Parameter(Mandatory = false, HelpMessage = "When set indicates that the full object is passed in to the -PropertyObject parameter.")]
7272
public SwitchParameter IsFullObject { get; set; }
7373

74+
/// <summary>
75+
/// Gets or sets the resource property object format.
76+
/// </summary>
77+
[Parameter(Mandatory = false, HelpMessage = "The output format of the resource properties.")]
78+
public ResourceObjectFormat OutputObjectFormat { get; set; }
79+
80+
/// <summary>
81+
/// Initializes a new instance of the <see cref="NewAzureResourceCmdlet" /> class.
82+
/// </summary>
83+
public NewAzureResourceCmdlet()
84+
{
85+
this.OutputObjectFormat = ResourceObjectFormat.Legacy;
86+
}
87+
7488
/// <summary>
7589
/// Executes the cmdlet.
7690
/// </summary>
@@ -109,7 +123,7 @@ protected override void OnProcessRecord()
109123
var result = this.GetLongRunningOperationTracker(activityName: activity, isResourceCreateOrUpdate: true)
110124
.WaitOnOperation(operationResult: operationResult);
111125

112-
this.WriteObject(result);
126+
this.WriteObject(result, this.OutputObjectFormat);
113127
});
114128
}
115129

@@ -119,22 +133,22 @@ protected override void OnProcessRecord()
119133
private JToken GetResourceBody()
120134
{
121135
return this.IsFullObject
122-
? this.PropertyObject.ToDictionary(addValueLayer: false).ToJToken()
136+
? this.Properties.ToResourcePropertiesBody().ToJToken()
123137
: this.GetResource().ToJToken();
124138
}
125139

126140
/// <summary>
127141
/// Constructs the resource assuming that only the properties were passed in.
128142
/// </summary>
129-
private Resource<Dictionary<string, object>> GetResource()
143+
private Resource<JToken> GetResource()
130144
{
131-
return new Resource<Dictionary<string, object>>()
145+
return new Resource<JToken>()
132146
{
133147
Location = this.Location,
134148
Kind = this.Kind,
135149
Plan = this.PlanObject.ToDictionary(addValueLayer: false).ToJson().FromJson<ResourcePlan>(),
136150
Tags = TagsHelper.GetTagsDictionary(this.Tag),
137-
Properties = this.PropertyObject.ToDictionary(addValueLayer: false),
151+
Properties = this.Properties.ToResourcePropertiesBody(),
138152
};
139153
}
140154

0 commit comments

Comments
 (0)