Skip to content

Commit 9919d18

Browse files
committed
Merge pull request #112 from rkeithhill/rkeithhill/update-example
Modified Examples dir to provide a preview of PSake based module publ…
2 parents de8caf4 + 46ef534 commit 9919d18

16 files changed

+461
-78
lines changed

examples/.gitignore

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# Don't checkin this output dir
2+
Release/
3+
4+
# Auto-generated test file
5+
foo[1].ps1

examples/.vscode/tasks.json

+47-9
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
// A task runner that invokes Pester to run all Pester tests under the
22
// current workspace folder.
33

4-
// NOTE: This Pester task runner requires an updated version of Pester (>=3.4.0)
4+
// NOTE: This Test task runner requires an updated version of Pester (>=3.4.0)
55
// in order for the problemMatcher to find failed test information (message, line, file).
6-
// If you don't have that version, you can update Pester from the PSGallery like so:
6+
// If you don't have that version, you can update Pester from the PowerShell Gallery
7+
// with this command:
78
//
89
// PS C:\> Update-Module Pester
910
//
@@ -14,14 +15,19 @@
1415
// PS C:\> Install-Module Pester -Scope CurrentUser -Force
1516
//
1617

18+
// NOTE: The Clean, Build and Publish tasks require PSake. PSake can be installed
19+
// from the PowerShell Gallery with this command:
20+
//
21+
// PS C:\> Install-Module PSake -Scope CurrentUser -Force
22+
//
23+
1724
// Available variables which can be used inside of strings.
1825
// ${workspaceRoot}: the root folder of the team
1926
// ${file}: the current opened file
2027
// ${fileBasename}: the current opened file's basename
2128
// ${fileDirname}: the current opened file's dirname
2229
// ${fileExtname}: the current opened file's extension
2330
// ${cwd}: the current working directory of the spawned process
24-
2531
{
2632
"version": "0.1.0",
2733

@@ -34,17 +40,49 @@
3440
// Show the output window always
3541
"showOutput": "always",
3642

37-
"args": [
38-
"-NoProfile", "-ExecutionPolicy", "Bypass",
39-
"Write-Host 'Invoking Pester...'; Invoke-Pester -PesterOption @{IncludeVSCodeMarker=$true};",
40-
"Invoke-Command { Write-Host \"Completed all tasks in task runner: $($args[0])\" } -args"
41-
],
43+
"args": [
44+
"-NoProfile", "-ExecutionPolicy", "Bypass"
45+
],
4246

4347
// Associate with test task runner
4448
"tasks": [
4549
{
46-
"taskName": "Pester",
50+
"taskName": "Clean",
51+
"suppressTaskName": true,
52+
"showOutput": "always",
53+
"args": [
54+
"Write-Host 'Invoking PSake...'; Invoke-PSake build.ps1 -taskList Clean;",
55+
"Invoke-Command { Write-Host 'Completed Clean task in task runner.' }"
56+
]
57+
},
58+
{
59+
"taskName": "Build",
60+
"suppressTaskName": true,
61+
"isBuildCommand": true,
62+
"showOutput": "always",
63+
"args": [
64+
"Write-Host 'Invoking PSake...'; Invoke-PSake build.ps1 -taskList Build;",
65+
"Invoke-Command { Write-Host 'Completed Build task in task runner.' }"
66+
]
67+
},
68+
{
69+
"taskName": "Publish",
70+
"suppressTaskName": true,
71+
"showOutput": "always",
72+
"args": [
73+
"Write-Host 'Invoking PSake...'; Invoke-PSake build.ps1 -taskList Publish;",
74+
"Invoke-Command { Write-Host 'Completed Publish task in task runner.' }"
75+
]
76+
},
77+
{
78+
"taskName": "Test",
79+
"suppressTaskName": true,
4780
"isTestCommand": true,
81+
"showOutput": "always",
82+
"args": [
83+
"Write-Host 'Invoking Pester...'; Invoke-Pester -PesterOption @{IncludeVSCodeMarker=$true};",
84+
"Invoke-Command { Write-Host 'Completed Test task in task runner.' }"
85+
],
4886
"problemMatcher": [
4987
{
5088
"owner": "powershell",

examples/Build.ps1

+227
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,227 @@
1+
##############################################################################
2+
# PREVIEW VERSION OF PSAKE SCRIPT FOR MODULE BUILD & PUBLISH TO THE PSGALLERY
3+
##############################################################################
4+
#
5+
# We are hoping to add support for publishing modules to the PowerShell gallery
6+
# and private repositories in a future release of this extension. This is an
7+
# early look at the approach we are considering which is to supply a
8+
# PSake-based script that will:
9+
#
10+
# 1. Create a directory from which to publish your module.
11+
# 2. Copy the appropriate module files to that directory excluding items like
12+
# the .vscode directory, Pester tests, etc. These are configurable in Build.ps1.
13+
# 3. Verify all existing Pester tests pass.
14+
# 4. Publish the module to the desired repository (defaulting to the PSGallery).
15+
#
16+
# Requirements: PSake. If you don't have this module installed use the following
17+
# command to install it:
18+
#
19+
# PS C:\> Install-Module PSake -Scope CurrentUser
20+
#
21+
##############################################################################
22+
# This is a PSake script that supports the following tasks:
23+
# clean, build, test and publish. The default task is build.
24+
#
25+
# The publish task uses the Publish-Module command to publish
26+
# to either the PowerShell Gallery (the default) or you can change
27+
# the $Repository property to the name of an alternate repository.
28+
#
29+
# The test task invokes Pester to run any Pester tests in your
30+
# workspace folder. Name your test scripts <TestName>.Tests.ps1
31+
# and Pester will find and run the tests contained in the files.
32+
#
33+
# You can run this build script directly using the invoke-psake
34+
# command which will execute the build task. This task "builds"
35+
# a temporary folder from which the module can be published.
36+
#
37+
# PS C:\> invoke-psake build.ps1
38+
#
39+
# You can run your Pester tests (if any) by running the following command.
40+
#
41+
# PS C:\> invoke-psake build.ps1 -taskList test
42+
#
43+
# You can execute the publish task with the following command. Note that
44+
# the publish task will run the test task first. The Pester tests must pass
45+
# before the publish task will run. The first time you run the publish
46+
# command, you will be prompted to enter your PowerShell Gallery NuGetApiKey.
47+
# After entering the key, it is encrypted and stored so you will not have to
48+
# enter it again.
49+
#
50+
# PS C:\> invoke-psake build.ps1 -taskList publish
51+
#
52+
# You can verify the stored and encrypted NuGetApiKey by running the following
53+
# command. This will display your NuGetApiKey in plain text!
54+
#
55+
# PS C:\> invoke-psake build.ps1 -taskList showKey
56+
#
57+
# You can store a new NuGetApiKey with this command. You can leave off
58+
# the -properties parameter and you'll be prompted for the key.
59+
#
60+
# PS C:\> invoke-psake build.ps1 -taskList storeKey -properties @{NuGetApiKey='test123'}
61+
#
62+
63+
###############################################################################
64+
# Customize these properties for your module.
65+
###############################################################################
66+
Properties {
67+
# The name of your module should match the basename of the PSD1 file.
68+
$ModuleName = (Get-Item $PSScriptRoot\*.psd1)[0].BaseName
69+
70+
# Path to the release notes file. Set to $null if the release notes reside in the manifest file.
71+
$ReleaseNotesPath = "$PSScriptRoot\ReleaseNotes.md"
72+
73+
# The directory used to publish the module from. If you are using Git, the
74+
# $PublishDir should be ignored if it is under the workspace directory.
75+
$PublishDir = "$PSScriptRoot\Release\$ModuleName"
76+
77+
# The following items will not be copied to the $PublishDir.
78+
# Add items that should not be published with the module.
79+
$Exclude = @(
80+
'Release',
81+
'Tests',
82+
'.git*',
83+
'.vscode',
84+
# The next three files are unique to this examples dir.
85+
'DebugTest.ps1',
86+
'Stop*.ps1',
87+
'Readme.md',
88+
(Split-Path $PSCommandPath -Leaf)
89+
)
90+
91+
# Name of the repository you wish to publish to. Default repo is the PSGallery.
92+
$PublishRepository = $null
93+
94+
# Your NuGet API key for the PSGallery. Leave it as $null and the first time
95+
# you publish you will be prompted to enter your API key. The build will
96+
# store the key encrypted in a file, so that on subsequent publishes you
97+
# will no longer be prompted for the API key.
98+
$NuGetApiKey = $null
99+
$EncryptedApiKeyPath = "$env:LOCALAPPDATA\vscode-powershell\NuGetApiKey.clixml"
100+
}
101+
102+
###############################################################################
103+
# Customize these tasks for performing operations before and/or after publish.
104+
###############################################################################
105+
Task PrePublish {
106+
}
107+
108+
Task PostPublish {
109+
}
110+
111+
###############################################################################
112+
# Core task implementations - this possibly "could" ship as part of the
113+
# vscode-powershell extension and then get dot sourced into this file.
114+
###############################################################################
115+
Task default -depends Build
116+
117+
Task Publish -depends Test, PrePublish, PublishImpl, PostPublish {
118+
}
119+
120+
Task PublishImpl -depends Test -requiredVariables PublishDir, EncryptedApiKeyPath {
121+
$NuGetApiKey = Get-NuGetApiKey $NuGetApiKey $EncryptedApiKeyPath
122+
123+
$publishParams = @{
124+
Path = $PublishDir
125+
NuGetApiKey = $NuGetApiKey
126+
}
127+
128+
if ($PublishRepository) {
129+
$publishParams['Repository'] = $PublishRepository
130+
}
131+
132+
# Consider not using -ReleaseNotes parameter when Update-ModuleManifest has been fixed.
133+
if ($ReleaseNotesPath) {
134+
$publishParams['ReleaseNotes'] = @(Get-Content $ReleaseNotesPath)
135+
}
136+
137+
"Calling Publish-Module..."
138+
Publish-Module @publishParams -WhatIf
139+
}
140+
141+
Task Test -depends Build {
142+
Import-Module Pester
143+
Invoke-Pester $PSScriptRoot
144+
}
145+
146+
Task Build -depends Clean -requiredVariables PublishDir, Exclude, ModuleName {
147+
Copy-Item $PSScriptRoot\* -Destination $PublishDir -Recurse -Exclude $Exclude
148+
149+
# Get contents of the ReleaseNotes file and update the copied module manifest file
150+
# with the release notes.
151+
# DO NOT USE UNTIL UPDATE-MODULEMANIFEST IS FIXED - HORRIBLY BROKEN RIGHT NOW.
152+
# if ($ReleaseNotesPath) {
153+
# $releaseNotes = @(Get-Content $ReleaseNotesPath)
154+
# Update-ModuleManifest -Path $PublishDir\${ModuleName}.psd1 -ReleaseNotes $releaseNotes
155+
# }
156+
}
157+
158+
Task Clean -depends Init -requiredVariables PublishDir {
159+
# Sanity check the dir we are about to "clean". If $PublishDir were to
160+
# inadvertently get set to $null, the Remove-Item commmand removes the
161+
# contents of \*. That's a bad day. Ask me how I know? :-(
162+
if ($PublishDir.Contains($PSScriptRoot)) {
163+
Remove-Item $PublishDir\* -Recurse -Force
164+
}
165+
}
166+
167+
Task Init -requiredVariables PublishDir {
168+
if (!(Test-Path $PublishDir)) {
169+
$null = New-Item $PublishDir -ItemType Directory
170+
}
171+
}
172+
173+
Task StoreKey -requiredVariables EncryptedApiKeyPath {
174+
if (Test-Path $EncryptedApiKeyPath) {
175+
Remove-Item $EncryptedApiKeyPath
176+
}
177+
178+
$null = Get-NuGetApiKey $NuGetApiKey $EncryptedApiKeyPath
179+
"The NuGetApiKey has been stored in $EncryptedApiKeyPath"
180+
}
181+
182+
Task ShowKey -requiredVariables EncryptedApiKeyPath {
183+
$NuGetApiKey = Get-NuGetApiKey $NuGetApiKey $EncryptedApiKeyPath
184+
"The stored NuGetApiKey is: $NuGetApiKey"
185+
}
186+
187+
Task ? -description 'Lists the available tasks' {
188+
"Available tasks:"
189+
$psake.context.Peek().tasks.Keys | Sort
190+
}
191+
192+
###############################################################################
193+
# Helper functions
194+
###############################################################################
195+
function Get-NuGetApiKey($NuGetApiKey, $EncryptedApiKeyPath) {
196+
$storedKey = $null
197+
if (!$NuGetApiKey) {
198+
if (Test-Path $EncryptedApiKeyPath) {
199+
$storedKey = Import-Clixml $EncryptedApiKeyPath | ConvertTo-SecureString
200+
$cred = New-Object -TypeName PSCredential -ArgumentList 'kh',$storedKey
201+
$NuGetApiKey = $cred.GetNetworkCredential().Password
202+
Write-Verbose "Retrieved encrypted NuGetApiKey from $EncryptedApiKeyPath"
203+
}
204+
else {
205+
$cred = Get-Credential -Message "Enter your NuGet API Key in the password field (or nothing, this isn't used yet in the preview)" -UserName "user"
206+
$apiKeySS = $cred.Password
207+
$NuGetApiKey = $cred.GetNetworkCredential().Password
208+
}
209+
}
210+
211+
if (!$storedKey) {
212+
# Store encrypted NuGet API key to use for future invocations
213+
if (!$apiKeySS) {
214+
$apiKeySS = ConvertTo-SecureString -String $NuGetApiKey -AsPlainText -Force
215+
}
216+
217+
$parentDir = Split-Path $EncryptedApiKeyPath -Parent
218+
if (!(Test-Path -Path $parentDir)) {
219+
$null = New-Item -Path $parentDir -ItemType Directory
220+
}
221+
222+
$apiKeySS | ConvertFrom-SecureString | Export-Clixml $EncryptedApiKeyPath
223+
Write-Verbose "Stored encrypted NuGetApiKey to $EncryptedApiKeyPath"
224+
}
225+
226+
$NuGetApiKey
227+
}

examples/DebugTest.ps1

262 Bytes
Binary file not shown.

examples/PathProcessingNoWildcards.ps1

+18-5
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,16 @@
1+
<#
2+
.SYNOPSIS
3+
Demonstrates how to write a command that works with paths that do
4+
not allow wildards but must exist.
5+
.DESCRIPTION
6+
This command does not require a LiteralPath parameter because the
7+
Path parameter can handle paths that use wildcard characters. That's
8+
because this command does not "resolve" the supplied path.
9+
.EXAMPLE
10+
C:\PS> Import-FileNoWildcard -Path ..\..\Tests\foo[1].txt -WhatIf
11+
This example shows how the Path parameter can handle a path that happens
12+
to use the wildcard chars "[" and "]".
13+
#>
114
function Import-FileNoWildcard {
215
[CmdletBinding(SupportsShouldProcess=$true)]
316
param(
@@ -13,10 +26,10 @@ function Import-FileNoWildcard {
1326
[string[]]
1427
$Path
1528
)
16-
29+
1730
begin {
1831
}
19-
32+
2033
process {
2134
# Modify [CmdletBinding()] to [CmdletBinding(SupportsShouldProcess=$true)]
2235
$paths = @()
@@ -28,19 +41,19 @@ function Import-FileNoWildcard {
2841
$psCmdlet.WriteError($errRecord)
2942
continue
3043
}
31-
44+
3245
# Resolve any relative paths
3346
$paths += $psCmdlet.SessionState.Path.GetUnresolvedProviderPathFromPSPath($aPath)
3447
}
35-
48+
3649
foreach ($aPath in $paths) {
3750
if ($pscmdlet.ShouldProcess($aPath, 'Operation')) {
3851
# Process each path
3952
$aPath
4053
}
4154
}
4255
}
43-
56+
4457
end {
4558
}
4659
}

0 commit comments

Comments
 (0)