diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile new file mode 100644 index 0000000..eaa399a --- /dev/null +++ b/.devcontainer/Dockerfile @@ -0,0 +1,30 @@ +#------------------------------------------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See https://go.microsoft.com/fwlink/?linkid=2090316 for license information. +#------------------------------------------------------------------------------------------------------------- + +FROM mcr.microsoft.com/powershell:latest + +# This Dockerfile adds a non-root user with sudo access. Use the "remoteUser" +# property in devcontainer.json to use it. On Linux, the container user's GID/UIDs +# will be updated to match your local UID/GID (when using the dockerFile property). +# See https://aka.ms/vscode-remote/containers/non-root-user for details. +ARG USERNAME=vscode +ARG USER_UID=1000 +ARG USER_GID=$USER_UID + +# install git iproute2, process tools +RUN apt-get update && apt-get -y install git openssh-client less iproute2 procps \ + # Create a non-root user to use if preferred - see https://aka.ms/vscode-remote/containers/non-root-user. + && groupadd --gid $USER_GID $USERNAME \ + && useradd -s /bin/bash --uid $USER_UID --gid $USER_GID -m $USERNAME \ + # [Optional] Add sudo support for the non-root user + && apt-get install -y sudo \ + && echo $USERNAME ALL=\(root\) NOPASSWD:ALL > /etc/sudoers.d/$USERNAME\ + && chmod 0440 /etc/sudoers.d/$USERNAME \ + # + # Clean up + && apt-get autoremove -y \ + && apt-get clean -y \ + && rm -rf /var/lib/apt/lists/* + diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json new file mode 100644 index 0000000..5ee09f4 --- /dev/null +++ b/.devcontainer/devcontainer.json @@ -0,0 +1,26 @@ +{ + "name": "PowerShell", + "dockerFile": "Dockerfile", + // "image": "mcr.microsoft.com/powershell", + + // Set *default* container specific settings.json values on container create. + "settings": { + "terminal.integrated.shell.linux": "/usr/bin/pwsh" + }, + + // Add the IDs of extensions you want installed when the container is created. + "extensions": [ + "ms-vscode.powershell", + "davidanson.vscode-markdownlint" + ], + + // Use 'forwardPorts' to make a list of ports inside the container available locally. + // "forwardPorts": [], + + // Bootstrap build modules + "postCreateCommand": "pwsh -c './build.ps1 -Task Init -Bootstrap'", + + // Uncomment to connect as a non-root user. See https://aka.ms/vscode-remote/containers/non-root. + // "remoteUser": "vscode" +} + diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..aecf250 --- /dev/null +++ b/.gitattributes @@ -0,0 +1 @@ +* -crlf diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md new file mode 100644 index 0000000..a255169 --- /dev/null +++ b/.github/CONTRIBUTING.md @@ -0,0 +1,62 @@ +# How to contribute + +Contributions to WilmaPSWorker are highly encouraged and desired. +Below are some guidelines that will help make the process as smooth as possible. + +## Getting Started + +- Make sure you have a [GitHub account](https://github.com/signup/free) +- Submit a new issue, assuming one does not already exist. + - Clearly describe the issue including steps to reproduce when it is a bug. + - Make sure you fill in the earliest version that you know has the issue. +- Fork the repository on GitHub + +## Suggesting Enhancements + +I want to know what you think is missing from WilmaPSWorker and how it can be made better. + +- When submitting an issue for an enhancement, please be as clear as possible about why you think the enhancement is needed and what the benefit of it would be. + +## Making Changes + +- From your fork of the repository, create a topic branch where work on your change will take place. +- To quickly create a topic branch based on master; `git checkout -b my_contribution master`. + Please avoid working directly on the `master` branch. +- Make commits of logical units. +- Check for unnecessary whitespace with `git diff --check` before committing. +- Please follow the prevailing code conventions in the repository. + Differences in style make the code harder to understand for everyone. +- Make sure your commit messages are in the proper format. + +``` + Add more cowbell to Get-Something.ps1 + + The functionality of Get-Something would be greatly improved if there was a little + more 'pizzazz' added to it. I propose a cowbell. Adding more cowbell has been + shown in studies to both increase one's mojo, and cement one's status + as a rock legend. +``` + +- Make sure you have added all the necessary Pester tests for your changes. +- Run _all_ Pester tests in the module to assure nothing else was accidentally broken. + +## Documentation + +I am infallible and as such my documenation needs no corectoin. +In the highly unlikely event that that is _not_ the case, commits to update or add documentation are highly apprecaited. + +## Submitting Changes + +- Push your changes to a topic branch in your fork of the repository. +- Submit a pull request to the main repository. +- Once the pull request has been reviewed and accepted, it will be merged with the master branch. +- Celebrate + +## Additional Resources + +- [General GitHub documentation](https://help.github.com/) +- [GitHub forking documentation](https://guides.github.com/activities/forking/) +- [GitHub pull request documentation](https://help.github.com/send-pull-requests/) +- [GitHub Flow guide](https://guides.github.com/introduction/flow/) +- [GitHub's guide to contributing to open source projects](https://guides.github.com/activities/contributing-to-open-source/) + diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md new file mode 100644 index 0000000..20b368b --- /dev/null +++ b/.github/ISSUE_TEMPLATE.md @@ -0,0 +1,31 @@ + + +## Expected Behavior + + + +## Current Behavior + + + +## Possible Solution + + + +## Steps to Reproduce (for bugs) + + +1. +2. +3. +4. + +## Context + + + +## Your Environment + +* Module version used: +* Operating System and PowerShell version: + diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 0000000..d52e659 --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,37 @@ + + +## Description + + +## Related Issue + + + + + +## Motivation and Context + + +## How Has This Been Tested? + + + + +## Screenshots (if appropriate): + +## Types of changes + +- [ ] Bug fix (non-breaking change which fixes an issue) +- [ ] New feature (non-breaking change which adds functionality) +- [ ] Breaking change (fix or feature that would cause existing functionality to change) + +## Checklist: + + +- [ ] My code follows the code style of this project. +- [ ] My change requires a change to the documentation. +- [ ] I have updated the documentation accordingly. +- [ ] I have read the **CONTRIBUTING** document. +- [ ] I have added tests to cover my changes. +- [ ] All new and existing tests passed. + diff --git a/.gitignore b/.gitignore index e69de29..a5441ac 100644 --- a/.gitignore +++ b/.gitignore @@ -0,0 +1,2 @@ +# Don't check in the Output dir +Output/ diff --git a/.vscode/extensions.json b/.vscode/extensions.json new file mode 100644 index 0000000..f4b2d75 --- /dev/null +++ b/.vscode/extensions.json @@ -0,0 +1,8 @@ +{ + // See http://go.microsoft.com/fwlink/?LinkId=827846 + // for the documentation about the extensions.json format + "recommendations": [ + "ms-vscode.PowerShell", + "DavidAnson.vscode-markdownlint" + ] +} diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..b2ab8ee --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,7 @@ +{ + "files.trimTrailingWhitespace": true, + "files.insertFinalNewline": true, + "editor.insertSpaces": true, + "editor.tabSize": 4, + "powershell.codeFormatting.preset": "OTBS" +} diff --git a/.vscode/tasks.json b/.vscode/tasks.json new file mode 100644 index 0000000..106a76c --- /dev/null +++ b/.vscode/tasks.json @@ -0,0 +1,74 @@ +{ + // See https://go.microsoft.com/fwlink/?LinkId=733558 + // for the documentation about the tasks.json format + "version": "2.0.0", + + // Start PowerShell (pwsh on *nix) + "windows": { + "options": { + "shell": { + "executable": "powershell.exe", + "args": [ "-NoProfile", "-ExecutionPolicy", "Bypass", "-Command" ] + } + } + }, + "linux": { + "options": { + "shell": { + "executable": "/usr/bin/pwsh", + "args": [ "-NoProfile", "-Command" ] + } + } + }, + "osx": { + "options": { + "shell": { + "executable": "/usr/local/bin/pwsh", + "args": [ "-NoProfile", "-Command" ] + } + } + }, + + "tasks": [ + { + "label": "Clean", + "type": "shell", + "command": "${cwd}/build.ps1 -Task Clean -Verbose" + }, + { + "label": "Test", + "type": "shell", + "command": "${cwd}/build.ps1 -Task Test -Verbose", + "group": { + "kind": "test", + "isDefault": true + }, + "problemMatcher": "$pester" + }, + { + "label": "Analyze", + "type": "shell", + "command": "${cwd}/build.ps1 -Task Analyze -Verbose" + }, + { + "label": "Pester", + "type": "shell", + "command": "${cwd}/build.ps1 -Task Pester -Verbose", + "problemMatcher": "$pester" + }, + { + "label": "Build", + "type": "shell", + "command": "${cwd}/build.ps1 -Task Build -Verbose", + "group": { + "kind": "build", + "isDefault": true + } + }, + { + "label": "Publish", + "type": "shell", + "command": "${cwd}/build.ps1 -Task Publish -Verbose" + } + ] +} diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..ccc200a --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,9 @@ +# Change Log + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](http://keepachangelog.com/) +and this project adheres to [Semantic Versioning](http://semver.org/). + +## [0.0.1] Unreleased + diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..e1c8322 --- /dev/null +++ b/LICENSE @@ -0,0 +1,22 @@ +MIT License + +Copyright (c) 2021 Petri Asikainen + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + diff --git a/README.md b/README.md index 68773a7..87e6197 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,10 @@ -# VilmaPSWorker -Some powershell tool to interact with Visma Wilma \ No newline at end of file +# WilmaPSWorker + +Tools for Visma Wilma + +## Overview + +## Installation + +## Examples + diff --git a/WilmaPSWorker/Private/GetHelloWorld.ps1 b/WilmaPSWorker/Private/GetHelloWorld.ps1 new file mode 100644 index 0000000..c0dabe5 --- /dev/null +++ b/WilmaPSWorker/Private/GetHelloWorld.ps1 @@ -0,0 +1,3 @@ +function GetHelloWorld { + 'Hello world' +} diff --git a/WilmaPSWorker/Public/Get-HelloWorld.ps1 b/WilmaPSWorker/Public/Get-HelloWorld.ps1 new file mode 100644 index 0000000..7ad3837 --- /dev/null +++ b/WilmaPSWorker/Public/Get-HelloWorld.ps1 @@ -0,0 +1,22 @@ + +Function Get-HelloWorld { + <# + .SYNOPSIS + Returns Hello world + .DESCRIPTION + Returns Hello world + .EXAMPLE + PS> Get-HelloWorld + + Runs the command + #> + [OutputType([string])] + [CmdletBinding()] + param ( + # Parameter description can go here or above in format: .PARAMETER + [Parameter()] + [string]$Value = 'GetHelloWorld' + ) + + $Value +} diff --git a/WilmaPSWorker/WilmaPSWorker.psd1 b/WilmaPSWorker/WilmaPSWorker.psd1 new file mode 100644 index 0000000..b427af1 --- /dev/null +++ b/WilmaPSWorker/WilmaPSWorker.psd1 @@ -0,0 +1,124 @@ +# +# Module manifest for module 'WilmaPSWorker' +# +# Generated by: Petri Asikainen +# +# Generated on: 26.5.2021 +# + +@{ + +# Script module or binary module file associated with this manifest. +RootModule = 'WilmaPSWorker.psm1' + +# Version number of this module. +ModuleVersion = '0.0.1' + +# Supported PSEditions +# CompatiblePSEditions = @() + +# ID used to uniquely identify this module +GUID = 'e3692be6-afeb-44bd-8f80-3aa7dfa225d1' + +# Author of this module +Author = 'Petri Asikainen' + +# Company or vendor of this module +CompanyName = 'Unknown' + +# Copyright statement for this module +Copyright = '(c) 2021 Petri Asikainen. All rights reserved.' + +# Description of the functionality provided by this module +Description = 'Tools for Visma Wilma' + +# Minimum version of the Windows PowerShell engine required by this module +# PowerShellVersion = '' + +# Name of the Windows PowerShell host required by this module +# PowerShellHostName = '' + +# Minimum version of the Windows PowerShell host required by this module +# PowerShellHostVersion = '' + +# Minimum version of Microsoft .NET Framework required by this module. This prerequisite is valid for the PowerShell Desktop edition only. +# DotNetFrameworkVersion = '' + +# Minimum version of the common language runtime (CLR) required by this module. This prerequisite is valid for the PowerShell Desktop edition only. +# CLRVersion = '' + +# Processor architecture (None, X86, Amd64) required by this module +# ProcessorArchitecture = '' + +# Modules that must be imported into the global environment prior to importing this module +# RequiredModules = @() + +# Assemblies that must be loaded prior to importing this module +# RequiredAssemblies = @() + +# Script files (.ps1) that are run in the caller's environment prior to importing this module. +# ScriptsToProcess = @() + +# Type files (.ps1xml) to be loaded when importing this module +# TypesToProcess = @() + +# Format files (.ps1xml) to be loaded when importing this module +# FormatsToProcess = @() + +# Modules to import as nested modules of the module specified in RootModule/ModuleToProcess +# NestedModules = @() + +# Functions to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no functions to export. +FunctionsToExport = '*' + +# Cmdlets to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no cmdlets to export. +CmdletsToExport = '*' + +# Variables to export from this module +VariablesToExport = '*' + +# Aliases to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no aliases to export. +AliasesToExport = '*' + +# DSC resources to export from this module +# DscResourcesToExport = @() + +# List of all modules packaged with this module +# ModuleList = @() + +# List of all files packaged with this module +# FileList = @() + +# Private data to pass to the module specified in RootModule/ModuleToProcess. This may also contain a PSData hashtable with additional module metadata used by PowerShell. +PrivateData = @{ + + PSData = @{ + + # Tags applied to this module. These help with module discovery in online galleries. + # Tags = @() + + # A URL to the license for this module. + # LicenseUri = '' + + # A URL to the main website for this project. + # ProjectUri = '' + + # A URL to an icon representing this module. + # IconUri = '' + + # ReleaseNotes of this module + # ReleaseNotes = '' + + } # End of PSData hashtable + +} # End of PrivateData hashtable + +# HelpInfo URI of this module +# HelpInfoURI = '' + +# Default prefix for commands exported from this module. Override the default prefix using Import-Module -Prefix. +# DefaultCommandPrefix = '' + +} + + diff --git a/WilmaPSWorker/WilmaPSWorker.psm1 b/WilmaPSWorker/WilmaPSWorker.psm1 new file mode 100644 index 0000000..954f7a1 --- /dev/null +++ b/WilmaPSWorker/WilmaPSWorker.psm1 @@ -0,0 +1,12 @@ +# Dot source public/private functions +$public = @(Get-ChildItem -Path (Join-Path -Path $PSScriptRoot -ChildPath 'Public/*.ps1') -Recurse -ErrorAction Stop) +$private = @(Get-ChildItem -Path (Join-Path -Path $PSScriptRoot -ChildPath 'Private/*.ps1') -Recurse -ErrorAction Stop) +foreach ($import in @($public + $private)) { + try { + . $import.FullName + } catch { + throw "Unable to dot source [$($import.FullName)]" + } +} + +Export-ModuleMember -Function $public.Basename diff --git a/appveyor.yml b/appveyor.yml new file mode 100644 index 0000000..3fa39b5 --- /dev/null +++ b/appveyor.yml @@ -0,0 +1,18 @@ +version: 0.1.0.{build} + +environment: + matrix: + - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 + PowerShellEdition: PowerShellCore + - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 + PowerShellEdition: WindowsPowerShell + +skip_commits: + message: /updated readme.*|update readme.*s/ +build: off + +# Kick off the CI/CD pipeline +test_script: + - ps: if ($env:PowerShellEdition -eq 'WindowsPowerShell') { . .\build.ps1 -Task Test } + - pwsh: if ($env:PowerShellEdition -eq 'PowerShellCore') { . .\build.ps1 -Task Test } + diff --git a/build.ps1 b/build.ps1 new file mode 100644 index 0000000..338fdad --- /dev/null +++ b/build.ps1 @@ -0,0 +1,47 @@ +[cmdletbinding(DefaultParameterSetName = 'Task')] +param( + # Build task(s) to execute + [parameter(ParameterSetName = 'task', position = 0)] + [string[]]$Task = 'default', + + # Bootstrap dependencies + [switch]$Bootstrap, + + # List available build tasks + [parameter(ParameterSetName = 'Help')] + [switch]$Help, + + # Optional properties to pass to psake + [hashtable]$Properties, + + # Optional parameters to pass to psake + [hashtable]$Parameters +) + +$ErrorActionPreference = 'Stop' + +# Bootstrap dependencies +if ($Bootstrap.IsPresent) { + Get-PackageProvider -Name Nuget -ForceBootstrap | Out-Null + Set-PSRepository -Name PSGallery -InstallationPolicy Trusted + if ((Test-Path -Path ./requirements.psd1)) { + if (-not (Get-Module -Name PSDepend -ListAvailable)) { + Install-Module -Name PSDepend -Repository PSGallery -Scope CurrentUser -Force + } + Import-Module -Name PSDepend -Verbose:$false + Invoke-PSDepend -Path './requirements.psd1' -Install -Import -Force -WarningAction SilentlyContinue + } else { + Write-Warning 'No [requirements.psd1] found. Skipping build dependency installation.' + } +} + +# Execute psake task(s) +$psakeFile = './psakeFile.ps1' +if ($PSCmdlet.ParameterSetName -eq 'Help') { + Get-PSakeScriptTasks -buildFile $psakeFile | + Format-Table -Property Name, Description, Alias, DependsOn +} else { + Set-BuildEnvironment -Force + Invoke-psake -buildFile $psakeFile -taskList $Task -nologo -properties $Properties -parameters $Parameters + exit ([int](-not $psake.build_success)) +} diff --git a/docs/en-US/about_WilmaPSWorker.help.md b/docs/en-US/about_WilmaPSWorker.help.md new file mode 100644 index 0000000..eb08ad6 --- /dev/null +++ b/docs/en-US/about_WilmaPSWorker.help.md @@ -0,0 +1,59 @@ +# WilmaPSWorker + +## about_WilmaPSWorker + +``` +ABOUT TOPIC NOTE: +The first header of the about topic should be the topic name. +The second header contains the lookup name used by the help system. + +IE: +# Some Help Topic Name +## SomeHelpTopicFileName + +This will be transformed into the text file +as `about_SomeHelpTopicFileName`. +Do not include file extensions. +The second header should have no spaces. +``` + +# SHORT DESCRIPTION +{{ Short Description Placeholder }} + +``` +ABOUT TOPIC NOTE: +About topics can be no longer than 80 characters wide when rendered to text. +Any topics greater than 80 characters will be automatically wrapped. +The generated about topic will be encoded UTF-8. +``` + +# LONG DESCRIPTION +{{ Long Description Placeholder }} + +## Optional Subtopics +{{ Optional Subtopic Placeholder }} + +# EXAMPLES +{{ Code or descriptive examples of how to leverage the functions described. }} + +# NOTE +{{ Note Placeholder - Additional information that a user needs to know.}} + +# TROUBLESHOOTING NOTE +{{ Troubleshooting Placeholder - Warns users of bugs}} + +{{ Explains behavior that is likely to change with fixes }} + +# SEE ALSO +{{ See also placeholder }} + +{{ You can also list related articles, blogs, and video URLs. }} + +# KEYWORDS +{{List alternate names or titles for this topic that readers might use.}} + +- {{ Keyword Placeholder }} +- {{ Keyword Placeholder }} +- {{ Keyword Placeholder }} +- {{ Keyword Placeholder }} + diff --git a/psakeFile.ps1 b/psakeFile.ps1 new file mode 100644 index 0000000..9856d68 --- /dev/null +++ b/psakeFile.ps1 @@ -0,0 +1,10 @@ +properties { + # Set this to $true to create a module with a monolithic PSM1 + $PSBPreference.Build.CompileModule = $false + $PSBPreference.Help.DefaultLocale = 'en-US' + $PSBPreference.Test.OutputFile = 'out/testResults.xml' +} + +task Default -depends Test + +task Test -FromModule PowerShellBuild -minimumVersion '0.6.1' diff --git a/requirements.psd1 b/requirements.psd1 new file mode 100644 index 0000000..b62eddb --- /dev/null +++ b/requirements.psd1 @@ -0,0 +1,23 @@ +@{ + PSDependOptions = @{ + Target = 'CurrentUser' + } + 'Pester' = @{ + Version = '5.1.1' + Parameters = @{ + SkipPublisherCheck = $true + } + } + 'psake' = @{ + Version = '4.9.0' + } + 'BuildHelpers' = @{ + Version = '2.0.16' + } + 'PowerShellBuild' = @{ + Version = '0.6.1' + } + 'PSScriptAnalyzer' = @{ + Version = '1.19.1' + } +} diff --git a/tests/Help.tests.ps1 b/tests/Help.tests.ps1 new file mode 100644 index 0000000..4d4410c --- /dev/null +++ b/tests/Help.tests.ps1 @@ -0,0 +1,117 @@ +# Taken with love from @juneb_get_help (https://raw.githubusercontent.com/juneb/PesterTDD/master/Module.Help.Tests.ps1) + +BeforeDiscovery { + + function script:FilterOutCommonParams { + param ($Params) + $commonParams = @( + 'Debug', 'ErrorAction', 'ErrorVariable', 'InformationAction', 'InformationVariable', + 'OutBuffer', 'OutVariable', 'PipelineVariable', 'Verbose', 'WarningAction', + 'WarningVariable', 'Confirm', 'Whatif' + ) + $params | Where-Object { $_.Name -notin $commonParams } | Sort-Object -Property Name -Unique + } + + $manifest = Import-PowerShellDataFile -Path $env:BHPSModuleManifest + $outputDir = Join-Path -Path $env:BHProjectPath -ChildPath 'Output' + $outputModDir = Join-Path -Path $outputDir -ChildPath $env:BHProjectName + $outputModVerDir = Join-Path -Path $outputModDir -ChildPath $manifest.ModuleVersion + $outputModVerManifest = Join-Path -Path $outputModVerDir -ChildPath "$($env:BHProjectName).psd1" + + # Get module commands + # Remove all versions of the module from the session. Pester can't handle multiple versions. + Get-Module $env:BHProjectName | Remove-Module -Force -ErrorAction Ignore + Import-Module -Name $outputModVerManifest -Verbose:$false -ErrorAction Stop + $params = @{ + Module = (Get-Module $env:BHProjectName) + CommandType = [System.Management.Automation.CommandTypes[]]'Cmdlet, Function' # Not alias + } + if ($PSVersionTable.PSVersion.Major -lt 6) { + $params.CommandType[0] += 'Workflow' + } + $commands = Get-Command @params + + ## When testing help, remember that help is cached at the beginning of each session. + ## To test, restart session. +} + +Describe "Test help for <_.Name>" -ForEach $commands { + + BeforeDiscovery { + # Get command help, parameters, and links + $command = $_ + $commandHelp = Get-Help $command.Name -ErrorAction SilentlyContinue + $commandParameters = script:FilterOutCommonParams -Params $command.ParameterSets.Parameters + $commandParameterNames = $commandParameters.Name + $helpLinks = $commandHelp.relatedLinks.navigationLink.uri + } + + BeforeAll { + # These vars are needed in both discovery and test phases so we need to duplicate them here + $command = $_ + $commandName = $_.Name + $commandHelp = Get-Help $command.Name -ErrorAction SilentlyContinue + $commandParameters = script:FilterOutCommonParams -Params $command.ParameterSets.Parameters + $commandParameterNames = $commandParameters.Name + $helpParameters = script:FilterOutCommonParams -Params $commandHelp.Parameters.Parameter + $helpParameterNames = $helpParameters.Name + } + + # If help is not found, synopsis in auto-generated help is the syntax diagram + It 'Help is not auto-generated' { + $commandHelp.Synopsis | Should -Not -BeLike '*`[``]*' + } + + # Should be a description for every function + It "Has description" { + $commandHelp.Description | Should -Not -BeNullOrEmpty + } + + # Should be at least one example + It "Has example code" { + ($commandHelp.Examples.Example | Select-Object -First 1).Code | Should -Not -BeNullOrEmpty + } + + # Should be at least one example description + It "Has example help" { + ($commandHelp.Examples.Example.Remarks | Select-Object -First 1).Text | Should -Not -BeNullOrEmpty + } + + It "Help link <_> is valid" -ForEach $helpLinks { + (Invoke-WebRequest -Uri $_ -UseBasicParsing).StatusCode | Should -Be '200' + } + + Context "Parameter <_.Name>" -Foreach $commandParameters { + + BeforeAll { + $parameter = $_ + $parameterName = $parameter.Name + $parameterHelp = $commandHelp.parameters.parameter | Where-Object Name -eq $parameterName + $parameterHelpType = if ($parameterHelp.ParameterValue) { $parameterHelp.ParameterValue.Trim() } + } + + # Should be a description for every parameter + It "Has description" { + $parameterHelp.Description.Text | Should -Not -BeNullOrEmpty + } + + # Required value in Help should match IsMandatory property of parameter + It "Has correct [mandatory] value" { + $codeMandatory = $_.IsMandatory.toString() + $parameterHelp.Required | Should -Be $codeMandatory + } + + # Parameter type in help should match code + It "Has correct parameter type" { + $parameterHelpType | Should -Be $parameter.ParameterType.Name + } + } + + Context "Test <_> help parameter help for " -Foreach $helpParameterNames { + + # Shouldn't find extra parameters in help. + It "finds help parameter in code: <_>" { + $_ -in $parameterNames | Should -Be $true + } + } +} diff --git a/tests/Manifest.tests.ps1 b/tests/Manifest.tests.ps1 new file mode 100644 index 0000000..001ae7b --- /dev/null +++ b/tests/Manifest.tests.ps1 @@ -0,0 +1,85 @@ +BeforeAll { + $moduleName = $env:BHProjectName + $manifest = Import-PowerShellDataFile -Path $env:BHPSModuleManifest + $outputDir = Join-Path -Path $ENV:BHProjectPath -ChildPath 'Output' + $outputModDir = Join-Path -Path $outputDir -ChildPath $env:BHProjectName + $outputModVerDir = Join-Path -Path $outputModDir -ChildPath $manifest.ModuleVersion + $outputManifestPath = Join-Path -Path $outputModVerDir -Child "$($moduleName).psd1" + $manifestData = Test-ModuleManifest -Path $outputManifestPath -Verbose:$false -ErrorAction Stop -WarningAction SilentlyContinue + + $changelogPath = Join-Path -Path $env:BHProjectPath -Child 'CHANGELOG.md' + $changelogVersion = Get-Content $changelogPath | ForEach-Object { + if ($_ -match "^##\s\[(?(\d+\.){1,3}\d+)\]") { + $changelogVersion = $matches.Version + break + } + } + + $script:manifest = $null +} +Describe 'Module manifest' { + + Context 'Validation' { + + It 'Has a valid manifest' { + $manifestData | Should -Not -BeNullOrEmpty + } + + It 'Has a valid name in the manifest' { + $manifestData.Name | Should -Be $moduleName + } + + It 'Has a valid root module' { + $manifestData.RootModule | Should -Be "$($moduleName).psm1" + } + + It 'Has a valid version in the manifest' { + $manifestData.Version -as [Version] | Should -Not -BeNullOrEmpty + } + + It 'Has a valid description' { + $manifestData.Description | Should -Not -BeNullOrEmpty + } + + It 'Has a valid author' { + $manifestData.Author | Should -Not -BeNullOrEmpty + } + + It 'Has a valid guid' { + {[guid]::Parse($manifestData.Guid)} | Should -Not -Throw + } + + It 'Has a valid copyright' { + $manifestData.CopyRight | Should -Not -BeNullOrEmpty + } + + It 'Has a valid version in the changelog' { + $changelogVersion | Should -Not -BeNullOrEmpty + $changelogVersion -as [Version] | Should -Not -BeNullOrEmpty + } + + It 'Changelog and manifest versions are the same' { + $changelogVersion -as [Version] | Should -Be ( $manifestData.Version -as [Version] ) + } + } +} + +Describe 'Git tagging' -Skip { + BeforeAll { + $gitTagVersion = $null + + if ($git = Get-Command git -CommandType Application -ErrorAction SilentlyContinue) { + $thisCommit = & $git log --decorate --oneline HEAD~1..HEAD + if ($thisCommit -match 'tag:\s*(\d+(?:\.\d+)*)') { $gitTagVersion = $matches[1] } + } + } + + It 'Is tagged with a valid version' { + $gitTagVersion | Should -Not -BeNullOrEmpty + $gitTagVersion -as [Version] | Should -Not -BeNullOrEmpty + } + + It 'Matches manifest version' { + $manifestData.Version -as [Version] | Should -Be ( $gitTagVersion -as [Version]) + } +} diff --git a/tests/Meta.tests.ps1 b/tests/Meta.tests.ps1 new file mode 100644 index 0000000..4c9457c --- /dev/null +++ b/tests/Meta.tests.ps1 @@ -0,0 +1,50 @@ +BeforeAll { + + Set-StrictMode -Version latest + + # Make sure MetaFixers.psm1 is loaded - it contains Get-TextFilesList + Import-Module -Name (Join-Path -Path $PSScriptRoot -ChildPath 'MetaFixers.psm1') -Verbose:$false -Force + + $projectRoot = $ENV:BHProjectPath + if (-not $projectRoot) { + $projectRoot = $PSScriptRoot + } + + $allTextFiles = Get-TextFilesList $projectRoot + $unicodeFilesCount = 0 + $totalTabsCount = 0 + foreach ($textFile in $allTextFiles) { + if (Test-FileUnicode $textFile) { + $unicodeFilesCount++ + Write-Warning ( + "File $($textFile.FullName) contains 0x00 bytes." + + " It probably uses Unicode/UTF-16 and needs to be converted to UTF-8." + + " Use Fixer 'Get-UnicodeFilesList `$pwd | ConvertTo-UTF8'." + ) + } + $unicodeFilesCount | Should -Be 0 + + $fileName = $textFile.FullName + (Get-Content $fileName -Raw) | Select-String "`t" | Foreach-Object { + Write-Warning ( + "There are tabs in $fileName." + + " Use Fixer 'Get-TextFilesList `$pwd | ConvertTo-SpaceIndentation'." + ) + $totalTabsCount++ + } + } +} + +Describe 'Text files formatting' { + Context 'File encoding' { + It "No text file uses Unicode/UTF-16 encoding" { + $unicodeFilesCount | Should -Be 0 + } + } + + Context 'Indentations' { + It "No text file use tabs for indentations" { + $totalTabsCount | Should -Be 0 + } + } +} diff --git a/tests/MetaFixers.psm1 b/tests/MetaFixers.psm1 new file mode 100644 index 0000000..8db1c89 --- /dev/null +++ b/tests/MetaFixers.psm1 @@ -0,0 +1,80 @@ +# Taken with love from https://github.com/PowerShell/DscResource.Tests/blob/master/MetaFixers.psm1 + +<# + This module helps fix problems, found by Meta.Tests.ps1 +#> + +$ErrorActionPreference = 'stop' +Set-StrictMode -Version latest + +function ConvertTo-UTF8() { + [CmdletBinding()] + [OutputType([void])] + param( + [Parameter(Mandatory, ValueFromPipeline)] + [System.IO.FileInfo]$FileInfo + ) + + process { + $content = Get-Content -Raw -Encoding Unicode -Path $FileInfo.FullName + [System.IO.File]::WriteAllText($FileInfo.FullName, $content, [System.Text.Encoding]::UTF8) + } +} + +function ConvertTo-SpaceIndentation() { + [CmdletBinding()] + [OutputType([void])] + param( + [Parameter(Mandatory, ValueFromPipeline)] + [IO.FileInfo]$FileInfo + ) + + process { + $content = (Get-Content -Raw -Path $FileInfo.FullName) -replace "`t", ' ' + [IO.File]::WriteAllText($FileInfo.FullName, $content) + } +} + +function Get-TextFilesList { + [CmdletBinding()] + [OutputType([IO.FileInfo])] + param( + [Parameter(Mandatory, ValueFromPipeline)] + [string]$Root + ) + + begin { + $txtFileExtentions = @('.gitignore', '.gitattributes', '.ps1', '.psm1', '.psd1', '.json', '.xml', '.cmd', '.mof') + } + + process { + Get-ChildItem -Path $Root -File -Recurse | + Where-Object { $_.Extension -in $txtFileExtentions } + } +} + +function Test-FileUnicode { + [CmdletBinding()] + [OutputType([bool])] + param( + [Parameter(Mandatory, ValueFromPipeline)] + [IO.FileInfo]$FileInfo + ) + + process { + $bytes = [IO.File]::ReadAllBytes($FileInfo.FullName) + $zeroBytes = @($bytes -eq 0) + return [bool]$zeroBytes.Length + } +} + +function Get-UnicodeFilesList() { + [CmdletBinding()] + [OutputType([IO.FileInfo])] + param( + [Parameter(Mandatory)] + [string]$Root + ) + + $root | Get-TextFilesList | Where-Object { Test-FileUnicode $_ } +} diff --git a/tests/ScriptAnalyzerSettings.psd1 b/tests/ScriptAnalyzerSettings.psd1 new file mode 100644 index 0000000..8fe45b9 --- /dev/null +++ b/tests/ScriptAnalyzerSettings.psd1 @@ -0,0 +1,3 @@ +@{ + +} diff --git a/tests/out/.gitkeep b/tests/out/.gitkeep new file mode 100644 index 0000000..e69de29