From b2fb02c8a7024a5c9772873dfef8da0188834f5a Mon Sep 17 00:00:00 2001 From: Johan Ljunggren Date: Mon, 18 Jul 2022 20:27:34 +0200 Subject: [PATCH] Update pipeline files to the latest in Sampler (#77) --- .gitattributes | 9 +- .github/ISSUE_TEMPLATE/Problem_with_module.md | 41 ---- .../ISSUE_TEMPLATE/Problem_with_module.yml | 101 ++++++++++ .github/ISSUE_TEMPLATE/config.yml | 5 + .gitignore | 19 +- .vscode/settings.json | 1 + CHANGELOG.md | 9 +- README.md | 1 + Resolve-Dependency.ps1 | 122 ++++++++++-- SECURITY.md | 31 +++ azure-pipelines.yml | 186 +++++++++++------- build.ps1 | 65 +++--- build.yaml | 34 +++- codecov.yml | 25 +++ source/WikiSource/Home.md | 9 + tests/QA/module.tests.ps1 | 41 +++- 16 files changed, 526 insertions(+), 173 deletions(-) delete mode 100644 .github/ISSUE_TEMPLATE/Problem_with_module.md create mode 100644 .github/ISSUE_TEMPLATE/Problem_with_module.yml create mode 100644 .github/ISSUE_TEMPLATE/config.yml create mode 100644 SECURITY.md create mode 100644 codecov.yml create mode 100644 source/WikiSource/Home.md diff --git a/.gitattributes b/.gitattributes index d49b050..96c2e0d 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,8 +1,15 @@ # Needed for publishing of examples, build worker defaults to core.autocrlf=input. -* text eol=crlf +* text eol=autocrlf + +*.mof text eol=crlf +*.sh text eol=lf +*.svg eol=lf # Ensure any exe files are treated as binary *.exe binary *.jpg binary *.xl* binary *.pfx binary +*.png binary +*.dll binary +*.so binary diff --git a/.github/ISSUE_TEMPLATE/Problem_with_module.md b/.github/ISSUE_TEMPLATE/Problem_with_module.md deleted file mode 100644 index fbcdf8a..0000000 --- a/.github/ISSUE_TEMPLATE/Problem_with_module.md +++ /dev/null @@ -1,41 +0,0 @@ ---- -name: Problem with the module -about: If you have a problem, bug, or enhancement with the module. ---- - -#### Details of the scenario you tried and the problem that is occurring - -#### Steps to reproduce the problem - -#### Expected behavior - -#### Current behavior - -#### Suggested solution to the issue - -#### The operating system the target node is running - -#### Version and build of PowerShell the target node is running - - -#### Version of the module that was used - diff --git a/.github/ISSUE_TEMPLATE/Problem_with_module.yml b/.github/ISSUE_TEMPLATE/Problem_with_module.yml new file mode 100644 index 0000000..76f94fc --- /dev/null +++ b/.github/ISSUE_TEMPLATE/Problem_with_module.yml @@ -0,0 +1,101 @@ +name: Problem with the module +description: If you have a problem using this module, want to report a bug, or suggest an enhancement to this module. +labels: [] +assignees: [] +body: + - type: markdown + attributes: + value: | + TITLE: Please be descriptive not sensationalist. + + Your feedback and support is greatly appreciated, thanks for contributing! + + Please provide information regarding your issue under each section below. + **Write N/A in sections that do not apply, or if the information is not available.** + - type: textarea + id: description + attributes: + label: Problem description + description: Details of the scenario you tried and the problem that is occurring, or the enhancement you are suggesting. + validations: + required: true + - type: textarea + id: logs + attributes: + label: Verbose logs + description: | + Verbose logs showing the problem. **NOTE! Sensitive information should be obfuscated.** _Will be automatically formatted as plain text._ + placeholder: | + Paste verbose logs here + render: text + validations: + required: true + - type: textarea + id: reproducible + attributes: + label: How to reproduce + description: Provide the steps to reproduce the problem. + validations: + required: true + - type: textarea + id: expectedBehavior + attributes: + label: Expected behavior + description: Describe what you expected to happen. + validations: + required: true + - type: textarea + id: currentBehavior + attributes: + label: Current behavior + description: Describe what actually happens. + validations: + required: true + - type: textarea + id: suggestedSolution + attributes: + label: Suggested solution + description: Do you have any suggestions how to solve the issue? + validations: + required: true + - type: textarea + id: targetNodeOS + attributes: + label: Operating system the target node is running + description: | + Please provide as much as possible about the node running DscResource.Common. _Will be automatically formatted as plain text._ + + To help with this information: + - On a Linux distribution, please provide the distribution name, version, and release. The following command can help get this information: `cat /etc/*-release && cat /proc/version` + - On a Windows OS please provide edition, version, build, and language. The following command can help get this information: `Get-ComputerInfo -Property @('OsName','OsOperatingSystemSKU','OSArchitecture','WindowsVersion','WindowsBuildLabEx','OsLanguage','OsMuiLanguages')` + placeholder: | + Add operating system information here + render: text + validations: + required: true + - type: textarea + id: targetNodePS + attributes: + label: PowerShell version and build the target node is running + description: | + Please provide the version and build of PowerShell the target node is running. _Will be automatically formatted as plain text._ + + To help with this information, please run this command: `$PSVersionTable` + placeholder: | + Add PowerShell information here + render: text + validations: + required: true + - type: textarea + id: moduleVersion + attributes: + label: Module version used + description: | + Please provide the version of the DscResource.Common module that was used. _Will be automatically formatted as plain text._ + + To help with this information, please run this command: `Get-Module -Name 'DscResource.Common' -ListAvailable | ft Name,Version,Path` + placeholder: | + Add module information here + render: text + validations: + required: true diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 0000000..4cd6921 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1,5 @@ +blank_issues_enabled: false +contact_links: + - name: "Virtual PowerShell User Group #DSC channel" + url: https://dsccommunity.org/community/contact/ + about: "To talk to the community and maintainers of DSC Community, please visit the #DSC channel." diff --git a/.gitignore b/.gitignore index 1733276..41a28dd 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,18 @@ -.vscode -.vs output/ + +**.bak +*.local.* +!**/README.md +.kitchen/ + +*.nupkg +*.suo +*.user +*.coverage +.vs +.vscode +.psproj +.sln +markdownissues.txt +node_modules +package-lock.json diff --git a/.vscode/settings.json b/.vscode/settings.json index 1ff4925..2f0a10e 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -35,6 +35,7 @@ "steppable" ], "[markdown]": { + "files.trimTrailingWhitespace": true, "files.encoding": "utf8" } } diff --git a/CHANGELOG.md b/CHANGELOG.md index ab20ad4..644df5d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,12 +1,17 @@ -# Changelog +# Changelog for DscResource.Common All notable changes to this project will be documented in this file. -The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +The format is based on and uses the types of changes according to [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [Unreleased] +### Changed + +- DscResource.Common + - Update pipeline files to the latest in Sampler. + ### Fixed - Correction to `Compare-DscParameterState` returning false positive when parameter diff --git a/README.md b/README.md index 79e1b6b..8318b18 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,7 @@ [![Build Status](https://dev.azure.com/dsccommunity/DscResource.Common/_apis/build/status/dsccommunity.DscResource.Common?branchName=main)](https://dev.azure.com/dsccommunity/DscResource.Common/_build/latest?definitionId=4&branchName=main) ![Azure DevOps coverage (branch)](https://img.shields.io/azure-devops/coverage/dsccommunity/DscResource.Common/4/main) +[![codecov](https://codecov.io/gh/dsccommunity/DscResource.Common/branch/main/graph/badge.svg)](https://codecov.io/gh/dsccommunity/DscResource.Common) [![Azure DevOps tests](https://img.shields.io/azure-devops/tests/dsccommunity/DscResource.Common/4/main)](https://dsccommunity.visualstudio.com/DscResource.Common/_test/analytics?definitionId=4&contextType=build) [![PowerShell Gallery (with prereleases)](https://img.shields.io/powershellgallery/vpre/DscResource.Common?label=DscResource.Common%20Preview)](https://www.powershellgallery.com/packages/DscResource.Common/) [![PowerShell Gallery](https://img.shields.io/powershellgallery/v/DscResource.Common?label=DscResource.Common)](https://www.powershellgallery.com/packages/DscResource.Common/) diff --git a/Resolve-Dependency.ps1 b/Resolve-Dependency.ps1 index 760df23..3848462 100644 --- a/Resolve-Dependency.ps1 +++ b/Resolve-Dependency.ps1 @@ -9,7 +9,7 @@ .PARAMETER PSDependTarget Path for PSDepend to be bootstrapped and save other dependencies. Can also be CurrentUser or AllUsers if you wish to install the modules in - such scope. The default value is './output/RequiredModules' relative to + such scope. The default value is 'output/RequiredModules' relative to this script's path. .PARAMETER Proxy @@ -59,7 +59,7 @@ param [Parameter()] [System.String] - $PSDependTarget = (Join-Path -Path $PSScriptRoot -ChildPath './output/RequiredModules'), + $PSDependTarget = (Join-Path -Path $PSScriptRoot -ChildPath 'output/RequiredModules'), [Parameter()] [System.Uri] @@ -96,7 +96,11 @@ param [Parameter()] [System.Management.Automation.SwitchParameter] - $WithYAML + $WithYAML, + + [Parameter()] + [System.Collections.Hashtable] + $RegisterGallery ) try @@ -138,7 +142,7 @@ try { if (-not $PSBoundParameters.Keys.Contains($parameterName) -and $resolveDependencyDefaults.ContainsKey($parameterName)) { - Write-Verbose -Message "Setting $parameterName with $($resolveDependencyDefaults[$parameterName])." + Write-Verbose -Message "Setting parameter '$parameterName' to value '$($resolveDependencyDefaults[$parameterName])'." try { @@ -207,6 +211,7 @@ if (-not $powerShellGetModule -and -not $nuGetProvider) Write-Information -MessageData 'Bootstrap: Installing NuGet Package Provider from the web (Make sure Microsoft addresses/ranges are allowed).' + # TODO: This does not handle a private Gallery yet. $null = Install-PackageProvider @providerBootstrapParams $nuGetProvider = Get-PackageProvider -Name 'NuGet' -ListAvailable | Select-Object -First 1 @@ -218,12 +223,50 @@ if (-not $powerShellGetModule -and -not $nuGetProvider) $Null = Import-PackageProvider -Name 'NuGet' -RequiredVersion $nuGetProviderVersion -Force } +if ($RegisterGallery) +{ + if ($RegisterGallery.ContainsKey('Name') -and -not [System.String]::IsNullOrEmpty($RegisterGallery.Name)) + { + $Gallery = $RegisterGallery.Name + } + else + { + $RegisterGallery.Name = $Gallery + } + + Write-Progress -Activity 'Bootstrap:' -PercentComplete 7 -CurrentOperation "Verifying private package repository '$Gallery'" -Completed + + $previousRegisteredRepository = Get-PSRepository -Name $Gallery -ErrorAction 'SilentlyContinue' + + if ($previousRegisteredRepository.SourceLocation -ne $RegisterGallery.SourceLocation) + { + if ($previousRegisteredRepository) + { + Write-Progress -Activity 'Bootstrap:' -PercentComplete 9 -CurrentOperation "Re-registrering private package repository '$Gallery'" -Completed + + Unregister-PSRepository -Name $Gallery + + $unregisteredPreviousRepository = $true + } + else + { + Write-Progress -Activity 'Bootstrap:' -PercentComplete 9 -CurrentOperation "Registering private package repository '$Gallery'" -Completed + } + + Register-PSRepository @RegisterGallery + } +} + Write-Progress -Activity 'Bootstrap:' -PercentComplete 10 -CurrentOperation "Ensuring Gallery $Gallery is trusted" # Fail if the given PSGallery is not registered. $previousGalleryInstallationPolicy = (Get-PSRepository -Name $Gallery -ErrorAction 'Stop').InstallationPolicy -Set-PSRepository -Name $Gallery -InstallationPolicy 'Trusted' -ErrorAction 'Ignore' +if ($previousGalleryInstallationPolicy -ne 'Trusted') +{ + # Only change policy if the repository is not trusted + Set-PSRepository -Name $Gallery -InstallationPolicy 'Trusted' -ErrorAction 'Ignore' +} try { @@ -290,7 +333,14 @@ try if ($PSBoundParameters.ContainsKey('MinimumPSDependVersion')) { - $psDependModule = $psDependModule | Where-Object -Property -eq $MinimumPSDependVersion + try + { + $psDependModule = $psDependModule | Where-Object -FilterScript { $_.Version -ge $MinimumPSDependVersion } + } + catch + { + throw ('There was a problem finding the minimum version of PSDepend. Error: {0}' -f $_) + } } if (-not $psDependModule) @@ -298,7 +348,7 @@ try # PSDepend module not found, installing or saving it. if ($PSDependTarget -in 'CurrentUser', 'AllUsers') { - Write-Debug -Message "PSDepend module not found. Attempting to install from Gallery $Gallery." + Write-Debug -Message "PSDepend module not found. Attempting to install from Gallery '$Gallery'." Write-Warning -Message "Installing PSDepend in $PSDependTarget Scope." @@ -328,6 +378,7 @@ try Name = 'PSDepend' Repository = $Gallery Path = $PSDependTarget + Force = $true } if ($MinimumPSDependVersion) @@ -365,12 +416,13 @@ try { Write-Progress -Activity 'Bootstrap:' -PercentComplete 85 -CurrentOperation 'Installing PowerShell module PowerShell-Yaml' - Write-Verbose -Message "PowerShell-Yaml module not found. Attempting to Save from Gallery $Gallery to $PSDependTarget" + Write-Verbose -Message "PowerShell-Yaml module not found. Attempting to Save from Gallery '$Gallery' to '$PSDependTarget'." $SaveModuleParam = @{ Name = 'PowerShell-Yaml' Repository = $Gallery Path = $PSDependTarget + Force = $true } Save-Module @SaveModuleParam @@ -379,10 +431,6 @@ try { Write-Verbose "PowerShell-Yaml is already available" } - - Write-Progress -Activity 'Bootstrap:' -PercentComplete 88 -CurrentOperation 'Importing PowerShell module PowerShell-Yaml' - - Import-Module -Name 'PowerShell-Yaml' -ErrorAction 'Stop' } Write-Progress -Activity 'Bootstrap:' -PercentComplete 90 -CurrentOperation 'Invoke PSDepend' @@ -406,7 +454,53 @@ try } finally { - # Reverting the Installation Policy for the given gallery - Set-PSRepository -Name $Gallery -InstallationPolicy $previousGalleryInstallationPolicy + if ($RegisterGallery) + { + Write-Verbose -Message "Removing private package repository '$Gallery'." + Unregister-PSRepository -Name $Gallery + } + + if ($unregisteredPreviousRepository) + { + Write-Verbose -Message "Reverting private package repository '$Gallery' to previous location URI:s." + + $registerPSRepositoryParameters = @{ + Name = $previousRegisteredRepository.Name + InstallationPolicy = $previousRegisteredRepository.InstallationPolicy + } + + if ($previousRegisteredRepository.SourceLocation) + { + $registerPSRepositoryParameters.SourceLocation = $previousRegisteredRepository.SourceLocation + } + + if ($previousRegisteredRepository.PublishLocation) + { + $registerPSRepositoryParameters.PublishLocation = $previousRegisteredRepository.PublishLocation + } + + if ($previousRegisteredRepository.ScriptSourceLocation) + { + $registerPSRepositoryParameters.ScriptSourceLocation = $previousRegisteredRepository.ScriptSourceLocation + } + + if ($previousRegisteredRepository.ScriptPublishLocation) + { + $registerPSRepositoryParameters.ScriptPublishLocation = $previousRegisteredRepository.ScriptPublishLocation + } + + Register-PSRepository @registerPSRepositoryParameters + } + + # Only try to revert installation policy if the repository exist + if ((Get-PSRepository -Name $Gallery -ErrorAction 'SilentlyContinue')) + { + if ($previousGalleryInstallationPolicy -and $previousGalleryInstallationPolicy -ne 'Trusted') + { + # Reverting the Installation Policy for the given gallery if it was not already trusted + Set-PSRepository -Name $Gallery -InstallationPolicy $previousGalleryInstallationPolicy + } + } + Write-Verbose -Message "Project Bootstrapped, returning to Invoke-Build" } diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 0000000..c804d2d --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,31 @@ +## Security + +We take the security of our modules seriously, which includes all source code repositories managed through our GitHub organization. + +If you believe you have found a security vulnerability in any of our repository, please report it to us as described below. + +## Reporting Security Issues + +**Please do not report security vulnerabilities through public GitHub issues.** + +Instead, please report them to one or several maintainers of the repository. +The easiest way to do so is to send us a direct message via twitter or find us +on some other social platform. + +You should receive a response within 48 hours. If for some reason you do not, please follow up by other means or to other contributors. + +Please include the requested information listed below (as much as you can provide) to help us better understand the nature and scope of the possible issue: + + * Type of issue + * Full paths of source file(s) related to the manifestation of the issue + * The location of the affected source code (tag/branch/commit or direct URL) + * Any special configuration required to reproduce the issue + * Step-by-step instructions to reproduce the issue + * Proof-of-concept or exploit code (if possible) + * Impact of the issue, including how an attacker might exploit the issue + +This information will help us triage your report more quickly. + +## Preferred Languages + +We prefer all communications to be in English. diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 518670e..3fe5a61 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -10,11 +10,12 @@ trigger: - "v*" exclude: - "*-*" + variables: buildFolderName: output buildArtifactName: output testResultFolderName: testResults - testArtifactName: testResults + defaultBranch: main stages: - stage: Build @@ -22,14 +23,17 @@ stages: - job: Package_Module displayName: 'Package Module' pool: - vmImage: 'ubuntu 16.04' + vmImage: 'ubuntu-latest' steps: - - task: GitVersion@5 - name: gitVersion - displayName: 'Evaluate Next Version' - inputs: - runtime: 'core' - configFilePath: 'GitVersion.yml' + - pwsh: | + dotnet tool install --global GitVersion.Tool + $gitVersionObject = dotnet-gitversion | ConvertFrom-Json + $gitVersionObject.PSObject.Properties.ForEach{ + Write-Host -Object "Setting Task Variable '$($_.Name)' with value '$($_.Value)'." + Write-Host -Object "##vso[task.setvariable variable=$($_.Name);]$($_.Value)" + } + Write-Host -Object "##vso[build.updatebuildnumber]$($gitVersionObject.FullSemVer)" + displayName: Calculate ModuleVersion (GitVersion) - task: PowerShell@2 name: package displayName: 'Build & Package Module' @@ -38,13 +42,14 @@ stages: arguments: '-ResolveDependency -tasks pack' pwsh: true env: - ModuleVersion: $(gitVersion.NuGetVersionV2) - - task: PublishBuildArtifacts@1 + ModuleVersion: $(NuGetVersionV2) + - task: PublishPipelineArtifact@1 displayName: 'Publish Build Artifact' inputs: - pathToPublish: 'output/' - artifactName: 'output' - publishLocation: 'Container' + targetPath: '$(buildFolderName)/' + artifact: $(buildArtifactName) + publishLocation: 'pipeline' + parallel: true - stage: Test dependsOn: Build @@ -52,16 +57,15 @@ stages: - job: Test_HQRM displayName: 'HQRM' pool: - vmImage: 'windows-2019' + vmImage: 'windows-latest' timeoutInMinutes: 0 steps: - - task: DownloadBuildArtifacts@0 + - task: DownloadPipelineArtifact@2 displayName: 'Download Build Artifact' inputs: buildType: 'current' - downloadType: 'single' - artifactName: 'output' - downloadPath: '$(Build.SourcesDirectory)' + artifactName: $(buildArtifactName) + targetPath: '$(Build.SourcesDirectory)/$(buildFolderName)' - task: PowerShell@2 name: test displayName: 'Run HQRM Test' @@ -81,15 +85,14 @@ stages: displayName: 'Linux' timeoutInMinutes: 0 pool: - vmImage: 'ubuntu 16.04' + vmImage: 'ubuntu-latest' steps: - - task: DownloadBuildArtifacts@0 + - task: DownloadPipelineArtifact@2 displayName: 'Download Build Artifact' inputs: buildType: 'current' - downloadType: 'single' - artifactName: 'output' - downloadPath: '$(Build.SourcesDirectory)' + artifactName: $(buildArtifactName) + targetPath: '$(Build.SourcesDirectory)/$(buildFolderName)' - task: PowerShell@2 name: test displayName: 'Run Tests' @@ -103,20 +106,26 @@ stages: testResultsFormat: 'NUnit' testResultsFiles: '$(buildFolderName)/$(testResultFolderName)/NUnit*.xml' testRunTitle: 'Linux' + - task: PublishPipelineArtifact@1 + displayName: 'Publish Test Artifact' + condition: succeededOrFailed() + inputs: + targetPath: '$(buildFolderName)/$(testResultFolderName)/' + artifactName: 'CodeCoverageLinux_$(System.JobAttempt)' + parallel: true - job: test_windows_core displayName: 'Windows (PowerShell Core)' timeoutInMinutes: 0 pool: - vmImage: 'windows-2019' + vmImage: 'windows-latest' steps: - - task: DownloadBuildArtifacts@0 + - task: DownloadPipelineArtifact@2 displayName: 'Download Build Artifact' inputs: buildType: 'current' - downloadType: 'single' - artifactName: 'output' - downloadPath: '$(Build.SourcesDirectory)' + artifactName: $(buildArtifactName) + targetPath: '$(Build.SourcesDirectory)/$(buildFolderName)' - task: PowerShell@2 name: test displayName: 'Run Tests' @@ -130,21 +139,27 @@ stages: inputs: testResultsFormat: 'NUnit' testResultsFiles: '$(buildFolderName)/$(testResultFolderName)/NUnit*.xml' - testRunTitle: 'Windows Server (PowerShell Core)' + testRunTitle: 'Windows Server Core (PowerShell Core)' + - task: PublishPipelineArtifact@1 + displayName: 'Publish Test Artifact' + condition: succeededOrFailed() + inputs: + targetPath: '$(buildFolderName)/$(testResultFolderName)/' + artifactName: 'CodeCoverageWinPS7_$(System.JobAttempt)' + parallel: true - job: test_windows_ps displayName: 'Windows (Windows PowerShell)' timeoutInMinutes: 0 pool: - vmImage: 'windows-2019' + vmImage: 'windows-latest' steps: - - task: DownloadBuildArtifacts@0 + - task: DownloadPipelineArtifact@2 displayName: 'Download Build Artifact' inputs: buildType: 'current' - downloadType: 'single' - artifactName: 'output' - downloadPath: '$(Build.SourcesDirectory)' + artifactName: $(buildArtifactName) + targetPath: '$(Build.SourcesDirectory)/$(buildFolderName)' - task: PowerShell@2 name: test displayName: 'Run Tests' @@ -158,13 +173,14 @@ stages: inputs: testResultsFormat: 'NUnit' testResultsFiles: '$(buildFolderName)/$(testResultFolderName)/NUnit*.xml' - testRunTitle: 'Windows Server (Windows PowerShell)' - - task: PublishBuildArtifacts@1 + testRunTitle: 'Windows Server Core (Windows PowerShell)' + - task: PublishPipelineArtifact@1 displayName: 'Publish Test Artifact' + condition: succeededOrFailed() inputs: - pathToPublish: '$(buildFolderName)/$(testResultFolderName)/' - artifactName: $(testArtifactName) - publishLocation: 'Container' + targetPath: '$(buildFolderName)/$(testResultFolderName)/' + artifactName: 'CodeCoverageWinPS51_$(System.JobAttempt)' + parallel: true - job: test_macos displayName: 'macOS' @@ -172,13 +188,12 @@ stages: pool: vmImage: 'macos-latest' steps: - - task: DownloadBuildArtifacts@0 + - task: DownloadPipelineArtifact@2 displayName: 'Download Build Artifact' inputs: buildType: 'current' - downloadType: 'single' - artifactName: 'output' - downloadPath: '$(Build.SourcesDirectory)' + artifactName: $(buildArtifactName) + targetPath: '$(Build.SourcesDirectory)/$(buildFolderName)' - task: PowerShell@2 name: test displayName: 'Run Tests' @@ -193,45 +208,72 @@ stages: testResultsFormat: 'NUnit' testResultsFiles: '$(buildFolderName)/$(testResultFolderName)/NUnit*.xml' testRunTitle: 'MacOS' + - task: PublishPipelineArtifact@1 + displayName: 'Publish Test Artifact' + condition: succeededOrFailed() + inputs: + targetPath: '$(buildFolderName)/$(testResultFolderName)/' + artifactName: 'CodeCoverageMacOS_$(System.JobAttempt)' + parallel: true - job: Code_Coverage displayName: 'Publish Code Coverage' - dependsOn: test_windows_ps + dependsOn: + - test_macos + - test_linux + - test_windows_core + - test_windows_ps + condition: succeededOrFailed() pool: - vmImage: 'ubuntu 16.04' + vmImage: 'ubuntu-latest' timeoutInMinutes: 0 steps: - - pwsh: | - $repositoryOwner,$repositoryName = $env:BUILD_REPOSITORY_NAME -split '/' - echo "##vso[task.setvariable variable=RepositoryOwner;isOutput=true]$repositoryOwner" - echo "##vso[task.setvariable variable=RepositoryName;isOutput=true]$repositoryName" - name: dscBuildVariable - displayName: 'Set Environment Variables' - - task: DownloadBuildArtifacts@0 + - task: DownloadPipelineArtifact@2 displayName: 'Download Build Artifact' inputs: buildType: 'current' - downloadType: 'single' artifactName: $(buildArtifactName) - downloadPath: '$(Build.SourcesDirectory)' - - task: DownloadBuildArtifacts@0 - displayName: 'Download Test Artifact' + targetPath: '$(Build.SourcesDirectory)/$(buildFolderName)' + - task: DownloadPipelineArtifact@2 + displayName: 'Download Test Artifact macOS' + inputs: + buildType: 'current' + artifactName: 'CodeCoverageMacOS_$(System.JobAttempt)' + targetPath: '$(Build.SourcesDirectory)/$(buildFolderName)/$(testResultFolderName)' + - task: DownloadPipelineArtifact@2 + displayName: 'Download Test Artifact Linux' + inputs: + buildType: 'current' + artifactName: 'CodeCoverageLinux_$(System.JobAttempt)' + targetPath: '$(Build.SourcesDirectory)/$(buildFolderName)/$(testResultFolderName)' + - task: DownloadPipelineArtifact@2 + displayName: 'Download Test Artifact Windows (PS 5.1)' + inputs: + buildType: 'current' + artifactName: 'CodeCoverageWinPS51_$(System.JobAttempt)' + targetPath: '$(Build.SourcesDirectory)/$(buildFolderName)/$(testResultFolderName)' + - task: DownloadPipelineArtifact@2 + displayName: 'Download Test Artifact Windows (PS7)' inputs: buildType: 'current' - downloadType: 'single' - artifactName: $(testArtifactName) - downloadPath: '$(Build.SourcesDirectory)/$(buildFolderName)' + artifactName: 'CodeCoverageWinPS7_$(System.JobAttempt)' + targetPath: '$(Build.SourcesDirectory)/$(buildFolderName)/$(testResultFolderName)' + - task: PowerShell@2 + name: merge + displayName: 'Merge Code Coverage files' + inputs: + filePath: './build.ps1' + arguments: '-tasks merge' + pwsh: true - task: PublishCodeCoverageResults@1 displayName: 'Publish Azure Code Coverage' - condition: succeededOrFailed() inputs: codeCoverageTool: 'JaCoCo' summaryFileLocation: '$(buildFolderName)/$(testResultFolderName)/JaCoCo_coverage.xml' - pathToSources: '$(Build.SourcesDirectory)/$(buildFolderName)/$(dscBuildVariable.RepositoryName)' + pathToSources: '$(Build.SourcesDirectory)/source/' - script: | bash <(curl -s https://codecov.io/bash) -f "./$(buildFolderName)/$(testResultFolderName)/JaCoCo_coverage.xml" - displayName: 'Upload to Codecov.io' - condition: succeededOrFailed() + displayName: 'Publish Code Coverage to Codecov.io' - stage: Deploy dependsOn: Test @@ -248,15 +290,14 @@ stages: - job: Deploy_Module displayName: 'Deploy Module' pool: - vmImage: 'ubuntu 16.04' + vmImage: 'ubuntu-latest' steps: - - task: DownloadBuildArtifacts@0 + - task: DownloadPipelineArtifact@2 displayName: 'Download Build Artifact' inputs: buildType: 'current' - downloadType: 'single' - artifactName: 'output' - downloadPath: '$(Build.SourcesDirectory)' + artifactName: $(buildArtifactName) + targetPath: '$(Build.SourcesDirectory)/$(buildFolderName)' - task: PowerShell@2 name: publishRelease displayName: 'Publish Release' @@ -267,8 +308,8 @@ stages: env: GitHubToken: $(GitHubToken) GalleryApiToken: $(GalleryApiToken) - ReleaseBranch: main - MainGitBranch: main + ReleaseBranch: $(defaultBranch) + MainGitBranch: $(defaultBranch) - task: PowerShell@2 name: sendChangelogPR displayName: 'Send Changelog PR' @@ -278,6 +319,5 @@ stages: pwsh: true env: GitHubToken: $(GitHubToken) - ReleaseBranch: main - MainGitBranch: main - + ReleaseBranch: $(defaultBranch) + MainGitBranch: $(defaultBranch) diff --git a/build.ps1 b/build.ps1 index 360d1c7..5579df1 100644 --- a/build.ps1 +++ b/build.ps1 @@ -27,7 +27,10 @@ 'output/RequiredModules'. .PARAMETER PesterScript - Not yet written. + One or more paths that will override the Pester configuration in build + configuration file when running the build task Invoke_Pester_Tests. + + If running Pester 5 test, use the alias PesterPath to be future-proof. .PARAMETER PesterTag Filter which tags to run when invoking Pester tests. This is used in the @@ -85,6 +88,8 @@ param $RequiredModulesDirectory = $(Join-Path 'output' 'RequiredModules'), [Parameter()] + # This alias is to prepare for the rename of this parameter to PesterPath when Pester 4 support is removed + [Alias('PesterPath')] [System.Object[]] $PesterScript, @@ -219,6 +224,38 @@ process Set-BuildHeader -Script ([scriptblock]::Create($BuildInfo.TaskHeader)) } + <# + Add BuildModuleOutput to PSModule Path environment variable. + Moved here (not in begin block) because build file can contains BuiltSubModuleDirectory value. + #> + if ($BuiltModuleSubdirectory) + { + if (-not (Split-Path -IsAbsolute -Path $BuiltModuleSubdirectory)) + { + $BuildModuleOutput = Join-Path -Path $OutputDirectory -ChildPath $BuiltModuleSubdirectory + } + else + { + $BuildModuleOutput = $BuiltModuleSubdirectory + } + } # test if BuiltModuleSubDirectory set in build config file + elseif ($BuildInfo.ContainsKey('BuiltModuleSubDirectory')) + { + $BuildModuleOutput = Join-Path -Path $OutputDirectory -ChildPath $BuildInfo['BuiltModuleSubdirectory'] + } + else + { + $BuildModuleOutput = $OutputDirectory + } + + # Pre-pending $BuildModuleOutput folder to PSModulePath to resolve built module from this folder. + if ($powerShellModulePaths -notcontains $BuildModuleOutput) + { + Write-Host -Object "[build] Pre-pending '$BuildModuleOutput' folder to PSModulePath" -ForegroundColor Green + + $env:PSModulePath = $BuildModuleOutput + [System.IO.Path]::PathSeparator + $env:PSModulePath + } + <# Import Tasks from modules via their exported aliases when defined in Build Manifest. https://github.com/nightroman/Invoke-Build/tree/master/Tasks/Import#example-2-import-from-a-module-with-tasks @@ -403,30 +440,6 @@ Begin } } - if ($BuiltModuleSubdirectory) - { - if (-not (Split-Path -IsAbsolute -Path $BuiltModuleSubdirectory)) - { - $BuildModuleOutput = Join-Path -Path $OutputDirectory -ChildPath $BuiltModuleSubdirectory - } - else - { - $BuildModuleOutput = $BuiltModuleSubdirectory - } - } - else - { - $BuildModuleOutput = $OutputDirectory - } - - # Pre-pending $BuildModuleOutput folder to PSModulePath to resolve built module from this folder. - if ($powerShellModulePaths -notcontains $BuildModuleOutput) - { - Write-Host -Object "[pre-build] Pre-pending '$BuildModuleOutput' folder to PSModulePath" -ForegroundColor Green - - $env:PSModulePath = $BuildModuleOutput + [System.IO.Path]::PathSeparator + $env:PSModulePath - } - <# The variable $PSDependTarget will be used below when building the splatting variable before calling Resolve-Dependency.ps1, unless overridden in the @@ -453,7 +466,7 @@ Begin # The parameter has been explicitly used for calling the .build.ps1 if ($MyInvocation.BoundParameters.ContainsKey($cmdParameter)) { - $paramValue = $MyInvocation.BoundParameters.ContainsKey($cmdParameter) + $paramValue = $MyInvocation.BoundParameters.Item($cmdParameter) Write-Debug " adding $cmdParameter :: $paramValue [from user-provided parameters to Build.ps1]" diff --git a/build.yaml b/build.yaml index d48e5b1..d6d5a5d 100644 --- a/build.yaml +++ b/build.yaml @@ -10,7 +10,7 @@ Encoding: UTF8 VersionedOutputDirectory: true #################################################### -# Pipeline Configuration # +# Sampler Pipeline Configuration # #################################################### BuildWorkflow: '.': @@ -35,10 +35,13 @@ BuildWorkflow: - Convert_Pester_Coverage - Pester_if_Code_Coverage_Under_Threshold + merge: + - Merge_CodeCoverage_Files + publish: - Publish_release_to_GitHub - publish_module_to_gallery - + - Publish_GitHub_Wiki_Content #################################################### # PESTER Configuration # @@ -51,12 +54,31 @@ Pester: - tests/QA - tests/Unit - tests/Integration + Output: + Verbosity: Detailed + StackTraceVerbosity: Full + CIFormat: Auto CodeCoverage: CoveragePercentTarget: 78 - OutputPath: JaCoCo_coverage.xml OutputEncoding: ascii + UseBreakpoints: false ExcludeFromCodeCoverage: +#################################################### +# Code Coverage Configuration # +#################################################### + +CodeCoverage: + # Filename of the file that will be outputted by the task Merge_CodeCoverage_Files. + CodeCoverageMergedOutputFile: JaCoCo_coverage.xml + # File pattern used to search for files under the ./output/testResults folder + # by task Merge_CodeCoverage_Files. + CodeCoverageFilePattern: Codecov*.xml + +#################################################### +# HQRM Test Configuration # +#################################################### + DscTest: Pester: Configuration: @@ -66,6 +88,7 @@ DscTest: - Common Tests - New Error-Level Script Analyzer Rules Output: Verbosity: Detailed + CIFormat: Auto TestResult: Enabled: true OutputFormat: NUnitXML @@ -79,11 +102,6 @@ DscTest: ExcludeModuleFile: MainGitBranch: main -Resolve-Dependency: - Gallery: 'PSGallery' - AllowPrerelease: false - Verbose: false - ModuleBuildTasks: Sampler: - '*.build.Sampler.ib.tasks' diff --git a/codecov.yml b/codecov.yml new file mode 100644 index 0000000..ae1a63c --- /dev/null +++ b/codecov.yml @@ -0,0 +1,25 @@ +codecov: + require_ci_to_pass: no + # master should be the baseline for reporting + branch: main + +comment: + layout: "reach, diff, flags, files" + behavior: default + +coverage: + range: 50..80 + round: down + precision: 0 + + status: + project: + default: + # Set the overall project code coverage requirement to 70% + target: 70 + patch: + default: + # Set the pull request requirement to not regress overall coverage by more than 5% + # and let codecov.io set the goal for the code changed in the patch. + target: auto + threshold: 5 diff --git a/source/WikiSource/Home.md b/source/WikiSource/Home.md new file mode 100644 index 0000000..ee50fe0 --- /dev/null +++ b/source/WikiSource/Home.md @@ -0,0 +1,9 @@ +# Welcome to the DscResource.Common wiki + +*DscResource.Common v#.#.#* + +For documentation please see the [README.md](https://github.com/dsccommunity/DscResource.Common/blob/main/README.md) + +Please leave comments, feature requests, and bug reports for this module in +the [issues section](https://github.com/dsccommunity/DscResource.Common/issues) +for this repository. diff --git a/tests/QA/module.tests.ps1 b/tests/QA/module.tests.ps1 index 10d67ed..f736563 100644 --- a/tests/QA/module.tests.ps1 +++ b/tests/QA/module.tests.ps1 @@ -32,6 +32,35 @@ BeforeAll { ).Directory.FullName } + Describe 'Changelog Management' -Tag 'Changelog' { + It 'Changelog has been updated' -skip:( + !([bool](Get-Command git -EA SilentlyContinue) -and + [bool](&(Get-Process -id $PID).Path -NoProfile -Command 'git rev-parse --is-inside-work-tree 2>$null')) + ) { + # Get the list of changed files compared with branch main + $HeadCommit = &git rev-parse HEAD + $defaultBranchCommit = &git rev-parse origin/main + $filesChanged = &git @('diff', "$defaultBranchCommit...$HeadCommit", '--name-only') + $filesStagedAndUnstaged = &git @('diff', "HEAD", '--name-only') + + $filesChanged += $filesStagedAndUnstaged + + # Only check if there are any changed files. + if ($filesChanged) + { + $filesChanged | Should -Contain 'CHANGELOG.md' -Because 'the CHANGELOG.md must be updated with at least one entry in the Unreleased section for each PR' + } + } + + It 'Changelog format compliant with keepachangelog format' -skip:(![bool](Get-Command git -EA SilentlyContinue)) { + { Get-ChangelogData (Join-Path $ProjectPath 'CHANGELOG.md') -ErrorAction Stop } | Should -Not -Throw + } + + It 'Changelog should have an Unreleased header' -Skip:$skipTest { + (Get-ChangelogData -Path (Join-Path -Path $ProjectPath -ChildPath 'CHANGELOG.md') -ErrorAction 'Stop').Unreleased.RawData | Should -Not -BeNullOrEmpty + } + } + Describe 'General module control' -Tags 'FunctionalQuality' { It 'Should import without errors' { { Import-Module -Name $script:moduleName -Force -ErrorAction Stop } | Should -Not -Throw @@ -80,11 +109,11 @@ Describe 'Quality for module' -Tags 'TestQuality' { } } - It 'Should have a unit test for ' -TestCases $testCases { + It 'Should have a unit test for ' -ForEach $testCases { Get-ChildItem -Path 'tests\' -Recurse -Include "$Name.Tests.ps1" | Should -Not -BeNullOrEmpty } - It 'Should pass Script Analyzer for ' -TestCases $testCases -Skip:(-not $scriptAnalyzerRules) { + It 'Should pass Script Analyzer for ' -ForEach $testCases -Skip:(-not $scriptAnalyzerRules) { $functionFile = Get-ChildItem -Path $sourcePath -Recurse -Include "$Name.ps1" $pssaResult = (Invoke-ScriptAnalyzer -Path $functionFile.FullName) @@ -95,7 +124,7 @@ Describe 'Quality for module' -Tags 'TestQuality' { } Describe 'Help for module' -Tags 'helpQuality' { - It 'Should have .SYNOPSIS for ' -TestCases $testCases { + It 'Should have .SYNOPSIS for ' -ForEach $testCases { $functionFile = Get-ChildItem -Path $sourcePath -Recurse -Include "$Name.ps1" $scriptFileRawContent = Get-Content -Raw -Path $functionFile.FullName @@ -114,7 +143,7 @@ Describe 'Help for module' -Tags 'helpQuality' { $functionHelp.Synopsis | Should -Not -BeNullOrEmpty } - It 'Should have a .DESCRIPTION with length greater than 40 characters for ' -TestCases $testCases { + It 'Should have a .DESCRIPTION with length greater than 40 characters for ' -ForEach $testCases { $functionFile = Get-ChildItem -Path $sourcePath -Recurse -Include "$Name.ps1" $scriptFileRawContent = Get-Content -Raw -Path $functionFile.FullName @@ -133,7 +162,7 @@ Describe 'Help for module' -Tags 'helpQuality' { $functionHelp.Description.Length | Should -BeGreaterThan 40 } - It 'Should have at least one (1) example for ' -TestCases $testCases { + It 'Should have at least one (1) example for ' -ForEach $testCases { $functionFile = Get-ChildItem -Path $sourcePath -Recurse -Include "$Name.ps1" $scriptFileRawContent = Get-Content -Raw -Path $functionFile.FullName @@ -155,7 +184,7 @@ Describe 'Help for module' -Tags 'helpQuality' { } - It 'Should have described all parameters for ' -TestCases $testCases { + It 'Should have described all parameters for ' -ForEach $testCases { $functionFile = Get-ChildItem -Path $sourcePath -Recurse -Include "$Name.ps1" $scriptFileRawContent = Get-Content -Raw -Path $functionFile.FullName