Skip to content

Commit cd4d229

Browse files
authored
Support in-tool notification for version upgrade (#22338)
* support in-tool notification for version upgrade * replace ArgumentException with AzPSArgumentException * update azconfig message and make IClock internal * update help md files for AzConfig
1 parent d47a151 commit cd4d229

File tree

11 files changed

+513
-12
lines changed

11 files changed

+513
-12
lines changed

src/Accounts/Accounts/ChangeLog.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
-->
2020

2121
## Upcoming Release
22+
* Supported in-tool notification for version upgrade.
2223
* Added an alias `Set-AzConfig` to `Update-AzConfig`
2324
* Refilled credentials from `AzKeyStore` when run `Save-AzContext` [#22355]
2425
* Added config `DisableErrorRecordsPersistence` to disable writing error records to file system [#21732]

src/Accounts/Accounts/help/Clear-AzConfig.md

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,9 @@ Clear-AzConfig [-Force] [-PassThru] [-AppliesTo <String>] [-Scope <ConfigScope>]
2121
### ClearByKey
2222
```
2323
Clear-AzConfig [-PassThru] [-AppliesTo <String>] [-Scope <ConfigScope>]
24-
[-DefaultProfile <IAzureContextContainer>] [-WhatIf] [-Confirm] [-DefaultSubscriptionForLogin]
25-
[-DisableErrorRecordsPersistence] [-DisplayBreakingChangeWarning] [-DisplayRegionIdentified]
26-
[-DisplaySurveyMessage] [-EnableDataCollection] [-EnableLoginByWam]
24+
[-DefaultProfile <IAzureContextContainer>] [-WhatIf] [-Confirm] [-CheckForUpgrade]
25+
[-DefaultSubscriptionForLogin] [-DisableErrorRecordsPersistence] [-DisplayBreakingChangeWarning]
26+
[-DisplayRegionIdentified] [-DisplaySurveyMessage] [-EnableDataCollection] [-EnableLoginByWam]
2727
[<CommonParameters>]
2828
```
2929

@@ -70,6 +70,21 @@ Accept pipeline input: False
7070
Accept wildcard characters: False
7171
```
7272
73+
### -CheckForUpgrade
74+
When enabled, Azure PowerShell will check for updates automatically and display a hint message when an update is available. The default value will be changed from false to true in Az version 11.0.0.
75+
76+
```yaml
77+
Type: System.Management.Automation.SwitchParameter
78+
Parameter Sets: ClearByKey
79+
Aliases:
80+
81+
Required: False
82+
Position: Named
83+
Default value: None
84+
Accept pipeline input: False
85+
Accept wildcard characters: False
86+
```
87+
7388
### -DefaultProfile
7489
The credentials, account, tenant, and subscription used for communication with Azure.
7590

src/Accounts/Accounts/help/Get-AzConfig.md

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,9 @@ Gets the configs of Azure PowerShell.
1414

1515
```
1616
Get-AzConfig [-AppliesTo <String>] [-Scope <ConfigScope>] [-DefaultProfile <IAzureContextContainer>]
17-
[-DefaultSubscriptionForLogin] [-DisableErrorRecordsPersistence] [-DisplayBreakingChangeWarning]
18-
[-DisplayRegionIdentified] [-DisplaySurveyMessage] [-EnableDataCollection] [-EnableLoginByWam]
19-
[<CommonParameters>]
17+
[-CheckForUpgrade] [-DefaultSubscriptionForLogin] [-DisableErrorRecordsPersistence]
18+
[-DisplayBreakingChangeWarning] [-DisplayRegionIdentified] [-DisplaySurveyMessage] [-EnableDataCollection]
19+
[-EnableLoginByWam] [<CommonParameters>]
2020
```
2121

2222
## DESCRIPTION
@@ -81,6 +81,21 @@ Accept pipeline input: False
8181
Accept wildcard characters: False
8282
```
8383
84+
### -CheckForUpgrade
85+
When enabled, Azure PowerShell will check for updates automatically and display a hint message when an update is available. The default value will be changed from false to true in Az version 11.0.0.
86+
87+
```yaml
88+
Type: System.Management.Automation.SwitchParameter
89+
Parameter Sets: (All)
90+
Aliases:
91+
92+
Required: False
93+
Position: Named
94+
Default value: None
95+
Accept pipeline input: False
96+
Accept wildcard characters: False
97+
```
98+
8499
### -DefaultProfile
85100
The credentials, account, tenant, and subscription used for communication with Azure.
86101

src/Accounts/Accounts/help/Update-AzConfig.md

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,10 @@ Updates the configs of Azure PowerShell.
1414

1515
```
1616
Update-AzConfig [-AppliesTo <String>] [-Scope <ConfigScope>] [-DefaultProfile <IAzureContextContainer>]
17-
[-WhatIf] [-Confirm] [-DefaultSubscriptionForLogin <String>] [-DisableErrorRecordsPersistence <Boolean>]
18-
[-DisplayBreakingChangeWarning <Boolean>] [-DisplayRegionIdentified <Boolean>]
19-
[-DisplaySurveyMessage <Boolean>] [-EnableDataCollection <Boolean>] [-EnableLoginByWam <Boolean>]
20-
[<CommonParameters>]
17+
[-WhatIf] [-Confirm] [-CheckForUpgrade <Boolean>] [-DefaultSubscriptionForLogin <String>]
18+
[-DisableErrorRecordsPersistence <Boolean>] [-DisplayBreakingChangeWarning <Boolean>]
19+
[-DisplayRegionIdentified <Boolean>] [-DisplaySurveyMessage <Boolean>] [-EnableDataCollection <Boolean>]
20+
[-EnableLoginByWam <Boolean>] [<CommonParameters>]
2121
```
2222

2323
## DESCRIPTION
@@ -93,6 +93,21 @@ Accept pipeline input: False
9393
Accept wildcard characters: False
9494
```
9595
96+
### -CheckForUpgrade
97+
When enabled, Azure PowerShell will check for updates automatically and display a hint message when an update is available. The default value will be changed from false to true in Az version 11.0.0.
98+
99+
```yaml
100+
Type: System.Boolean
101+
Parameter Sets: (All)
102+
Aliases:
103+
104+
Required: False
105+
Position: Named
106+
Default value: None
107+
Accept pipeline input: True (ByPropertyName)
108+
Accept wildcard characters: False
109+
```
110+
96111
### -DefaultProfile
97112
The credentials, account, tenant, and subscription used for communication with Azure.
98113
Lines changed: 237 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,237 @@
1+
using System;
2+
using Xunit;
3+
using System.Linq;
4+
using Microsoft.Azure.Commands.Common.Authentication.Models;
5+
using Microsoft.Azure.Commands.Common.Authentication;
6+
7+
namespace Microsoft.Azure.Authentication.Test.UnitTests
8+
{
9+
class MockClock : IClock
10+
{
11+
public DateTime fakeNow { get; set; }
12+
public bool IsDue(DateTime lastCheckTime, TimeSpan freq)
13+
{
14+
return fakeNow - lastCheckTime >= freq;
15+
}
16+
public void AddSecond(int sec)
17+
{
18+
fakeNow = fakeNow.AddSeconds(sec);
19+
}
20+
}
21+
22+
public class FrequencyServiceTests
23+
{
24+
private FrequencyService _frequencyService;
25+
26+
public FrequencyServiceTests()
27+
{
28+
_frequencyService = new FrequencyService(new MemoryDataStore(), new Clock());
29+
}
30+
31+
[Fact]
32+
public void TestAdd()
33+
{
34+
// Arrange
35+
string featureName = "TestFeature";
36+
TimeSpan frequency = new TimeSpan(0, 0, 5); // 5 seconds
37+
38+
// Act
39+
_frequencyService.Register(featureName, frequency);
40+
41+
// Assert
42+
var frequencyInfo = new FrequencyService.FrequencyInfo(frequency, DateTime.Now);
43+
Assert.NotNull(frequencyInfo);
44+
Assert.Equal(frequency, frequencyInfo.Frequency);
45+
}
46+
47+
[Fact]
48+
public void TestAddSession()
49+
{
50+
string featureName = "testFeature";
51+
_frequencyService.RegisterInSession(featureName);
52+
53+
Assert.True(_frequencyService.SessionLogic.ContainsKey(featureName));
54+
Assert.False(_frequencyService.SessionLogic[featureName]);
55+
}
56+
57+
[Fact]
58+
public void TestCheck_SessionLogic()
59+
{
60+
string featureName = "testFeature";
61+
_frequencyService.RegisterInSession(featureName);
62+
63+
bool businessCheck = true;
64+
bool businessCalled = false;
65+
_frequencyService.TryRun(featureName, () => businessCheck, () => businessCalled = true);
66+
67+
Assert.True(businessCalled);
68+
Assert.True(_frequencyService.SessionLogic[featureName]);
69+
}
70+
71+
[Fact]
72+
public void TestCheck_Frequencies()
73+
{
74+
string featureName = "testFeature";
75+
TimeSpan frequency = new TimeSpan(0, 0, 1);
76+
_frequencyService.Register(featureName, frequency);
77+
78+
bool businessCheck = true;
79+
bool businessCalled = false;
80+
_frequencyService.TryRun(featureName, () => businessCheck, () => businessCalled = true);
81+
82+
Assert.True(businessCalled);
83+
}
84+
85+
[Fact]
86+
public void AddsFeatureToFrequencyService()
87+
{
88+
// Arrange
89+
var featureName = "MyFeature";
90+
var frequency = TimeSpan.FromMinutes(5);
91+
92+
// Act
93+
_frequencyService.Register(featureName, frequency);
94+
95+
// Assert
96+
Assert.NotNull(_frequencyService);
97+
Assert.NotNull(_frequencyService.GetAllFeatureNames());
98+
Assert.Contains(featureName, _frequencyService.GetAllFeatureNames());
99+
}
100+
101+
[Fact]
102+
public void DoesNotAddDuplicateToFrequencyService()
103+
{
104+
// Arrange
105+
var featureName = "MyFeature1";
106+
var frequency = TimeSpan.FromMinutes(5);
107+
108+
// Act
109+
_frequencyService.Register(featureName, frequency);
110+
_frequencyService.Register(featureName, frequency);
111+
112+
// Assert
113+
Assert.Equal(1, _frequencyService.GetAllFeatureNames().Count(n => n == featureName));
114+
}
115+
116+
[Fact]
117+
public void AddsSessionFeatureToFrequencyService()
118+
{
119+
// Arrange
120+
var featureName = "MySessionFeature";
121+
122+
// Act
123+
_frequencyService.RegisterInSession(featureName);
124+
125+
// Assert
126+
Assert.Contains(featureName, _frequencyService.GetAllFeatureNames());
127+
}
128+
129+
[Fact]
130+
public void DoesNotAddDuplicateSessionToFrequencyService()
131+
{
132+
// Arrange
133+
var frequencyService = new FrequencyService(new MemoryDataStore(), new Clock());
134+
var featureName = "MySessionFeature";
135+
136+
// Act
137+
frequencyService.RegisterInSession(featureName);
138+
frequencyService.RegisterInSession(featureName);
139+
140+
// Assert
141+
Assert.Equal(1, frequencyService.GetAllFeatureNames().Count(n => n == featureName));
142+
}
143+
144+
[Fact]
145+
public void Check_FrequencyMet_ExecuteBusinessLogic()
146+
{
147+
// Arrange
148+
var frequencyService = new FrequencyService(new MemoryDataStore(), new Clock());
149+
var featureName = "MyFeature2";
150+
var frequency = TimeSpan.FromMinutes(5);
151+
var businessLogicExecuted = false;
152+
frequencyService.Register(featureName, frequency);
153+
154+
// Act
155+
frequencyService.TryRun(featureName, () => true, () => businessLogicExecuted = true);
156+
157+
// Assert
158+
Assert.True(businessLogicExecuted);
159+
}
160+
161+
[Fact]
162+
public void Check_FrequencyNotMet_DoesNotExecuteBusinessLogic()
163+
{
164+
// Arrange
165+
var frequencyService = new FrequencyService(new MemoryDataStore());
166+
var featureName = "MyFeature3";
167+
var frequency = TimeSpan.FromMinutes(5);
168+
var businessLogicExecuted = false;
169+
frequencyService.Register(featureName, frequency);
170+
171+
// Act
172+
frequencyService.TryRun(featureName, () => false, () => businessLogicExecuted = true);
173+
174+
// Assert
175+
Assert.False(businessLogicExecuted);
176+
}
177+
178+
[Fact]
179+
public void Check_SessionFeatureFirstTime_ExecuteBusinessLogic()
180+
{
181+
// Arrange
182+
var frequencyService = new FrequencyService(new MemoryDataStore(), new Clock());
183+
var featureName = "MySessionFeature";
184+
var businessLogicExecuted = false;
185+
frequencyService.RegisterInSession(featureName);
186+
187+
// Act
188+
frequencyService.TryRun(featureName, () => true, () => businessLogicExecuted = true);
189+
190+
// Assert
191+
Assert.True(businessLogicExecuted);
192+
}
193+
194+
[Fact]
195+
public void Check_SessionFeatureSecondTime_DoesNotExecuteBusinessLogic()
196+
{
197+
// Arrange
198+
var frequencyService = new FrequencyService(new MemoryDataStore(), new Clock());
199+
var featureName = "MySessionFeature";
200+
var businessLogicExecuted = false;
201+
frequencyService.RegisterInSession(featureName);
202+
203+
// Act
204+
frequencyService.TryRun(featureName, () => true, () => businessLogicExecuted = true);
205+
frequencyService.TryRun(featureName, () => true, () => businessLogicExecuted = false);
206+
207+
// Assert
208+
Assert.True(businessLogicExecuted);
209+
}
210+
211+
[Fact]
212+
public void Check_Frequency_Logic()
213+
{
214+
var frequencyService = new FrequencyService(new MemoryDataStore(), new MockClock());
215+
var featureName = "MyFeature4";
216+
var frequency = TimeSpan.FromSeconds(1);
217+
int businessValue = 13;
218+
frequencyService.Register(featureName, frequency);
219+
220+
((MockClock)frequencyService._clock).fakeNow = DateTime.Now;
221+
frequencyService.Check(featureName, () => true, () => businessValue = 100, DateTime.Now);
222+
Assert.Equal(100, businessValue);
223+
224+
((MockClock)frequencyService._clock).AddSecond(2);
225+
frequencyService.Check(featureName, () => true, () => businessValue = -100, ((MockClock)frequencyService._clock).fakeNow);
226+
Assert.Equal(-100, businessValue);
227+
228+
frequencyService.Check(featureName, () => true, () => businessValue = 16, ((MockClock)frequencyService._clock).fakeNow);
229+
Assert.Equal(-100, businessValue);
230+
231+
232+
((MockClock)frequencyService._clock).AddSecond(2);
233+
frequencyService.Check(featureName, () => true, () => businessValue = 17, ((MockClock)frequencyService._clock).fakeNow);
234+
Assert.Equal(17, businessValue);
235+
}
236+
}
237+
}

src/Accounts/Authentication/AzureSessionInitializer.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
using Microsoft.WindowsAzure.Commands.Utilities.Common;
3636
using Microsoft.Azure.Commands.Common.Authentication.Utilities;
3737
using Microsoft.WindowsAzure.Commands.Common.Utilities;
38+
using Microsoft.WindowsAzure.Commands.Common;
3839

3940
namespace Microsoft.Azure.Commands.Common.Authentication
4041
{
@@ -282,6 +283,8 @@ static IAzureSession CreateInstance(IDataStore dataStore = null, Action<string>
282283
() => new DefaultRecommendationService());
283284
session.RegisterComponent<IParameterTelemetryFormatter>(nameof(IParameterTelemetryFormatter),
284285
() => new ParameterTelemetryFormatter());
286+
session.RegisterComponent<IFrequencyService>(nameof(IFrequencyService),
287+
() => new FrequencyService(dataStore));
285288
session.TokenCache = session.TokenCache ?? new AzureTokenCache();
286289
return session;
287290
}

src/Accounts/Authentication/Config/ConfigInitializer.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,12 @@ private void RegisterConfigs(IConfigManager configManager)
203203
false,
204204
string.Format("AzPS{0}", ConfigKeys.DisableErrorRecordsPersistence),
205205
new[] { AppliesTo.Az }));
206+
configManager.RegisterConfig(new SimpleTypedConfig<bool>(
207+
ConfigKeys.CheckForUpgrade,
208+
Resources.HelpMessageOfCheckForUpgrade,
209+
false,
210+
ConfigKeys.EnvCheckForUpgrade,
211+
new[] { AppliesTo.Az }));
206212
#if DEBUG || TESTCOVERAGE
207213
configManager.RegisterConfig(new SimpleTypedConfig<bool>(
208214
ConfigKeys.EnableTestCoverage,

0 commit comments

Comments
 (0)