-
Notifications
You must be signed in to change notification settings - Fork 237
Send Pester describe line and info whether Pester 4.6.0 is installed to PowerShell.RunPesterTests command #856
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 13 commits
f26755f
a034574
c978a6f
725f643
62b101b
b6b4b4c
dbd42b5
61f62f5
ba32b20
565f2f8
32c69aa
69e7260
e5bddd0
39290a2
7245bd6
4ec3b3f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -8,6 +8,7 @@ | |
using System; | ||
using System.Collections.Generic; | ||
using System.Linq; | ||
using System.Management.Automation; | ||
using System.Threading; | ||
using System.Threading.Tasks; | ||
|
||
|
@@ -25,6 +26,12 @@ internal class PesterCodeLensProvider : FeatureProviderBase, ICodeLensProvider | |
/// </summary> | ||
private IDocumentSymbolProvider _symbolProvider; | ||
|
||
/// <summary> | ||
/// Pester 4.6.0 introduced a new ScriptblockFilter parameter to be able to run a test based on a line, | ||
/// therefore knowing this information is important. | ||
/// </summary> | ||
private readonly Lazy<bool> _pesterV4_6_0_OrHigherAvailable; | ||
|
||
/// <summary> | ||
/// Create a new Pester CodeLens provider for a given editor session. | ||
/// </summary> | ||
|
@@ -33,6 +40,7 @@ public PesterCodeLensProvider(EditorSession editorSession) | |
{ | ||
_editorSession = editorSession; | ||
_symbolProvider = new PesterDocumentSymbolProvider(); | ||
_pesterV4_6_0_OrHigherAvailable = new Lazy<bool>(() => DeterminePesterVersion()); | ||
} | ||
|
||
/// <summary> | ||
|
@@ -45,6 +53,9 @@ private CodeLens[] GetPesterLens( | |
PesterSymbolReference pesterSymbol, | ||
ScriptFile scriptFile) | ||
{ | ||
// A value of null is a signal to PSES that the available Pester version does not support | ||
// running Describe blocks by name (the test name will used instead then). | ||
int? describeBlockLineNumber = _pesterV4_6_0_OrHigherAvailable.Value ? (int?)pesterSymbol.ScriptRegion.StartLineNumber : null; | ||
var codeLensResults = new CodeLens[] | ||
{ | ||
new CodeLens( | ||
|
@@ -54,7 +65,7 @@ private CodeLens[] GetPesterLens( | |
new ClientCommand( | ||
"PowerShell.RunPesterTests", | ||
"Run tests", | ||
new object[] { scriptFile.ClientFilePath, false /* No debug */, pesterSymbol.TestName })), | ||
new object[] { scriptFile.ClientFilePath, false /* No debug */, pesterSymbol.TestName, describeBlockLineNumber })), | ||
|
||
new CodeLens( | ||
this, | ||
|
@@ -63,12 +74,43 @@ private CodeLens[] GetPesterLens( | |
new ClientCommand( | ||
"PowerShell.RunPesterTests", | ||
"Debug tests", | ||
new object[] { scriptFile.ClientFilePath, true /* Run in debugger */, pesterSymbol.TestName })), | ||
new object[] { scriptFile.ClientFilePath, true /* Run in debugger */, pesterSymbol.TestName, describeBlockLineNumber })), | ||
}; | ||
|
||
return codeLensResults; | ||
} | ||
|
||
/// <summary> | ||
/// Used to determine the value of <see cref="_pesterV4_6_0_OrHigherAvailable"/> as a background task. | ||
/// </summary> | ||
private bool DeterminePesterVersion() | ||
{ | ||
var powerShell = new PSCommand() | ||
.AddCommand("Get-Module") | ||
.AddParameter("ListAvailable") | ||
.AddParameter("Name", "Pester"); | ||
|
||
IEnumerable<PSObject> result = Task.Run(() => | ||
{ | ||
return _editorSession.PowerShellContext.ExecuteCommandAsync<PSObject>(powerShell); | ||
}).Result; | ||
|
||
if (result == null) | ||
{ | ||
return false; | ||
} | ||
|
||
var minimumPesterVersionSupportingInlineInvocation = new Version(4, 6); | ||
foreach (PSObject module in result) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What I'm worried about here is... Lets look at the
let's say they have version 4.5 in their user module path ( but 4.6 in their allusers module path This function will return true but 4.5 is what will get imported when doing:
I think we should only check the first item in the result. This should be the Pester that would get imported. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is that really the behaviour of PowerShell to not use the latest available version? Can you please point to some docs or code for my own education. How do you know that just looking at the first item is enough? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes that's the behavior of PowerShell. I'm unaware of any docs out in the wild (cc @SteveL-MSFT or @joeyaiello maybe?). The A simple test: → Install-Module Pester -Scope AllUsers -Force
→ Install-Module Pester -Scope CurrentUser -Force -MaximumVersion 4.5
→ Get-Command Invoke-Pester
CommandType Name Version Source
----------- ---- ------- ------
Function Invoke-Pester 4.5.0 Pester
→ Get-Module -ListAvailable Pester
Directory: /Users/tyler/.local/share/powershell/Modules
ModuleType Version Name PSEdition ExportedCommands
---------- ------- ---- --------- ----------------
Script 4.5.0 Pester Desk {Describe, Context, It, Should…}
Directory: /usr/local/share/powershell/Modules
ModuleType Version Name PSEdition ExportedCommands
---------- ------- ---- --------- ----------------
Script 4.6.0 Pester Desk {Describe, Context, It, Should…}
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Because when you do There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hmm, yes, this sounds like There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah... can @rjmholt and @SeeminglyScience help me understand why this should be synchronous? I would think non-blocking would be better here. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. AFAICT the bulk of the Pester code lens implementation is sync (other than LSP message reading/writing). This code is a bit old so maybe we weren't doing as much async then (??) or it could be that the specific symbol we are looking for results in a "fast enough" AST search. One issue I have with this approach is that it doesn't take into account that I might have already imported an older version of Pester e.g. Another thing to consider is this feature seems to be implemented before PS Core was shipped. That is, Windows PowerShell comes with Pester but not PS Core - right? But this feature is still enabled resulting in this user exp:
Perhaps we should consider shipping Pester with the extension like we do with PSSA? That would ensure this feature works on a vanilla PS Core install. This would ensure we have loaded a minimum version of Pester - like we do for PSSA. But we still allow folks to install later versions of Pester and those would get loaded. Again, very similiar to how we load PSSA. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @rkeithhill you touch on a lot of great points.
This makes sense. But
Some people rely on specific version of Pester. PowerShell itself relied on a specific version of Pester for a while in preparation for Core support from Pester. I don't think we can add Pester into PSES and grab the latest version on the PSModulePath because I don't want to hurt customers by forcing a newer version of Pester on them and all of a sudden their CI and their local are different. PSSA does fall in that camp, a bit... but PSSA is more for local analysis than anything else, I feel. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @TylerLeonhardt I agree with point 2 and 3. Regarding point 2, we could potentially offer to install the latest version of Pester as a 3rd option in the dialog, but I see this as an optional, nice to have feature that can happen after this PR. Regarding point 1: I am not sure if we are on the same page: At the moment, when There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I made it use |
||
{ | ||
if (module.BaseObject is PSModuleInfo psModuleInfo && psModuleInfo.Version >= minimumPesterVersionSupportingInlineInvocation) | ||
{ | ||
return true; | ||
} | ||
} | ||
return false; | ||
} | ||
|
||
/// <summary> | ||
/// Get all Pester CodeLenses for a given script file. | ||
/// </summary> | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there a reason you're using
.Result
instead of using async/await?Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To make it synchronous since I moved it to the last possible point (when a .tests.ps1 file with a Describe block gets opened). If I did not call .Result (i.e. make it async) then it would default to the old Pester syntax in the first 1-2 seconds until the value has been determined (which people did not like in the first version of the PR). It is still using Task APIs because the PSCommand APIs that were suggested are all async.