Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions ReadMe.md
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,20 @@ Possible values for the `-AutomaticallyWritePowerShellTip` parameter are `Never`
Tips will only be automatically shown in interactive PowerShell sessions.
This prevents them from appearing unexpectedly when running scripts or other automated processes.

#### Do not show the same tips twice

By default, tiPS will cycle through all available tips, so once all tips have been shown it will restart and display them again.
If you prefer to only see tips that haven't been shown before, you can configure tiPS to only show unshown tips by running:

```powershell
Set-TiPSConfiguration -AllTipsShownBehaviour DoNotShowTips
```

Possible values for the `-AllTipsShownBehaviour` parameter are `ClearShownTipsList` (default) and `DoNotShowTips`.

When `DoNotShowTips` is used, tiPS will only automatically display a tip if there are tips that have not been shown yet.
Once all tips have been shown, no more tips will be displayed until new tips are added (by updating the module).

### ⬆️ Automatic updates

New tips are obtained by updating the tiPS module.
Expand Down
8 changes: 8 additions & 0 deletions src/CSharpClasses/tiPSClasses/Configuration.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,17 +26,25 @@ public enum TipRetrievalOrder
Random = 2
}

public enum AllTipsShownBehaviours
{
ClearShownTipsList = 0,
DoNotShowTips = 1
}

public class Configuration
{
public ModuleAutoUpdateCadence AutoUpdateCadence { get; set; }
public WritePowerShellTipCadence AutoWritePowerShellTipCadence { get; set; }
public TipRetrievalOrder TipRetrievalOrder { get; set; }
public AllTipsShownBehaviours AllTipsShownBehaviour { get; set; }

public Configuration()
{
AutoUpdateCadence = ModuleAutoUpdateCadence.Never;
AutoWritePowerShellTipCadence = WritePowerShellTipCadence.Never;
TipRetrievalOrder = TipRetrievalOrder.NewestFirst;
AllTipsShownBehaviour = AllTipsShownBehaviours.ClearShownTipsList;
}
}
}
71 changes: 71 additions & 0 deletions src/tiPS/Private/AutomaticWritePowerShellTipFunctions.Tests.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,30 @@ InModuleScope -ModuleName tiPS { # Must use InModuleScope to call private functi
Assert-MockCalled WriteAutomaticPowerShellTip -Times 0 -Exactly
}
}

Context 'When the AllTipsShownBehaviour is DoNotShowTips' {
It 'Should show a tip when there are unseen tips' {
$config = [tiPS.Configuration]::new()
$config.AutoWritePowerShellTipCadence = [tiPS.WritePowerShellTipCadence]::EverySession
$config.AllTipsShownBehaviour = [tiPS.AllTipsShownBehaviours]::DoNotShowTips
Mock -CommandName TestIfUnseenTipsExist -MockWith { return $true }

WriteAutomaticPowerShellTipIfNeeded -Config $config

Assert-MockCalled WriteAutomaticPowerShellTip -Times 1 -Exactly
}

It 'Should not show a tip when all tips have been shown' {
$config = [tiPS.Configuration]::new()
$config.AutoWritePowerShellTipCadence = [tiPS.WritePowerShellTipCadence]::EverySession
$config.AllTipsShownBehaviour = [tiPS.AllTipsShownBehaviours]::DoNotShowTips
Mock -CommandName TestIfUnseenTipsExist -MockWith { return $false }

WriteAutomaticPowerShellTipIfNeeded -Config $config

Assert-MockCalled WriteAutomaticPowerShellTip -Times 0 -Exactly
}
}
}

Describe 'Calling WriteLastAutomaticTipWrittenDate' {
Expand All @@ -164,4 +188,51 @@ InModuleScope -ModuleName tiPS { # Must use InModuleScope to call private functi
$lastAutomaticTipWrittenDate | Should -Be $today
}
}

Describe 'Calling TestIfUnseenTipsExist' {
BeforeEach {
# Use a temp configuration data directory instead of reading/overwriting the current user's configuration.
Mock -CommandName Get-TiPSDataDirectoryPath -MockWith {
[string] $directoryPath = "$TestDrive/tiPS" # Use $TestDrive variable so .NET methods can resolve the path.
if (-not (Test-Path -Path $directoryPath -PathType Container))
{
New-Item -Path $directoryPath -ItemType Directory -Force > $null
}
return $directoryPath
}
}

It 'Should return true when no tips have been shown yet' {
# Ensure the file is empty
ClearTipIdsAlreadyShown

$result = TestIfUnseenTipsExist

$result | Should -Be $true
}

It 'Should return true when some tips have been shown but not all' {
# Get all tips and mark only one as shown
[hashtable] $allTips = ReadAllPowerShellTipsFromJsonFile
[string] $firstTipId = $allTips.Keys | Select-Object -First 1
AppendTipIdToTipIdsAlreadyShown -TipId $firstTipId

$result = TestIfUnseenTipsExist

$result | Should -Be $true
}

It 'Should return false when all tips have been shown' {
# Mark all tips as shown
[hashtable] $allTips = ReadAllPowerShellTipsFromJsonFile
foreach ($tipId in $allTips.Keys)
{
AppendTipIdToTipIdsAlreadyShown -TipId $tipId
}

$result = TestIfUnseenTipsExist

$result | Should -Be $false
}
}
}
34 changes: 34 additions & 0 deletions src/tiPS/Private/AutomaticWritePowerShellTipFunctions.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,12 @@ function WriteAutomaticPowerShellTipIfNeeded
([tiPS.WritePowerShellTipCadence]::Monthly) { $shouldShowTip = $daysSinceLastAutomaticTipWritten -ge 30; break }
}

