PowerShell 6 Core Support (#35)

## About
This pull request reflects all changes done in the `linuxsupport` branch.

## Content
- Enable PowerShell 6 Core support
- Use PFX Certificate for encryption ( fixes #32 )
- Updates CI / CD pipeline ( fixes #31 )
- uses portable libressl ( fixes #34 )
- adds `-PassThru` switch for returning current `VIServer` session in `Connect-To` ( fixes #34 )
- adds git lfs for embedded libressl files
- restructured internal functions into `Private` dir
- added certificate related functions
- adds travis build pipeline for tests
This commit is contained in:
2019-01-16 12:55:29 +01:00
committed by GitHub
parent ab13962f6e
commit afab3c870c
83 changed files with 2465 additions and 1342 deletions

View File

@ -7,7 +7,7 @@
- Module name
#>
$CALLSIGN = 'PSCredentialStore'
Write-Host ("Callsign is: {0}" -f $CALLSIGN) -ForegroundColor Yellow
Write-Host ("Callsign is: {0}" -f $CALLSIGN) -ForegroundColor Black -BackgroundColor Yellow
Function Invoke-InstallDependencies() {
@ -16,18 +16,19 @@ Function Invoke-InstallDependencies() {
Process {
Try {
Get-PackageProvider -ListAvailable
Install-PackageProvider -Name NuGet -RequiredVersion '2.8.5.208' -Force -Verbose
Import-PackageProvider -Name NuGet -RequiredVersion '2.8.5.208' -Force
Install-Module -Name 'Pester' -Scope CurrentUser -RequiredVersion '4.0.8' -Force -SkipPublisherCheck -AllowClobber
Install-Module -Name 'posh-git' -Scope CurrentUser -RequiredVersion '0.7.1' -Force -SkipPublisherCheck -AllowClobber
Install-Module -Name 'PSCoverage' -Scope CurrentUser -Force -SkipPublisherCheck -AllowClobber
Import-Module -Name 'Pester', 'posh-git', 'PSCoverage'
Install-Module -Name 'Pester' -Scope CurrentUser -RequiredVersion '4.4.2' -Force -SkipPublisherCheck -AllowClobber
Install-Module -Name 'posh-git' -Scope CurrentUser -RequiredVersion '1.0.0-beta2' -Force -SkipPublisherCheck -AllowClobber -AllowPrerelease
# Install-Module -Name 'PSCoverage' -Scope CurrentUser -Force -SkipPublisherCheck -AllowClobber
Import-Module -Name 'Pester', 'posh-git' #, 'PSCoverage'
}
Catch {
$MsgParams = @{
Message = 'Could not install the required dependencies!'
Message = 'Could not install the required dependencies!'
Category = 'Error'
Details = $_.Exception.Message
Details = $_.Exception.Message
}
Add-AppveyorMessage @MsgParams
Throw $MsgParams.Message
@ -39,21 +40,21 @@ Function Invoke-AppVeyorBumpVersion() {
[CmdletBinding()]
Param()
Write-Host "Listing Env Vars for debugging:" -ForegroundColor Yellow
Write-Host "Listing Env Vars for debugging:" -ForegroundColor Black -BackgroundColor Yellow
# Filter Results to prevent exposing secure vars.
Get-ChildItem -Path "Env:*" | Where-Object { $_.name -notmatch "(NuGetToken|CoverallsToken)"} | Sort-Object -Property Name | Format-Table
Try {
$ModManifest = Get-Content -Path (".\src\{0}.psd1" -f $CALLSIGN)
$BumpedManifest = $ModManifest -replace '0.0.0.9999', $Env:APPVEYOR_BUILD_VERSION
$BumpedManifest = $ModManifest -replace '0.0.9999', $Env:APPVEYOR_BUILD_VERSION
Remove-Item -Path (".\src\{0}.psd1" -f $CALLSIGN)
Out-File -FilePath (".\src\{0}.psd1" -f $CALLSIGN) -InputObject $BumpedManifest -NoClobber -Encoding utf8 -Force
}
Catch {
$MsgParams = @{
Message = 'Could not bump current version into module manifest.'
Message = 'Could not bump current version into module manifest.'
Category = 'Error'
Details = $_.Exception.Message
Details = $_.Exception.Message
}
Add-AppveyorMessage @MsgParams
Throw $MsgParams.Message
@ -62,27 +63,29 @@ Function Invoke-AppVeyorBumpVersion() {
Function Invoke-AppVeyorBuild() {
[CmdletBinding()]
[OutputType([PsCustomObject])]
Param()
$MsgParams = @{
Message = 'Creating build artifacts'
Message = 'Creating build artifacts'
Category = 'Information'
Details = 'Extracting source files and compressing them into zip file.'
Details = 'Extracting source files and compressing them into zip file.'
}
Add-AppveyorMessage @MsgParams
$CompParams = @{
Path = "{0}\src\*" -f $env:APPVEYOR_BUILD_FOLDER
Path = "{0}\src\*" -f $env:APPVEYOR_BUILD_FOLDER
DestinationPath = "{0}\bin\{1}.zip" -f $env:APPVEYOR_BUILD_FOLDER, $CALLSIGN
Update = $True
Verbose = $True
Update = $True
Verbose = $True
}
Compress-Archive @CompParams
$MsgParams = @{
Message = 'Pushing artifacts'
Message = 'Pushing artifacts'
Category = 'Information'
Details = 'Pushing artifacts to AppVeyor store.'
Details = 'Pushing artifacts to AppVeyor store.'
}
Add-AppveyorMessage @MsgParams
Push-AppveyorArtifact (".\bin\{0}.zip" -f $CALLSIGN)
$ArtifactPath = Join-Path -Path '.' -ChildPath ('bin/{0}.zip' -f $CALLSIGN)
Push-AppveyorArtifact $ArtifactPath
}
Function Invoke-AppVeyorTests() {
@ -90,60 +93,85 @@ Function Invoke-AppVeyorTests() {
Param()
$MsgParams = @{
Message = 'Starting Pester tests'
Message = 'Starting Pester tests'
Category = 'Information'
Details = 'Now running all test found in .\tests\ dir.'
Details = 'Now running all test found in .\tests\ dir.'
}
Add-AppveyorMessage @MsgParams
$testresults = Invoke-Pester -Path ( Get-ChildItem -Path ".\tests\*.Tests.ps1" -Recurse | Sort-Object -Property Name ) -ExcludeTag 'Disabled' -PassThru
ForEach ($Item in $testresults.TestResult) {
try {
Write-Host '===== Preload internal private functions =====' -ForegroundColor Black -BackgroundColor Yellow
$Privates = Get-ChildItem -Path (Join-Path -Path $Env:APPVEYOR_BUILD_FOLDER -ChildPath '/src/Private/*') -Include "*.ps1" -Recurse
foreach ($File in $Privates) {
if (Test-Path -Path $File.FullName) {
. $File.FullName
Write-Verbose -Message ('Private function dot-sourced: {0}' -f $File.FullName) -Verbose
}
else {
Write-Warning -Message ('Could not find file: {0} !' -f $File.FullName)
}
}
}
catch {
$_.Exception.Message | Write-Error
throw 'Could not load required private functions!'
}
#$testresults = Invoke-Pester -Path ( Get-ChildItem -Path ".\tests\*.Tests.ps1" -Recurse | Sort-Object -Property Name ) -ExcludeTag 'Disabled' -PassThru
$srcFiles = Get-ChildItem -Path ".\src\*.ps1" -Recurse | Sort-Object -Property 'Name' | Select-Object -ExpandProperty 'FullName'
$testFiles = Get-ChildItem -Path ".\tests\*.Tests.ps1" -Recurse | Sort-Object -Property 'Name' | Select-Object -ExpandProperty 'FullName'
$TestResults = Invoke-Pester -Path $testFiles -CodeCoverage $srcFiles -PassThru
ForEach ($Item in $TestResults.TestResult) {
Switch ($Item.Result) {
"Passed" {
$TestParams = @{
Name = "{0}: {1}" -f $Item.Context, $Item.Name
Name = "{0}: {1}" -f $Item.Context, $Item.Name
Framework = "NUnit"
Filename = $Item.Describe
Outcome = "Passed"
Duration = $Item.Time.Milliseconds
Filename = $Item.Describe
Outcome = "Passed"
Duration = $Item.Time.Milliseconds
}
Add-AppveyorTest @TestParams
}
"Failed" {
$TestParams = @{
Name = "{0}: {1}" -f $Item.Context, $Item.Name
Framework = "NUnit"
Filename = $Item.Describe
Outcome = "Failed"
Duration = $Item.Time.Milliseconds
ErrorMessage = $Item.FailureMessage
Name = "{0}: {1}" -f $Item.Context, $Item.Name
Framework = "NUnit"
Filename = $Item.Describe
Outcome = "Failed"
Duration = $Item.Time.Milliseconds
ErrorMessage = $Item.FailureMessage
ErrorStackTrace = $Item.StackTrace
}
Add-AppveyorTest @TestParams
}
Default {
$TestParams = @{
Name = "{0}: {1}" -f $Item.Context, $Item.Name
Framework = "NUnit"
Filename = $Item.Describe
Outcome = "None"
Duration = $Item.Time.Milliseconds
ErrorMessage = $Item.FailureMessage
Name = "{0}: {1}" -f $Item.Context, $Item.Name
Framework = "NUnit"
Filename = $Item.Describe
Outcome = "None"
Duration = $Item.Time.Milliseconds
ErrorMessage = $Item.FailureMessage
ErrorStackTrace = $Item.StackTrace
}
Add-AppveyorTest @TestParams
}
}
}
If ($testresults.FailedCount -gt 0) {
If ($TestResults.FailedCount -gt 0) {
$MsgParams = @{
Message = 'Pester Tests failed.'
Message = 'Pester Tests failed.'
Category = 'Error'
Details = "$($testresults.FailedCount) tests failed."
Details = "$($TestResults.FailedCount) tests failed."
}
Add-AppveyorMessage @MsgParams
Throw $MsgParams.Message
}
return $TestResults.CodeCoverage
}
Function Invoke-CoverageReport() {
@ -151,13 +179,17 @@ Function Invoke-CoverageReport() {
Param(
[Parameter(Mandatory = $False)]
[ValidateNotNullOrEmpty()]
[String]$RepoToken = $Env:CoverallsToken
[String]$RepoToken = $Env:CoverallsToken,
[Parameter(Mandatory = $True)]
[ValidateNotNullOrEmpty()]
[PSCustomObject]$PesterCoverageReport
)
$FileMap = New-PesterFileMap -SourceRoot '.\src' -PesterRoot '.\tests'
$CoverageReport = New-CoverageReport -PesterFileMap $FileMap -RepoToken $RepoToken
#$CoverageReport | Format-Custom -Depth 5 | Out-String | Write-Verbose
$CoverageReport = New-CoverageReport -CodeCoverage $PesterCoverageReport -RepoToken $RepoToken
Write-Host "CoverageReport JSON:" -ForegroundColor Yellow
$CoverageReport | Out-String | Write-Host
#$CoverageReport | ConvertTo-Json -Depth 5 | Out-String | Write-Verbose
Publish-CoverageReport -CoverageReport $CoverageReport
}
@ -170,36 +202,36 @@ Function Invoke-AppVeyorPSGallery() {
)
Expand-Archive -Path (".\bin\{0}.zip" -f $CALLSIGN) -DestinationPath ("C:\Users\appveyor\Documents\WindowsPowerShell\Modules\{0}\" -f $CALLSIGN) -Verbose
Import-Module -Name $CALLSIGN -Verbose -Force
Write-Host "Available Package Provider:" -ForegroundColor Yellow
Write-Host "Available Package Provider:" -ForegroundColor Black -BackgroundColor Yellow
Get-PackageProvider -ListAvailable
Write-Host "Available Package Sources:" -ForegroundColor Yellow
Write-Host "Available Package Sources:" -ForegroundColor Black -BackgroundColor Yellow
Get-PackageSource
Try {
Write-Host "Try to get NuGet Provider:" -ForegroundColor Yellow
Write-Host "Try to get NuGet Provider:" -ForegroundColor Black -BackgroundColor Yellow
Get-PackageProvider -Name NuGet -ErrorAction Stop
}
Catch {
Write-Host "Installing NuGet..." -ForegroundColor Yellow
Write-Host "Installing NuGet..." -ForegroundColor Black -BackgroundColor Yellow
Install-PackageProvider -Name NuGet -MinimumVersion '2.8.5.201' -Force -Verbose
Import-PackageProvider NuGet -MinimumVersion '2.8.5.201' -Force
}
Try {
If ($env:APPVEYOR_REPO_BRANCH -eq 'master') {
Write-Host "try to publish module" -ForegroundColor Yellow
Write-Host ("Callsign is: {0}" -f $CALLSIGN) -ForegroundColor Yellow
Publish-Module -Name $CALLSIGN -NuGetApiKey $env:NuGetToken -Verbose -Force
Write-Host "try to publish module" -ForegroundColor Black -BackgroundColor Yellow
Write-Host ("Callsign is: {0}" -f $CALLSIGN) -ForegroundColor Black -BackgroundColor Yellow
Publish-Module -Name $CALLSIGN -NuGetApiKey $env:NuGetToken -Verbose -Force -AllowPrerelease
}
Else {
Write-Host "Skip publishing to PS Gallery because we are on $($env:APPVEYOR_REPO_BRANCH) branch." -ForegroundColor Yellow
Write-Host "Skip publishing to PS Gallery because we are on $($env:APPVEYOR_REPO_BRANCH) branch." -ForegroundColor Black -BackgroundColor Yellow
# had to remove the publish-Module statement because it would publish although the -WhatIf is given.
# Publish-Module -Name $CALLSIGN -NuGetApiKey $env:NuGetToken -Verbose -WhatIf
}
}
Catch {
$MsgParams = @{
Message = 'Could not deploy module to PSGallery.'
Message = 'Could not deploy module to PSGallery.'
Category = 'Error'
Details = $_.Exception.Message
Details = $_.Exception.Message
}
Add-AppveyorMessage @MsgParams
Throw $MsgParams.Message

178
tools/CoverallsIO.psm1 Normal file
View File

@ -0,0 +1,178 @@
function Get-GitInfo {
[CmdletBinding()]
param(
[string]$BranchName
)
if ($Env:AppVeyor) {
return [PSCustomObject]@{
head = [PSCustomObject]@{
id = $Env:APPVEYOR_REPO_COMMIT
author_name = $Env:APPVEYOR_REPO_COMMIT_AUTHOR
author_email = $Env:APPVEYOR_REPO_COMMIT_AUTHOR_EMAIL
comitter_name = $Env:APPVEYOR_REPO_COMMIT_AUTHOR
comitter_email = $Env:APPVEYOR_REPO_COMMIT_AUTHOR_EMAIL
message = $Env:APPVEYOR_REPO_COMMIT_MESSAGE
}
branch = $Env:APPVEYOR_REPO_BRANCH
}
}
else {
if (-not $BranchName) {
$BranchName = (git rev-parse --abbrev-ref HEAD)
}
return [PSCustomObject]@{
head = [PSCustomObject]@{
id = (git log --format="%H" HEAD -1)
author_name = (git log --format="%an" HEAD -1)
author_email = (git log --format="%ae" HEAD -1)
committer_name = (git log --format="%cn" HEAD -1)
committer_email = (git log --format="%ce" HEAD -1)
message = (git log --format="%s" HEAD -1)
}
branch = $BranchName
}
}
}
function New-CoverageReport {
[CmdletBinding()]
param(
[Parameter(Mandatory = $true)]
[ValidateNotNullOrEmpty()]
[PSCustomObject]$CodeCoverage,
[Parameter(Mandatory = $true)]
[ValidateNotNullOrEmpty()]
[string]$RepoToken,
[Parameter(Mandatory = $false)]
[ValidateNotNullOrEmpty()]
[string]$ModuleRoot = $(Get-Location)
)
begin {
$CoverReport = [PSCustomObject]@{
repo_token = $RepoToken
commit_sha = (git log --format="%H" HEAD -1)
git = Get-GitInfo
service_name = 'appveyor'
source_files = @()
}
}
process {
# Find all files with hit commands -> These file have pester tests
$UsedFiles = $CodeCoverage.AnalyzedFiles | Where-Object {
$CodeCoverage.HitCommands.File -contains $_
}
foreach ($SourceFile in $UsedFiles) {
$Lines = (Get-Content -Path $SourceFile | Measure-Object).Count
Write-Verbose ("SourceFile: {0} | LinesCount: {1}" -f $SourceFile, $Lines)
$CoverageArray = @()
$Hits = 0
$Missed = 0
for ($LinePointer = 1; $LinePointer -le $Lines; $LinePointer++) {
# Get only hit commands from current src file
$curHits = $CodeCoverage.HitCommands | Where-Object {
$_.File -eq $SourceFile
}
[int]$Hits = (
$curHits | Where-Object {
$_.Line -eq $LinePointer
} | Measure-Object
).Count
# again filter only missed commands from the curent file
$curMissed = $CodeCoverage.MissedCommands | Where-Object {
$_.File -eq $SourceFile
}
[int]$Missed = (
$curMissed | Where-Object {
$_.Line -eq $LinePointer
} | Measure-Object
).Count
Write-Verbose ("SourceFile:{0} | Line: {1} | Hits: {2} | Missed: {3}" -f $SourceFile, $LinePointer, $Hits, $Missed)
if ((-not $Hits -gt 0) -and (-not $Missed -gt 0)) {
$CoverageArray += 'null'
}
else {
if ($Hits -gt 0) {
$CoverageArray += $Hits
}
elseif ($Missed -gt 0) {
$CoverageArray += 0
}
}
}
# Get rid of the quotation
$CoverageArray = $CoverageArray -Replace '"', ''
$CoverageSourceFile = [PSCustomObject]@{
name = $SourceFile.Replace($ModuleRoot, '').Replace('\', '/')
source_digest = (Get-FileHash -Path $SourceFile -Algorithm MD5).Hash
coverage = $CoverageArray
}
If ($CoverageSourceFile.Name.StartsWith('/')) {
$CoverageSourceFile.Name = $CoverageSourceFile.Name.Remove(0, 1)
}
$CoverReport.source_files += $CoverageSourceFile
}
# Find all untested files to create a null coverage file
$UnUsedFiles = $CodeCoverage.AnalyzedFiles | Where-Object {
$CodeCoverage.HitCommands.File -notcontains $_
}
foreach ($UnUsedFile in $UnUsedFiles) {
$Lines = (Get-Content -Path $UnUsedFile | Measure-Object).Count
$CoverageArray = @()
for ($LinePointer = 1; $LinePointer -le $Lines; $LinePointer++) {
$CoverageArray += '0'
}
$CoverageSourceFile = [PSCustomObject]@{
name = $UnUsedFile.Replace($ModuleRoot, '').Replace('\', '/')
source_digest = (Get-FileHash -Path $UnUsedFile -Algorithm MD5).Hash
coverage = $CoverageArray
}
if ($CoverageSourceFile.Name.StartsWith('/')) {
$CoverageSourceFile.Name = $CoverageSourceFile.Name.Remove(0, 1)
}
$CoverReport.source_files += $CoverageSourceFile
}
}
end {
Write-Output $CoverReport
}
}
function Publish-CoverageReport () {
[CmdletBinding()]
param(
[Parameter(Mandatory = $True)]
[ValidateNotNullOrEmpty()]
[PSCustomObject]$CoverageReport
)
begin {
Add-Type -AssemblyName System.Net.Http
}
process {
$CoverageJSON = ConvertTo-Json $CoverageReport -Depth 5
# Try to fix null elements in coverage array.
$CoverageJSON = $CoverageJSON.Replace('"null"', 'null')
$stringContent = New-Object System.Net.Http.StringContent ($CoverageJSON)
$httpClient = New-Object System.Net.Http.Httpclient
$formdata = New-Object System.Net.Http.MultipartFormDataContent
$formData.Add($stringContent, "json_file", "coverage.json")
$result = $httpClient.PostAsync('https://coveralls.io/api/v1/jobs', $formData).Result
$content = $result.Content.ReadAsStringAsync()
}
end {
Write-Output $Content
}
}

66
tools/Travis.psm1 Normal file
View File

@ -0,0 +1,66 @@
$Global:ProgressPreference = 'SilentlyContinue'
$CALLSIGN = 'PSCredentialStore'
Write-Host ("Callsign is: {0}" -f $CALLSIGN) -ForegroundColor Black -BackgroundColor Yellow
function Invoke-InstallDependencies {
[CmdletBinding()]
Param()
process {
try {
Write-Host '===== Environment Vars: =====' -ForegroundColor Black -BackgroundColor Yellow
Get-ChildItem -Path Env:
Write-Host -Message '===== Existing Variables: =====' -ForegroundColor Black -BackgroundColor Yellow
Get-Variable -Name * | Format-Table -AutoSize
Get-PackageProvider -ListAvailable
Import-PackageProvider -Name 'NuGet' -MinimumVersion '2.8.5.208' -Verbose -Force
Install-Module -Name 'Pester' -Scope CurrentUser -RequiredVersion '4.4.2' -Force -SkipPublisherCheck -AllowClobber -Verbose
Install-Module -Name 'posh-git' -Scope CurrentUser -RequiredVersion '1.0.0-beta2' -Force -SkipPublisherCheck -AllowClobber -AllowPrerelease -Verbose
Import-Module -Name 'Pester', 'posh-git' -Verbose
}
catch {
$_.Exception.Message | Write-Error
throw 'Could not install the required dependencies!'
}
}
}
function Invoke-UnitTests {
[CmdletBinding()]
Param()
process {
try {
Write-Host '===== Preload internal private functions =====' -ForegroundColor Black -BackgroundColor Yellow
$Privates = Get-ChildItem -Path (Join-Path -Path $Env:TRAVIS_BUILD_DIR -ChildPath '/src/Private/*') -Include "*.ps1" -Recurse -ErrorAction Stop
foreach ($File in $Privates) {
if (Test-Path -Path $File.FullName) {
. $File.FullName
Write-Verbose -Message ('Private function dot-sourced: {0}' -f $File.FullName) -Verbose
}
else {
Write-Warning -Message ('Could not find file: {0} !' -f $File.FullName)
}
}
}
catch {
$_.Exception.Message | Write-Error
throw 'Could not load required private functions!'
}
Write-Host '===== Running Pester =====' -ForegroundColor Black -BackgroundColor Yellow
$TestFiles = Get-ChildItem -Path (Join-Path -Path '.' -ChildPath './tests/*.Tests.ps1') -Recurse| Sort-Object -Property Name
$TestResults = Invoke-Pester -Script $TestFiles -ExcludeTag 'Disabled' -PassThru
if ($TestResults.FailedCount -gt 0) {
throw ('{0} tests failed!' -f $TestResults.FailedCount)
}
}
}

14
tools/travis.sh Normal file
View File

@ -0,0 +1,14 @@
set -x
ulimit -n 4096
echo "TRAVIS_EVENT_TYPE value $TRAVIS_EVENT_TYPE"
if [ $TRAVIS_EVENT_TYPE = cron ] || [ $TRAVIS_EVENT_TYPE = api ]; then
sudo pwsh -NoProfile -NonInteractive -c "Import-Module ./tools/Travis.psm1;
Invoke-InstallDependencies;
Invoke-UnitTests;"
else
sudo pwsh -NoProfile -NonInteractive -c "Import-Module ./tools/Travis.psm1;
Invoke-InstallDependencies;
Invoke-UnitTests;"
fi