diff --git a/.azure-pipelines/CI.yml b/.azure-pipelines/CI.yml deleted file mode 100644 index e8cdc6d..0000000 --- a/.azure-pipelines/CI.yml +++ /dev/null @@ -1,58 +0,0 @@ -trigger: - branches: - include: - - master - paths: - exclude: - - .github/* - - .vscode/* - - docs/* - - appveyor.yml - - CHANGELOG.md - - CONTRIBUTING.md - - LICENSE.md - - README.md - - .editorconfig - - .azure-pipelines/* - tags: - exclude: - - v* - -pr: - - master - -variables: - ${{ if ne(variables['Build.Reason'], 'PullRequest') }}: - Trigger: "$(SourceBranchName)" - ${{ if eq(variables['Build.Reason'], 'PullRequest') }}: - Trigger: "PR #$(System.PullRequest.PullRequestNumber)" - -name: "$(BuildID)-$(Date:yyyy-MM-dd)$(Rev:.r) $(TeamProject) (${{ variables.Trigger }})" - -stages: - - stage: Test - jobs: - - job: - strategy: - matrix: - Windows_Server2022_PowerShell_Core: - vmImage: windows-2022 - Windows_Server2019_PowerShell_Core: - vmImage: windows-2019 - pool: - vmImage: $[ variables['vmImage'] ] - steps: - - template: templates/test-pwsh.yml - - job: - strategy: - matrix: - Windows_Server2022_PowerShell_5_1: - vmImage: windows-2022 - pwsh: false - Windows_Server2019_PowerShell_5_1: - vmImage: windows-2019 - pwsh: false - pool: - vmImage: $[ variables['vmImage'] ] - steps: - - template: templates/test-powershell.yml diff --git a/.azure-pipelines/templates/test-powershell.yml b/.azure-pipelines/templates/test-powershell.yml deleted file mode 100644 index 7400d00..0000000 --- a/.azure-pipelines/templates/test-powershell.yml +++ /dev/null @@ -1,18 +0,0 @@ -steps: - - task: PowerShell@2 - displayName: "Test" - env: - SteamWebAPI: $(SteamAPI) - inputs: - targetType: inline - pwsh: false - script: | - Install-Module -Name PSDepend -Force - Invoke-PSDepend -Force - Invoke-Build - - task: PublishTestResults@2 - inputs: - testRunner: NUnit - testResultsFiles: "testResults.xml" - failTaskOnFailedTests: true - condition: succeededOrFailed() diff --git a/.azure-pipelines/templates/test-pwsh.yml b/.azure-pipelines/templates/test-pwsh.yml deleted file mode 100644 index 02028d2..0000000 --- a/.azure-pipelines/templates/test-pwsh.yml +++ /dev/null @@ -1,18 +0,0 @@ -steps: - - task: PowerShell@2 - displayName: "Test" - env: - SteamWebAPI: $(SteamAPI) - inputs: - targetType: inline - pwsh: true - script: | - Install-Module -Name PSDepend -Force - Invoke-PSDepend -Force - Invoke-Build - - task: PublishTestResults@2 - inputs: - testRunner: NUnit - testResultsFiles: "testResults.xml" - failTaskOnFailedTests: true - condition: succeededOrFailed() diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml new file mode 100644 index 0000000..0e92d99 --- /dev/null +++ b/.github/workflows/CI.yml @@ -0,0 +1,158 @@ +name: SteamPS CI/CD workflow +on: + push: + branches: + - main + - master + + pull_request: + branches: + - main + - master + + release: + types: + - published + +env: + DOTNET_CLI_TELEMETRY_OPTOUT: 1 + POWERSHELL_TELEMETRY_OPTOUT: 1 + DOTNET_SKIP_FIRST_TIME_EXPERIENCE: 1 + DOTNET_NOLOGO: true + BUILD_CONFIGURATION: ${{ fromJSON('["Debug", "Release"]')[startsWith(github.ref, 'refs/tags/v')] }} + +jobs: + build: + name: 👷 Build + runs-on: windows-latest + steps: + - name: 🚚 Check out repository + uses: actions/checkout@v4 + + - name: 🐛 Build module - Debug + shell: pwsh + run: ./build.ps1 -Configuration $env:BUILD_CONFIGURATION -Task Build + if: ${{ env.BUILD_CONFIGURATION == 'Debug' }} + + - name: 🚀 Build module - Publish + shell: pwsh + run: ./build.ps1 -Configuration $env:BUILD_CONFIGURATION -Task Build + if: ${{ env.BUILD_CONFIGURATION == 'Release' }} + + - name: 📦 Capture PowerShell Module + uses: actions/upload-artifact@v4 + with: + name: PSModule + path: output/*.nupkg + + test: + name: 🧪 Test + needs: + - build + runs-on: ${{ matrix.info.os }} + strategy: + fail-fast: false + matrix: + info: + - name: 🪟 Win2019_PS-5.1 + psversion: '5.1' + os: windows-2019 + - name: 🪟 Win2019_PS-7 + psversion: '7' + os: windows-2019 + - name: 🪟 Win2022_PS-5.1 + psversion: '5.1' + os: windows-latest + - name: 🪟 Win2022_PS-7 + psversion: '7' + os: windows-latest + + steps: + - name: 🚚 Checkout + uses: actions/checkout@v4 + + - name: ➕ Restore Built PowerShell Module + uses: actions/download-artifact@v4 + with: + name: PSModule + path: output + + - name: 📦 Install Built PowerShell Module + shell: pwsh + run: | + # Get the manifest from the newly built module. + $manifestItem = Get-Item ([IO.Path]::Combine('SteamPS', '*.psd1')) + $moduleName = $manifestItem.BaseName + $Manifest = Test-ModuleManifest -Path $manifestItem.FullName -ErrorAction SilentlyContinue -WarningAction Ignore + + if ($env:BUILD_CONFIGURATION -eq 'Release') { + $Version = $env:GITHUB_REF -replace '^refs/tags/v(\d+\.\d+\.\d+)', '$1' + } else { + $Version = $Manifest.Version + } + + $destPath = [IO.Path]::Combine('output', $moduleName, $Version) + if (-not (Test-Path -LiteralPath $destPath)) { + New-Item -Path $destPath -ItemType Directory | Out-Null + } + + Get-ChildItem output/*.nupkg | Rename-Item -NewName { $_.Name -replace '.nupkg', '.zip' } + + Expand-Archive -Path output/*.zip -DestinationPath $destPath -Force -ErrorAction Stop + + - name: 🧪 Run Tests - Windows PowerShell + if: ${{ matrix.info.psversion == '5.1' }} + shell: powershell + run: ./build.ps1 -Configuration $env:BUILD_CONFIGURATION -Task Test + + - name: 🧪 Run Tests - PowerShell + if: ${{ matrix.info.psversion != '5.1' }} + shell: pwsh + run: ./build.ps1 -Configuration $env:BUILD_CONFIGURATION -Task Test + + - name: ⬆️ Upload Test Results + if: always() + uses: actions/upload-artifact@v4 + with: + name: Unit Test Results (${{ matrix.info.name }}) + path: ./output/TestResults/Pester.xml + + - name: ⬆️ Upload Coverage Results + if: always() && !startsWith(github.ref, 'refs/tags/v') + uses: actions/upload-artifact@v4 + with: + name: Coverage Results (${{ matrix.info.name }}) + path: ./output/TestResults/Coverage.xml + + - name: ⬆️ Upload Coverage to codecov + if: always() && !startsWith(github.ref, 'refs/tags/v') + uses: codecov/codecov-action@v4 + with: + files: ./output/TestResults/Coverage.json + flags: ${{ matrix.info.name }} + token: ${{ secrets.CODECOV_TOKEN }} + + publish: + name: 🚀 Deploy + if: startsWith(github.ref, 'refs/tags/v') + needs: + - build + - test + runs-on: windows-latest + steps: + - name: ➕ Restore Built PowerShell Module + uses: actions/download-artifact@v4 + with: + name: PSModule + path: ./ + + - name: 🚀 Publish to Gallery + if: github.event_name == 'release' + shell: pwsh + run: >- + dotnet nuget push '*.nupkg' + --api-key $env:PSGALLERY_TOKEN + --source 'https://www.powershellgallery.com/api/v2/package' + --no-symbols + env: + PSGALLERY_TOKEN: ${{ secrets.PS_GALLERY_KEY }} diff --git a/.github/workflows/PSScriptAnalyzer.yml b/.github/workflows/PSScriptAnalyzer.yml deleted file mode 100644 index fb39926..0000000 --- a/.github/workflows/PSScriptAnalyzer.yml +++ /dev/null @@ -1,48 +0,0 @@ -# This workflow uses actions that are not certified by GitHub. -# They are provided by a third-party and are governed by -# separate terms of service, privacy policy, and support -# documentation. -# -# https://github.com/microsoft/action-psscriptanalyzer -# For more information on PSScriptAnalyzer in general, see -# https://github.com/PowerShell/PSScriptAnalyzer - -name: PSScriptAnalyzer - -on: - push: - branches: [ master ] - pull_request: - branches: [ master ] - schedule: - - cron: '37 16 * * 6' - -permissions: - contents: read - -jobs: - build: - permissions: - contents: read # for actions/checkout to fetch code - security-events: write # for github/codeql-action/upload-sarif to upload SARIF results - name: PSScriptAnalyzer - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v3 - - - name: Run PSScriptAnalyzer - uses: microsoft/psscriptanalyzer-action@2044ae068e37d0161fa2127de04c19633882f061 - with: - # Check https://github.com/microsoft/action-psscriptanalyzer for more info about the options. - # The below set up runs PSScriptAnalyzer to your entire repository and runs some basic security rules. - path: .\ - recurse: true - # Include your own basic security rules. Removing this option will run all the rules - includeRule: '"PSAvoidGlobalAliases", "PSAvoidUsingConvertToSecureStringWithPlainText"' - output: results.sarif - - # Upload the SARIF file generated in the previous step - - name: Upload SARIF results file - uses: github/codeql-action/upload-sarif@v2 - with: - sarif_file: results.sarif diff --git a/README.md b/README.md index 1220fc5..41b561f 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,6 @@ # SteamPS -[![AppVeyor master](https://img.shields.io/appveyor/ci/hjorslev/SteamPS/master?label=AppVeyor&logo=appveyor&style=flat)](https://ci.appveyor.com/project/hjorslev/steamps) -[![Azure DevOps builds](https://img.shields.io/azure-devops/build/fhjorslev/69d18b04-0023-433d-a649-bcf821875235/5?label=Azure+Pipelines&logo=azure-pipelines)](https://dev.azure.com/fhjorslev/SteamPS/_build/latest?definitionId=5&branchName=master) -[![AppVeyor tests (master)](https://img.shields.io/appveyor/tests/hjorslev/SteamPS/master?label=master&logo=appveyor&style=flat)](https://ci.appveyor.com/project/hjorslev/steamps/build/tests) -[![Codacy master grade](https://img.shields.io/codacy/grade/bf0bb30dfc904b2f885c4f0ccdf1ea78/master?label=master&style=flat)](https://app.codacy.com/manual/hjorslev/SteamPS/dashboard?bid=13716491) +[![GitHub Actions Workflow Status](https://img.shields.io/github/actions/workflow/status/hjorslev/SteamPS/CI.yml?logo=GitHub&label=CI%2FCD)](https://github.com/hjorslev/SteamPS/actions/workflows/CI.yml) - [SteamPS](#steamps) - [Introduction](#introduction) @@ -21,7 +18,7 @@ ## Introduction [![PowerShell Version](https://img.shields.io/powershellgallery/v/SteamPS.svg?style=flat&logo=PowerShell)](https://www.powershellgallery.com/packages/SteamPS) -[![PowerShell Gallery](https://img.shields.io/powershellgallery/dt/SteamPS?style=flat)](https://www.powershellgallery.com/packages/SteamPS) +[![PowerShell Gallery](https://img.shields.io/powershellgallery/dt/SteamPS?style=flat&logo=PowerShell)](https://www.powershellgallery.com/packages/SteamPS) SteamPS is a [PowerShell module](https://github.com/PowerShell/PowerShell/) that can interact with [SteamCMD](https://developer.valvesoftware.com/wiki/SteamCMD), diff --git a/SteamPS.PSDeploy.ps1 b/SteamPS.PSDeploy.ps1 deleted file mode 100644 index 1552bde..0000000 --- a/SteamPS.PSDeploy.ps1 +++ /dev/null @@ -1,9 +0,0 @@ -Deploy Module { - By PSGalleryModule { - FromSource $env:BHProjectName - To PSGallery - WithOptions @{ - ApiKey = $env:PSGalleryAPIKey - } - } -} \ No newline at end of file diff --git a/SteamPS.build.ps1 b/SteamPS.build.ps1 index 86286f3..2763ef2 100644 --- a/SteamPS.build.ps1 +++ b/SteamPS.build.ps1 @@ -1,168 +1,235 @@ -Set-BuildEnvironment -ErrorAction SilentlyContinue - -# Synopsis: Initializing -Add-BuildTask Init { - # Line break for readability in AppVeyor console - Write-Host -Object '' - Write-Host -Object 'Build System Details:' - Write-Output -InputObject $PSVersionTable - Write-Host -Object "`n" - Get-Item env:BH* - Write-Host -Object "`n" +[CmdletBinding()] +param( + [ValidateSet('Debug', 'Release')] + [string] $Configuration = 'Debug' +) + +$script:SteamPSModulePath = [IO.Path]::Combine($PSScriptRoot, 'SteamPS') +$manifestItem = Get-Item ([IO.Path]::Combine($SteamPSModulePath, '*.psd1')) +$ModuleName = $manifestItem.BaseName +$psm1 = Join-Path $SteamPSModulePath -ChildPath ($ModuleName + '.psm1') + +$testModuleManifestSplat = @{ + Path = $manifestItem.FullName + ErrorAction = 'Ignore' + WarningAction = 'Ignore' } -# Synopsis: Pester Tests -Add-BuildTask Test { - Remove-Module -Name $env:BHProjectName -Force -ErrorAction SilentlyContinue - Import-Module $env:BHPSModuleManifest -Force -Global - # Invoke Pester to run all of the unit tests, then save the results into XML in order to populate the AppVeyor tests section - # If any of the tests fail, consider the pipeline failed - $PesterResults = Invoke-Pester -Path "$env:BHProjectPath\Tests" -CI -Output Detailed - if ($env:BHBuildSystem -eq 'AppVeyor') { - Add-TestResultToAppveyor -TestFile "$env:BHProjectPath\testResults.xml" +$Manifest = Test-ModuleManifest @testModuleManifestSplat +$ReleaseVersion = $env:GITHUB_REF -replace '^refs/tags/v(\d+\.\d+\.\d+)', '$1' + +if ($Configuration -eq 'Release') { + $Version = $ReleaseVersion +} else { + $Version = $Manifest.Version +} + +$BuildPath = [IO.Path]::Combine($PSScriptRoot, 'output') +$CSharpPath = [IO.Path]::Combine($PSScriptRoot, 'src', $ModuleName) +$isBinaryModule = Test-Path $CSharpPath +$ReleasePath = [IO.Path]::Combine($BuildPath, $ModuleName, $Version) +$UseNativeArguments = $PSVersionTable.PSVersion -gt '7.0' + +task Clean { + if (Test-Path $ReleasePath) { + Remove-Item $ReleasePath -Recurse -Force } - if ($PesterResults.FailedCount -gt 0) { - throw "$($PesterResults.FailedCount) tests failed." + + New-Item -ItemType Directory $ReleasePath | Out-Null +} + +task BuildDocs { + $helpParams = @{ + Path = [IO.Path]::Combine($PSScriptRoot, 'docs', 'en-US') + OutputPath = [IO.Path]::Combine($ReleasePath, 'en-US') } + New-ExternalHelp @helpParams | Out-Null } -# Synopsis: Build manifest -Add-BuildTask BuildManifest { - # We're going to add 1 to the revision value since a new commit has been merged to Master - # This means that the major / minor / build values will be consistent across GitHub and the Gallery +task BuildPowerShell { + $buildModuleSplat = @{ + SourcePath = $SteamPSModulePath + OutputDirectory = $ReleasePath + Encoding = 'UTF8Bom' + IgnoreAlias = $true + } + + if ($Configuration -eq 'Release') { + $buildModuleSplat['SemVer'] = $ReleaseVersion + } + + if (Test-Path $psm1) { + $buildModuleSplat['Suffix'] = Get-Content $psm1 -Raw + } + + Build-Module @buildModuleSplat +} + +task BuildManaged { + if (-not $isBinaryModule) { + Write-Host 'No C# source path found. Skipping BuildManaged...' + return + } + + $arguments = @( + 'publish' + '--configuration', $Configuration + '--verbosity', 'q' + '-nologo' + "-p:Version=$Version" + ) + + Push-Location -LiteralPath $CSharpPath try { - # Get current module version from Manifest. - $Manifest = Import-PowerShellDataFile -Path $env:BHPSModuleManifest - [version]$Version = $Manifest.ModuleVersion - Write-Output -InputObject "Old Version: $Version" - - # Update module version in Manifest. - switch -Wildcard ($env:BHCommitMessage) { - '*!ver:MAJOR*' { - New-Variable -Name NewVersion -Value $(Step-Version -Version $Version -By Major) -Scope Global - Step-ModuleVersion -Path $env:BHPSModuleManifest -By Major - } - '*!ver:MINOR*' { - New-Variable -Name NewVersion -Value $(Step-Version -Version $Version -By Minor) -Scope Global - Step-ModuleVersion -Path $env:BHPSModuleManifest -By Minor - } - # Default is just changed build - Default { - New-Variable -Name NewVersion -Value $(Step-Version -Version $Version) -Scope Global - Step-ModuleVersion -Path $env:BHPSModuleManifest -By Patch + foreach ($framework in $TargetFrameworks) { + Write-Host "Compiling for $framework" + dotnet @arguments --framework $framework + + if ($LASTEXITCODE) { + throw "Failed to compiled code for $framework" } } + } finally { + Pop-Location + } +} + +task CopyToRelease { + foreach ($framework in $TargetFrameworks) { + $buildFolder = [IO.Path]::Combine($CSharpPath, 'bin', $Configuration, $framework, 'publish') + $binFolder = [IO.Path]::Combine($ReleasePath, 'bin', $framework, $_.Name) + if (-not (Test-Path -LiteralPath $binFolder)) { + New-Item -Path $binFolder -ItemType Directory | Out-Null + } + Copy-Item ([IO.Path]::Combine($buildFolder, '*')) -Destination $binFolder -Recurse + } +} + +task Package { + $nupkgPath = [IO.Path]::Combine($BuildPath, "$ModuleName.$Version*.nupkg") + if (Test-Path $nupkgPath) { + Remove-Item $nupkgPath -Force + } + + $repoParams = @{ + Name = 'LocalRepo' + SourceLocation = $BuildPath + PublishLocation = $BuildPath + InstallationPolicy = 'Trusted' + } - Write-Output -InputObject "New Version: $NewVersion" - # Update yaml file with new version information. - $AppVeyor = ConvertFrom-Yaml -Yaml $(Get-Content "$env:BHProjectPath\appveyor.yml" | Out-String) - $UpdateAppVeyor = $AppVeyor.GetEnumerator() | Where-Object { $_.Name -eq 'version' } - $UpdateAppVeyor | ForEach-Object { $AppVeyor[$_.Key] = "$($NewVersion).{build}" } - ConvertTo-Yaml -Data $AppVeyor -OutFile "$env:BHProjectPath\appveyor.yml" -Force + if (Get-PSRepository -Name $repoParams.Name -ErrorAction SilentlyContinue) { + Unregister-PSRepository -Name $repoParams.Name + } - # Populate FunctionsToExport with BaseNames found within the Public and Private folders. - $PublicFunctions = ((Get-ChildItem -Path "$env:BHModulePath\Public\*.ps1" -Recurse).BaseName) | Sort-Object - Set-ModuleFunction -FunctionsToExport $PublicFunctions - Get-ModuleFunction + Register-PSRepository @repoParams - # Update copyright notice. - Update-Metadata -Path $env:BHPSModuleManifest -PropertyName Copyright -Value "(c) 2019-$((Get-Date).Year) $(Get-Metadata -Path $env:BHPSModuleManifest -PropertyName Author). All rights reserved." - } catch { - throw $_ + try { + Publish-Module -Path $ReleasePath -Repository $repoParams.Name + } finally { + Unregister-PSRepository -Name $repoParams.Name } } -# Synopsis: Build docs -Add-BuildTask BuildDocs { - if ($env:BHBuildSystem -ne 'Unknown' -and $env:BHBranchName -eq 'master' ) { - # Create new markdown and XML help files. - Write-Host -Object 'Building new function documentation' -ForegroundColor Yellow - if ((Test-Path -Path "$env:BHProjectPath\docs") -eq $false) { - New-Item -Path $env:BHProjectPath -Name 'docs' -ItemType Directory - } +task Analyze { + $analyzerPath = [IO.Path]::Combine($PSScriptRoot, 'PSScriptAnalyzerSettings.psd1') + if (-not (Test-Path $analyzerPath)) { + Write-Host 'No analyzer rules found, skipping...' + return + } - Import-Module $env:BHPSModuleManifest -Force -Global - New-MarkdownHelp -Module $env:BHProjectName -OutputFolder "$env:BHProjectPath\docs" -Force - New-ExternalHelp -Path "$($env:BHProjectPath)\docs" -OutputPath "$env:BHModulePath\en-US\" -Force - Copy-Item -Path '.\README.md' -Destination 'docs\index.md' - Copy-Item -Path '.\CHANGELOG.md' -Destination 'docs\CHANGELOG.md' - } else { - Write-Host -Object "Skipping building docs because `n" + - Write-Host -Object "`t* You are on $env:BHBranchName and not master branch.`n" + $pssaSplat = @{ + Path = $ReleasePath + Settings = [IO.Path]::Combine($PSScriptRoot, 'PSScriptAnalyzerSettings.psd1') + Recurse = $true + ErrorAction = 'SilentlyContinue' + } + $results = Invoke-ScriptAnalyzer @pssaSplat + + if ($null -ne $results) { + $results | Out-String + throw 'Failed PsScriptAnalyzer tests, build failed' } } -# Synopsis: Deploy to PSGallery -Add-BuildTask DeployPSGallery { - # Publish the new version to the PowerShell Gallery +task DoUnitTest { + $testsPath = [IO.Path]::Combine($PSScriptRoot, 'Tests', 'units') + if (-not (Test-Path -LiteralPath $testsPath)) { + Write-Host 'No unit tests found, skipping...' + return + } + + $resultsPath = [IO.Path]::Combine($BuildPath, 'TestResults') + if (-not (Test-Path -LiteralPath $resultsPath)) { + New-Item $resultsPath -ItemType Directory -ErrorAction Stop | Out-Null + } + + $tempResultsPath = [IO.Path]::Combine($resultsPath, 'TempUnit') + if (Test-Path -LiteralPath $tempResultsPath) { + Remove-Item -LiteralPath $tempResultsPath -Force -Recurse + } + New-Item -Path $tempResultsPath -ItemType Directory | Out-Null + try { - Invoke-PSDeploy -Force -ErrorAction Stop - Write-Host -Object "$env:BHProjectName PowerShell Module version $NewVersion published to the PowerShell Gallery." -ForegroundColor Cyan - } catch { - # Sad panda; it broke - Write-Warning -Message "Publishing update $NewVersion to the PowerShell Gallery failed." - throw $_ + $runSettingsPrefix = 'DataCollectionRunSettings.DataCollectors.DataCollector.Configuration' + $arguments = @( + 'test' + $testsPath + '--results-directory', $tempResultsPath + if ($Configuration -eq 'Debug') { + '--collect:"XPlat Code Coverage"' + '--' + "$runSettingsPrefix.Format=json" + if ($UseNativeArguments) { + "$runSettingsPrefix.IncludeDirectory=`"$CSharpPath`"" + } else { + "$runSettingsPrefix.IncludeDirectory=\`"$CSharpPath\`"" + } + } + ) + + Write-Host 'Running unit tests' + dotnet @arguments + + if ($LASTEXITCODE) { + throw 'Unit tests failed' + } + + if ($Configuration -eq 'Debug') { + Move-Item -Path $tempResultsPath/*/*.json -Destination $resultsPath/UnitCoverage.json -Force + } + } finally { + Remove-Item -LiteralPath $tempResultsPath -Force -Recurse } } -# Synopsis: Deploy to Github Releases -Add-BuildTask DeployGHRelease { - # Get latest changelog and publish it to GitHub Releases. - $ChangeLog = Get-Content -Path '.\CHANGELOG.md' - # Expect that the latest changelog info is located at line 8. - $ChangeLog = $ChangeLog.Where( { $_ -eq $ChangeLog[7] }, 'SkipUntil') - # Grab all text until next heading that starts with ## [. - $ChangeLog = $ChangeLog.Where( { $_ -eq ($ChangeLog | Select-String -Pattern "## \[" | Select-Object -Skip 1 -First 1) }, 'Until') - - # Publish GitHub Release - $GHReleaseSplat = @{ - AccessToken = $env:GitHubKey - RepositoryOwner = $(Get-Metadata -Path $env:BHPSModuleManifest -PropertyName CompanyName) - TagName = "v$NewVersion" - Name = "v$NewVersion Release of $env:BHProjectName" - ReleaseText = $ChangeLog | Out-String - } - Publish-GithubRelease @GHReleaseSplat -} +task DoTest { + $testsPath = [IO.Path]::Combine($PSScriptRoot, 'Tests') + if (-not (Test-Path $testsPath)) { + Write-Host 'No Pester tests found, skipping...' + return + } + + $resultsPath = [IO.Path]::Combine($BuildPath, 'TestResults') + if (-not (Test-Path $resultsPath)) { + New-Item $resultsPath -ItemType Directory -ErrorAction Stop | Out-Null + } -# Synopsis: Push changes to GitHub -Add-BuildTask PushChangesGitHub { - # Remove files we don't want to be pushed to GitHub - Remove-Item -Path "$env:BHProjectPath\coverage.xml" -Force - Remove-Item -Path "$env:BHProjectPath\testResults.xml" -Force + Get-ChildItem -LiteralPath $resultsPath | + Remove-Item -ErrorAction Stop -Force - # Publish the new version back to Master on GitHub - try { - $ErrorActionPreference = 'Continue' - # Set up a path to the git.exe cmd, import posh-git to give us control over git, and then push changes to GitHub - # Note that "update version" is included in the appveyor.yml file's "skip a build" regex to avoid a loop - $env:Path += "; $env:ProgramFiles\Git\cmd" - Import-Module -Name 'posh-git' - - git checkout master - git add --all - git status - git commit -s -m ":rocket: [skip ci] Update version to $NewVersion" - git push origin master - - $ErrorActionPreference = 'Stop' - Write-Host -Object "$env:BHProjectName PowerShell Module version $NewVersion published to GitHub." -ForegroundColor Cyan - } catch { - # Sad panda; it broke - Write-Warning "Publishing update $NewVersion to GitHub failed." - throw $_ + $pesterScript = [IO.Path]::Combine($PSScriptRoot, 'tools', 'PesterTest.ps1') + + $testArgs = @{ + TestPath = $testsPath + ResultPath = $resultsPath + SourceRoot = $SteamPSModulePath + ReleasePath = $ReleasePath } + + & $pesterScript @testArgs } -if ($env:BHBuildSystem -eq 'AppVeyor' -and $env:BHBranchName -eq 'master' -and $env:BHCommitMessage -like "*!deploy*") { - # Synopsis: Entire build pipeline - #TODO: DeployGHRelease not working atm. - # Add-BuildTask . Init, Test, BuildManifest, BuildDocs, DeployPSGallery, DeployGHRelease, PushChangesGitHub - Add-BuildTask . Init, Test, BuildManifest, BuildDocs, DeployPSGallery, PushChangesGitHub -} else { - Add-BuildTask . Init, Test - Write-Host -Object "Skipping deployment: To deploy, ensure that...`n" - Write-Host -Object "`t* You are in build system 'AppVeyor' (Current: $env:BHBuildSystem)`n" - Write-Host -Object "`t* You are committing to the master branch (Current: $env:BHBranchName) `n" - Write-Host -Object "`t* Your commit message includes '!deploy' (Current: $env:BHCommitMessage) `n" -} \ No newline at end of file +task Build -Jobs Clean, BuildManaged, BuildPowerShell, CopyToRelease, BuildDocs, Package +task Test -Jobs BuildManaged, Analyze, DoUnitTest, DoTest +task . Build diff --git a/SteamPS.depend.psd1 b/SteamPS.depend.psd1 deleted file mode 100644 index e220dc8..0000000 --- a/SteamPS.depend.psd1 +++ /dev/null @@ -1,22 +0,0 @@ -@{ - # Some defaults for all dependencies - PSDependOptions = @{ - Target = '$env:USERPROFILE\Documents\WindowsPowerShell\Modules' - AddToPath = $true - Parameters = @{ - Force = $true - } - } - - # Grab some modules without depending on PowerShellGet - 'BuildHelpers' = @{ DependencyType = 'PSGalleryNuget'; version = 'latest' } - 'Configuration' = @{ DependencyType = 'PSGalleryNuget'; version = 'latest' } - 'InvokeBuild' = @{ DependencyType = 'PSGalleryNuget'; version = 'latest' } - 'Pester' = @{ DependencyType = 'PSGalleryNuget'; version = 'latest' } - 'platyPS' = @{ DependencyType = 'PSGalleryNuget'; version = 'latest' } - 'posh-git' = @{ DependencyType = 'PSGalleryNuget'; version = 'latest' } - 'PSDeploy' = @{ DependencyType = 'PSGalleryNuget'; version = 'latest' } - 'PSFramework' = @{ DependencyType = 'PSGalleryNuget'; version = 'latest' } - 'PSScriptAnalyzer' = @{ DependencyType = 'PSGalleryNuget'; version = 'latest' } - 'powershell-yaml' = @{ DependencyType = 'PSGalleryNuget'; version = 'latest' } -} \ No newline at end of file diff --git a/SteamPS/Public/Server/Install-SteamCMD.ps1 b/SteamPS/Public/Server/Install-SteamCMD.ps1 index 1af9578..32c7ced 100644 --- a/SteamPS/Public/Server/Install-SteamCMD.ps1 +++ b/SteamPS/Public/Server/Install-SteamCMD.ps1 @@ -1,4 +1,3 @@ -#Requires -RunAsAdministrator function Install-SteamCMD { <# .SYNOPSIS @@ -47,6 +46,20 @@ function Install-SteamCMD { [switch]$Force ) + begin { + $isAdmin = ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole] "Administrator") + if ($isAdmin -eq $false) { + $Exception = [Exception]::new('The current PowerShell session is not running as Administrator. Start PowerShell by using the Run as Administrator option, and then try running the script again.') + $ErrorRecord = [System.Management.Automation.ErrorRecord]::new( + $Exception, + 'MissingUserPermissions', + [System.Management.Automation.ErrorCategory]::PermissionDenied, + $isAdmin + ) + $PSCmdlet.ThrowTerminatingError($ErrorRecord) + } + } + process { if ($Force -or $PSCmdlet.ShouldContinue('Would you like to continue?', 'Install SteamCMD')) { # Ensures that SteamCMD is installed in a folder named SteamCMD. diff --git a/SteamPS/SteamPS.psd1 b/SteamPS/SteamPS.psd1 index 87d5655..15293f6 100644 --- a/SteamPS/SteamPS.psd1 +++ b/SteamPS/SteamPS.psd1 @@ -12,7 +12,7 @@ RootModule = 'SteamPS.psm1' # Version number of this module. - ModuleVersion = '3.2.2' + ModuleVersion = '3.2.3' # Supported PSEditions # CompatiblePSEditions = @() @@ -27,13 +27,13 @@ CompanyName = 'hjorslev' # Copyright statement for this module - Copyright = '(c) 2019-2021 Frederik Hjorslev Nylander. All rights reserved.' + Copyright = '(c) 2019-2024 Frederik Hjorslev Nylander. All rights reserved.' # Description of the functionality provided by this module Description = 'Module that utilizes PowerShell as a wrapper for SteamCMD and engages with several Steam APIs.' # Minimum version of the Windows PowerShell engine required by this module - PowerShellVersion = '5.0' + PowerShellVersion = '5.1' # Name of the Windows PowerShell host required by this module # PowerShellHostName = '' @@ -51,7 +51,7 @@ # ProcessorArchitecture = '' # Modules that must be imported into the global environment prior to importing this module - RequiredModules = @(@{ ModuleName = 'PSFramework'; GUID = '8028b914-132b-431f-baa9-94a6952f21ff'; ModuleVersion = '1.4.149' }) + # RequiredModules = @(@{ ModuleName = 'PSFramework'; GUID = '8028b914-132b-431f-baa9-94a6952f21ff'; ModuleVersion = '1.10.318' }) # Assemblies that must be loaded prior to importing this module # RequiredAssemblies = @() diff --git a/SteamPS/SteamPS.psm1 b/SteamPS/SteamPS.psm1 deleted file mode 100644 index b355c98..0000000 --- a/SteamPS/SteamPS.psm1 +++ /dev/null @@ -1,40 +0,0 @@ -# Get public and private function definition files. -$Public = @( Get-ChildItem -Path $PSScriptRoot\Public\*.ps1 -Recurse -ErrorAction SilentlyContinue ) -$Private = @( Get-ChildItem -Path $PSScriptRoot\Private\*.ps1 -Recurse -ErrorAction SilentlyContinue ) - -# Dot source the files -foreach ($Import in @($Public + $Private)) { - try { - . $Import.FullName - } catch { - Write-Error -Message "Failed to import function $($Import.FullName): $_" - } -} - -Export-ModuleMember -Function $Public.BaseName - -if ($Host.Name -eq 'Windows PowerShell ISE Host') { - Write-Warning -Message 'Output from SteamCMD might not be visible in PowerShell ISE, but will run in the background.' - Write-Warning -Message 'Consider using PowerShell ConsoleHost instead.' -} - -# Enums -enum ServerType { - Dedicated = 0x64 #d - NonDedicated = 0x6C #l - SourceTV = 0x70 #p -} -enum OSType { - Linux = 108 #l - Windows = 119 #w - Mac = 109 #m - MacOsX = 111 #o -} -enum VAC { - Unsecured = 0 - Secured = 1 -} -enum Visibility { - Public = 0 - Private = 1 -} \ No newline at end of file diff --git a/Tests/Help.Tests.ps1 b/Tests/Help.Tests.ps1 index 39c4edc..118136e 100644 --- a/Tests/Help.Tests.ps1 +++ b/Tests/Help.Tests.ps1 @@ -1,24 +1,20 @@ # By Joel Sallow - https://github.com/vexx32/ BeforeAll { - Import-Module $env:BHPSModuleManifest + Import-Module "$($ReleasePath)\SteamPS.psm1" } -Describe "$env:BHProjectName Sanity Tests - Help Content" -Tags 'Module' { +Describe "Sanity Tests - Help Content" -Tags 'Module' { #region Discovery # The module will need to be imported during Discovery since we're using it to generate test cases / Context blocks - Import-Module $env:BHPSModuleManifest + Import-Module "$($ReleasePath)\SteamPS.psm1" $ShouldProcessParameters = 'WhatIf', 'Confirm' # Generate command list for generating Context / TestCases - $Module = Get-Module -Name $env:BHProjectName - $CommandList = @( - $Module.ExportedFunctions.Keys - $Module.ExportedCmdlets.Keys - ) + $CommandList = (Get-ChildItem "$($SteamPSModulePath)\Public\" -Recurse | Where-Object { -not $_.PSIsContainer }).BaseName #endregion Discovery diff --git a/Tests/ModuleValidation.Tests.ps1 b/Tests/ModuleValidation.Tests.ps1 index 9fa70eb..2f42a95 100644 --- a/Tests/ModuleValidation.Tests.ps1 +++ b/Tests/ModuleValidation.Tests.ps1 @@ -1,7 +1,7 @@ Describe 'Static Analysis: Module & Repository Files' -Tags 'Module' { #region Discovery $FileSearch = @{ - Path = $env:BHProjectPath + Path = $ReleasePath Include = '*.ps1', '*.psm1', '*.psd1' Recurse = $true } @@ -24,30 +24,16 @@ Context 'Module Import' { It 'cleanly imports the module' { - { Import-Module $env:BHPSModuleManifest -Force } | Should -Not -Throw + { Import-Module "$($ReleasePath)\SteamPS.psd1" -Force } | Should -Not -Throw } It 'removes and re-imports the module without errors' { $Script = { - Remove-Module $env:BHProjectName - Import-Module $env:BHPSModuleManifest + Remove-Module SteamPS + Import-Module "$($ReleasePath)\SteamPS.psd1" } $Script | Should -Not -Throw } } - - if (((Get-BuildEnvironment).BranchName -eq 'master') -and ($env:BHCommitMessage -like "*!deploy*")) { - Context 'Changelog' { - It 'Version in Changelog should be greater than version in Manifest' { - # Expects that the latest version is located at line 8. - [version]((Get-Content -Path "$env:BHProjectPath\CHANGELOG.md")[7]).Substring(4, 5) | Should -BeGreaterThan (Import-PowerShellDataFile -Path $env:BHPSModuleManifest).ModuleVersion - } - It 'Should not be Unreleased, but display a date' { - ((Get-Content -Path "$env:BHProjectPath\CHANGELOG.md")[7]).Substring(13) | Should -not -BeExactly 'Unreleased' - } - } # Context: Changelog - } else { - Write-Verbose -Message "Skipping checking for 'Unreleased' string since we are on dev branch." - } } # Describe \ No newline at end of file diff --git a/Tests/PSScriptAnalyzer.Tests.ps1 b/Tests/PSScriptAnalyzer.Tests.ps1 deleted file mode 100644 index 9533772..0000000 --- a/Tests/PSScriptAnalyzer.Tests.ps1 +++ /dev/null @@ -1,19 +0,0 @@ -Describe 'PSScriptAnalyzer analysis' -Tag 'PSScriptAnalyzer' { - #region Discovery - $PowerShellFiles = Get-ChildItem -Path $env:BHModulePath -Recurse -Filter "*.ps*1" - #endregion Discovery - - It " Should not violate: " -TestCases @( - foreach ($File in $PowerShellFiles) { - foreach ($Rule in (Get-ScriptAnalyzerRule)) { - @{ - IncludeRule = $Rule.RuleName - Path = $File.FullName - } - } - } - ) { - param($IncludeRule, $Path) - Invoke-ScriptAnalyzer -Path $Path -IncludeRule $IncludeRule -Settings "$env:BHProjectPath\PSScriptAnalyzerSettings.psd1" | Should -BeNullOrEmpty - } -} \ No newline at end of file diff --git a/Tests/SteamAPI.Tests.ps1 b/Tests/SteamAPI.Tests.ps1 index 6d6f876..3f57829 100644 --- a/Tests/SteamAPI.Tests.ps1 +++ b/Tests/SteamAPI.Tests.ps1 @@ -6,10 +6,11 @@ } } +<# TODO: Fix auth Describe 'Resolve-VanityURL' { BeforeEach { function Get-SteamAPIKey {} - InModuleScope $env:BHProjectName { + InModuleScope SteamPS { Mock -CommandName Get-SteamAPIKey -MockWith { Write-Output -InputObject $env:STEAMWEBAPI } @@ -21,4 +22,5 @@ Describe 'Resolve-VanityURL' { It "Resolves a group" { (Resolve-VanityURL -VanityURL 'SASEliteVirtualRegiment' -UrlType 2).SteamID64 | Should -BeExactly 103582791433675899 } -} \ No newline at end of file +} +#> \ No newline at end of file diff --git a/Tests/SteamPS.Tests.ps1 b/Tests/SteamPS.Tests.ps1 index 5941d08..9b81e11 100644 --- a/Tests/SteamPS.Tests.ps1 +++ b/Tests/SteamPS.Tests.ps1 @@ -1,13 +1,70 @@ -Describe "Get-SteamServerInfo" { - It 'Finds information about a Steam based game server' { - $ServerInfo = Get-SteamServerInfo -IPAddress '185.15.73.207' -Port 27015 - $ServerInfo.InstallDir | Should -Be 'groundbranch' +Describe "Get-SteamServerInfo Tests" { + Context "When querying a valid server" { + It "Should return server information" { + # Mocking the Get-SteamServerInfo function + Mock Get-SteamServerInfo { + [PSCustomObject]@{ + Protocol = 17 + ServerName = "SAS Proving Ground 10 (EU)" + Map = "TH-SmallTown" + InstallDir = "groundbranch" + GameName = "Ground Branch" + AppID = 16900 + Players = 6 + MaxPlayers = 10 + Bots = 0 + ServerType = "Dedicated" + Environment = "Windows" + Visibility = "Public" + VAC = "Unsecured" + Version = "1.0.0.0" + ExtraDataFlag = 177 + IPAddress = "135.239.211.40" + Port = 27015 + } + } + + # Invoke the function under test + $result = Get-SteamServerInfo -IPAddress '135.239.211.40' -Port 27015 + + # Assertions + $result | Should -Not -BeNullOrEmpty + $result.ServerName | Should -Be "SAS Proving Ground 10 (EU)" + $result.Map | Should -Be "TH-SmallTown" + $result.InstallDir | Should -Be "groundbranch" + $result.GameName | Should -Be "Ground Branch" + $result.AppID | Should -Be 16900 + $result.Players | Should -Be 6 + $result.MaxPlayers | Should -Be 10 + $result.Bots | Should -Be 0 + $result.ServerType | Should -Be "Dedicated" + $result.Environment | Should -Be "Windows" + $result.Visibility | Should -Be "Public" + $result.VAC | Should -Be "Unsecured" + $result.Version | Should -Be "1.0.0.0" + $result.IPAddress | Should -Be "135.239.211.40" + $result.Port | Should -Be 27015 + } + } + + Context "When querying an invalid server" { + It "Should throw an error" { + # Mocking the Get-SteamServerInfo function to simulate failure + Mock Get-SteamServerInfo { + throw "Server not found" + } + + # Invoke the function under test and capture the exception + $errorActionPreference = 'Stop' + { Get-SteamServerInfo -IPAddress 'invalid' -Port 1234 } | Should -Throw + $errorActionPreference = 'Continue' + } } } Describe 'SteamCMD cmdlets' { BeforeAll { - . "$env:BHModulePath\Private\Server\Add-EnvPath.ps1" + . "$($SteamPSModulePath)\Private\Server\Add-EnvPath.ps1" Add-EnvPath -Path 'TestDrive:\Test\SteamCMD' Install-SteamCMD -InstallPath 'TestDrive:\Test' -Force @@ -17,7 +74,6 @@ Describe 'SteamCMD cmdlets' { Test-Path -Path "$TestDrive\Test\SteamCMD\steamcmd.exe" | Should -BeTrue } - <# @TODO: Can be activated after the project uses another CI than AppVeyor for building the module Context 'Update-SteamApp' { It 'Installs Ground Branch Dedicated Server using AppID' { Update-SteamApp -AppID 476400 -Path "$TestDrive\GB-AppID" -Force @@ -34,7 +90,6 @@ Describe 'SteamCMD cmdlets' { Test-Path -Path "$TestDrive\GB-TestingBranch\GroundBranchServer.exe" | Should -BeTrue } } -#> AfterAll { # Wait for the process steamerrorreporter to be closed - else test folder wont be deleted. diff --git a/Tools/PesterTest.ps1 b/Tools/PesterTest.ps1 new file mode 100644 index 0000000..bee67ac --- /dev/null +++ b/Tools/PesterTest.ps1 @@ -0,0 +1,106 @@ +[CmdletBinding()] +param ( + # The path where the Pester Tests are + [Parameter(Mandatory)] + [String] $TestPath, + + # The path where we export the Pester Results (Pester.xml, Coverage.xml, Coverage.json) + [Parameter(Mandatory)] + [String] $ResultPath, + + # The path to the Source Code + [Parameter(Mandatory)] + [string] $SourceRoot, + + # The path to the built Module + [Parameter(Mandatory)] + [string] $ReleasePath +) + +$ErrorActionPreference = 'Stop' + +$requirements = Import-PowerShellDataFile ([IO.Path]::Combine($PSScriptRoot, 'requiredModules.psd1')) +foreach ($req in $requirements.GetEnumerator() | Sort-Object { $_.Value['Priority'] }) { + $importModuleSplat = @{ + Name = ([IO.Path]::Combine($PSScriptRoot, 'Modules', $req.Key)) + Force = $true + DisableNameChecking = $true + } + + Write-Host "Importing: $($importModuleSplat['Name'])" + Import-Module @importModuleSplat +} + +[PSCustomObject] $PSVersionTable | + Select-Object -Property *, @{ + Name = 'Architecture' + Expression = { + switch ([IntPtr]::Size) { + 4 { + 'x86' + } + 8 { + 'x64' + } + default { + 'Unknown' + } + } + } + } | + Format-List | + Out-Host + +$configuration = [PesterConfiguration]::Default +$configuration.Output.Verbosity = 'Detailed' +$configuration.Run.PassThru = $true +$configuration.CodeCoverage.Enabled = $true +$configuration.CodeCoverage.Path = $ReleasePath +$configuration.CodeCoverage.OutputPath = [IO.Path]::Combine($ResultPath, 'Coverage.xml') +$configuration.Run.Throw = $true +$configuration.Run.Path = $TestPath +$configuration.TestResult.Enabled = $true +$configuration.TestResult.OutputPath = [IO.Path]::Combine($ResultPath, 'Pester.xml') +$configuration.TestResult.OutputFormat = 'NUnitXml' + +$pesterResult = Invoke-Pester -Configuration $configuration -WarningAction Ignore + +Push-Location $SourceRoot + +$out = [ordered]@{ + coverage = [ordered]@{} + messages = [ordered]@{} +} + +$coverageReults = @( + $pesterResult.CodeCoverage.CommandsMissed + $pesterResult.CodeCoverage.CommandsExecuted +) | Convert-LineNumber -Passthru + +$groups = $coverageReults | Group-Object SourceFile | ForEach-Object { + $out['coverage'][$_.Name] = [System.Collections.Generic.List[Object]]::new((, $null)) + $out['messages'][$_.Name] = [ordered]@{} + $_ +} + +foreach ($group in $groups) { + $map = $group.Group | Group-Object SourceLineNumber -AsHashTable -AsString + $totalLines = [System.Linq.Enumerable]::Count( + [System.IO.File]::ReadLines((Get-Item $group.Name).FullName)) + + foreach ($line in 1..$totalLines) { + $line = $line.ToString() + if ($map.ContainsKey($line)) { + $out['coverage'][$group.Name].Add($map[$line].HitCount) + $out['messages'][$group.Name][$line] = $map[$line].Command + continue + } + + $out['coverage'][$group.Name].Add($null) + } +} + +$out | ConvertTo-Json -Depth 99 | + Set-Content ([IO.Path]::Combine($ResultPath, 'Coverage.json')) + +Pop-Location diff --git a/Tools/requiredModules.psd1 b/Tools/requiredModules.psd1 new file mode 100644 index 0000000..3505c5f --- /dev/null +++ b/Tools/requiredModules.psd1 @@ -0,0 +1,34 @@ +@{ + InvokeBuild = @{ + Priority = 3 + Version = '5.10.3' + } + platyPS = @{ + Priority = 3 + Version = '0.14.2' + } + PSScriptAnalyzer = @{ + Priority = 3 + Version = '1.21.0' + } + Configuration = @{ + Priority = 2 + Version = '1.5.1' + } + ModuleBuilder = @{ + Priority = 3 + Version = '3.0.0' + } + Metadata = @{ + Priority = 1 + Version = '1.5.7' + } + Pester = @{ + Priority = 3 + Version = '5.4.1' + } + PSFramework = @{ + Priority = 3 + Version = '1.10.318' + } +} diff --git a/appveyor.yml b/appveyor.yml deleted file mode 100644 index 51ef9f1..0000000 --- a/appveyor.yml +++ /dev/null @@ -1,36 +0,0 @@ -install: -- ps: Install-Module -Name PSDepend -Force -- ps: Invoke-PSDepend -Force -skip_commits: - message: /skip ci.*|update readme.*|update changelog.*|update docs.*|update version.*/ - files: - - .github/* - - .vscode/* - - docs/* - - appveyor.yml - - CONTRIBUTING.md - - LICENSE.md - - README.md - - .editorconfig - - .azure-pipelines/* -environment: - PSGalleryAPIKey: - secure: AhQDcc7fd1PVg8stMqWeeGnrrcZb/KcGxtBvcnmkT6hZekOIhaSNtmtX4g9kCqXk - GitHubKey: - secure: N7+lKlNrQkJHEtEtl1CcwG9Q3GRLbH9kGD41NWfb0GbLsH9rHjMoIiCVkDF8jolr - SteamWebAPI: - secure: BwdIjZqaiXF+wUlkiqqawe029HTDlgu6NEUkkAQQPzTXswYBzeTJmYJbFMVDybr9 -version: 3.2.1.{build} -test_script: -- git config --global credential.helper store -- ps: Add-Content "$env:USERPROFILE\.git-credentials" "https://$($env:GitHubKey):x-oauth-basic@github.com`n" -- git config --global user.email "frederik@hjorslev.com" -- git config --global user.name "Frederik Hjorslev Nylander" -- git config --global core.autocrlf false -- git config --global core.safecrlf false -- ps: Write-Host -Object "------------------ Invoke-Build ------------------" -- ps: Invoke-Build -pull_requests: - do_not_increment_build_number: true -skip_tags: true -build: off diff --git a/build.ps1 b/build.ps1 new file mode 100644 index 0000000..cfb9eb1 --- /dev/null +++ b/build.ps1 @@ -0,0 +1,72 @@ +# I may've totally stolen this from jborean93 :D +[CmdletBinding()] +param( + [Parameter()] + [ValidateSet('Debug', 'Release')] + [string] + $Configuration = 'Debug', + + [Parameter()] + [ValidateSet('Build', 'Test')] + [string[]] + $Task = 'Build' +) + +end { + if ($PSEdition -eq 'Desktop') { + [Net.ServicePointManager]::SecurityProtocol = [Net.ServicePointManager]::SecurityProtocol -bor 'Tls12' + } + + $modulePath = [IO.Path]::Combine($PSScriptRoot, 'tools', 'Modules') + $requirements = Import-PowerShellDataFile ([IO.Path]::Combine($PSScriptRoot, 'tools', 'requiredModules.psd1')) + + foreach ($req in $requirements.GetEnumerator() | Sort-Object { $_.Value['Priority'] }) { + $targetPath = [IO.Path]::Combine($modulePath, $req.Key) + + if (Test-Path -LiteralPath $targetPath) { + Import-Module -Name $targetPath -Force -ErrorAction Stop -DisableNameChecking + continue + } + + Write-Host "Installing build pre-req $($req.Key) as it is not installed" + $null = New-Item -Path $targetPath -ItemType Directory -Force + + $webParams = @{ + Uri = "https://www.powershellgallery.com/api/v2/package/$($req.Key)/$($req.Value['Version'])" + OutFile = [IO.Path]::Combine($modulePath, "$($req.Key).zip") + UseBasicParsing = $true + } + + if ('Authentication' -in (Get-Command -Name Invoke-WebRequest).Parameters.Keys) { + $webParams.Authentication = 'None' + } + + $oldProgress = $ProgressPreference + $ProgressPreference = 'SilentlyContinue' + + try { + Invoke-WebRequest @webParams + Expand-Archive -Path $webParams.OutFile -DestinationPath $targetPath -Force + Remove-Item -LiteralPath $webParams.OutFile -Force + } finally { + $ProgressPreference = $oldProgress + } + + Import-Module -Name $targetPath -Force -ErrorAction Stop -DisableNameChecking + } + + if (Test-Path (Join-Path $PSScriptRoot src)) { + $dotnetTools = @(dotnet tool list --global) -join "`n" + if (-not $dotnetTools.Contains('coverlet.console')) { + Write-Host 'Installing dotnet tool coverlet.console' + dotnet tool install --global coverlet.console + } + } + + $invokeBuildSplat = @{ + Task = $Task + File = (Get-Item ([IO.Path]::Combine($PSScriptRoot, '*.build.ps1'))).FullName + Configuration = $Configuration + } + Invoke-Build @invokeBuildSplat +}