# If the cadence says we should show a tip, check if we should only show unseen tips
if ($shouldShowTip -and $Config.AllTipsShownBehaviour -eq [tiPS.AllTipsShownBehaviours]::DoNotShowTips)
{
$shouldShowTip = TestIfUnseenTipsExist
}

if ($shouldShowTip)
{
[bool] $isSessionInteractive = TestPowerShellSessionIsInteractive
Expand Down Expand Up @@ -137,3 +143,31 @@ function GetLastAutomaticTipWrittenDateFilePath
[string] $lastAutomaticTipWrittenDateFilePath = Join-Path -Path $appDataDirectoryPath -ChildPath 'LastAutomaticTipWrittenDate.txt'
return $lastAutomaticTipWrittenDateFilePath
}

function TestIfUnseenTipsExist
{
[CmdletBinding()]
[OutputType([bool])]
Param()

[hashtable] $allTips = ReadAllPowerShellTipsFromJsonFile
[string[]] $tipIdsAlreadyShown = ReadTipIdsAlreadyShownOrDefault

# If no tips have been shown yet, there are definitely unseen tips
if ($tipIdsAlreadyShown.Count -eq 0)
{
return $true
}

# Check if there are any tips that haven't been shown yet
foreach ($tipId in $allTips.Keys)
{
if ($tipId -notin $tipIdsAlreadyShown)
{
return $true
}
}

# All tips have been shown
return $false
}
22 changes: 22 additions & 0 deletions src/tiPS/Public/Set-TiPSConfiguration.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,11 @@ function Set-TiPSConfiguration
Whether to automatically write a PowerShell tip at session startup.
Valid values are Never, EverySession, Daily, Weekly, Biweekly, and Monthly. Default is Never.

.PARAMETER AllTipsShownBehaviour
Controls how tips are selected when automatically showing tips.
Valid values are ClearShownTipsList (default) and DoNotShowTips.
DoNotShowTips will only show tips that have not been shown before.

.PARAMETER TipRetrievalOrder
The order in which to retrieve PowerShell tips.
Valid values are NewestFirst, OldestFirst, and Random. Default is NewestFirst.
Expand Down Expand Up @@ -60,6 +65,11 @@ function Set-TiPSConfiguration
Set-TiPSConfiguration -TipRetrievalOrder Random

Set the tiPS configuration to retrieve PowerShell tips in random order.

.EXAMPLE
Set-TiPSConfiguration -AutomaticallyWritePowerShellTip Daily -AllTipsShownBehaviour DoNotShowTips

Set the tiPS configuration to automatically write a PowerShell tip every day, but only if there are tips that have not been shown yet.
#>
[CmdletBinding(SupportsShouldProcess = $true, DefaultParameterSetName = 'PartialConfiguration')]
[OutputType([void])]
Expand All @@ -75,6 +85,9 @@ function Set-TiPSConfiguration
[Parameter(Mandatory = $false, ParameterSetName = 'PartialConfiguration', ValueFromPipelineByPropertyName = $true)]
[tiPS.WritePowerShellTipCadence] $AutomaticallyWritePowerShellTip = [tiPS.WritePowerShellTipCadence]::Never,

[Parameter(Mandatory = $false, ParameterSetName = 'PartialConfiguration', ValueFromPipelineByPropertyName = $true)]
[tiPS.AllTipsShownBehaviours] $AllTipsShownBehaviour = [tiPS.AllTipsShownBehaviours]::ClearShownTipsList,

[Parameter(Mandatory = $false, ParameterSetName = 'PartialConfiguration', ValueFromPipelineByPropertyName = $true)]
[Alias('TipOrder')]
[tiPS.TipRetrievalOrder] $TipRetrievalOrder = [tiPS.TipRetrievalOrder]::NewestFirst
Expand Down Expand Up @@ -118,6 +131,15 @@ function Set-TiPSConfiguration
}
}

# If the AllTipsShownBehaviour parameter is passed in, set it.
if ($PSBoundParameters.ContainsKey('AllTipsShownBehaviour'))
{
if ($PSCmdlet.ShouldProcess('tiPS configuration AllTipsShownBehaviour property', 'Set'))
{
$script:TiPSConfiguration.AllTipsShownBehaviour = $AllTipsShownBehaviour
}
}

Write-Debug "Saving the tiPS configuration to the configuration file."
WriteConfigurationToFile -Config $script:TiPSConfiguration

Expand Down