From e638ca47d038e6ba8e579671fa1e7dc3b3694867 Mon Sep 17 00:00:00 2001 From: Oliver Lipkau Date: Wed, 10 Jan 2024 21:02:42 +0100 Subject: [PATCH] wip --- .github/workflows/ci.yml | 100 +++++++ .vscode/settings.json | 2 + CHANGELOG.md | 6 + JiraAgilePS.build.ps1 | 252 +++++++++--------- JiraAgilePS/JiraAgilePS.psd1 | 1 + PSScriptAnalyzerSettings.dev.psd1 | 5 + PSScriptAnalyzerSettings.psd1 | 2 +- Tests/Build.tests.ps1 | 59 ++++ .../Add-IssueToSprint.Unit.Tests.ps1 | 0 Tests/Functions/Get-Board.Unit.Tests.ps1 | 0 Tests/Functions/Get-Sprint.Unit.Tests.ps1 | 0 Tests/JiraAgilePS.Tests.ps1 | 66 +++++ Tests/PSScriptAnalyzer.Tests.ps1 | 64 +++++ Tests/Project.Tests.ps1 | 98 +++++++ Tests/Style.Tests.ps1 | 106 ++++++++ Tools/BuildTools.psm1 | 228 +--------------- Tools/build.requirements.psd1 | 14 +- Tools/setup.ps1 | 18 +- azure-pipelines.yml | 198 -------------- 19 files changed, 649 insertions(+), 570 deletions(-) create mode 100644 .github/workflows/ci.yml create mode 100644 PSScriptAnalyzerSettings.dev.psd1 create mode 100644 Tests/Build.tests.ps1 create mode 100644 Tests/Functions/Add-IssueToSprint.Unit.Tests.ps1 create mode 100644 Tests/Functions/Get-Board.Unit.Tests.ps1 create mode 100644 Tests/Functions/Get-Sprint.Unit.Tests.ps1 create mode 100644 Tests/JiraAgilePS.Tests.ps1 create mode 100644 Tests/PSScriptAnalyzer.Tests.ps1 create mode 100644 Tests/Project.Tests.ps1 create mode 100644 Tests/Style.Tests.ps1 delete mode 100644 azure-pipelines.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..1aac17a --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,100 @@ +name: Continuous Integration + +on: + push: + branches: [master, develop] + paths: + - "docs/**" + - "JiraAgilePS/**" + - "Tests/**" + pull_request: + branches: [master, develop] + paths: + - ".github/workflows/**" + - "docs/**" + - "JiraAgilePS/**" + - "Tests/**" + - "Tools/**" + - "JiraAgilePS.build.ps1" + - "PSScriptAnalyzerSettings.psd1" + - "PSScriptAnalyzerSettings.dev.psd1" + workflow_dispatch: + +defaults: + run: + shell: pwsh + +jobs: + build: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + + - uses: actions/cache@v3 + id: cacher + with: + key: ${{ runner.os }}-PSModules + path: "~/.local/share/powershell/Modules" + + - name: Setup + if: ${{ steps.cacher.outputs.cache-hit != 'true' }} + run: ./Tools/setup.ps1 + + - name: CI Context Info + run: Invoke-Build -Task ShowInfo + + - name: Build + run: Invoke-Build -Task Clean, Build + + - uses: actions/upload-artifact@v4 + with: + name: Release + path: | + ./Release/ + ./Tests + PSScriptAnalyzerSettings.psd1 + + test: + needs: [build] + + strategy: + matrix: + os: [windows-latest, ubuntu-latest, macos-latest] + shell: [pwsh] + include: + - os: windows-latest + shell: powershell + + runs-on: ${{ matrix.os }} + + steps: + - uses: actions/checkout@v4 + + - uses: actions/download-artifact@v4 + with: + name: Release + path: ./Release/ + + - uses: actions/cache@v3 + id: cacher + with: + key: ${{ runner.os }}-PSModules + path: "~/.local/share/powershell/Modules" + + - name: Setup + if: ${{ steps.cacher.outputs.cache-hit != 'true' }} + run: ${{ matrix.shell }} -c ". ./Tools/setup.ps1" + + - name: CI Context Info + run: ${{ matrix.shell }} -c "Invoke-Build -Task ShowInfo" + + - name: Test + run: ${{ matrix.shell }} -c "Invoke-Build -Task Test" + + - uses: actions/upload-artifact@v4 + with: + name: ${{ runner.os }}-${{ matrix.shell }}-TestResults + path: testResults*.xml + if-no-files-found: error + if: ${{ always() }} diff --git a/.vscode/settings.json b/.vscode/settings.json index 1dc4802..613921c 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -10,6 +10,8 @@ "powershell.codeFormatting.preset": "Stroustrup", "powershell.codeFormatting.ignoreOneLineBlock": true, "powershell.scriptAnalysis.settingsPath": "PSScriptAnalyzerSettings.psd1", + "powershell.pester.useLegacyCodeLens": true, + "powershell.pester.codeLens": false, "[shellscript]": { "files.eol": "\n" }, diff --git a/CHANGELOG.md b/CHANGELOG.md index 70250bb..c67ef2d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,12 @@ ### Fixed +## [0.1] -- TBD + +### Added + +Initial release + [@lipkau]: https://github.com/lipkau diff --git a/JiraAgilePS.build.ps1 b/JiraAgilePS.build.ps1 index a51ef33..91c5061 100644 --- a/JiraAgilePS.build.ps1 +++ b/JiraAgilePS.build.ps1 @@ -1,13 +1,12 @@ #requires -Modules InvokeBuild +#requires -Modules @{ ModuleName = 'Pester'; RequiredVersion = '5.5.0' } [CmdletBinding()] [System.Diagnostics.CodeAnalysis.SuppressMessage('PSAvoidUsingWriteHost', '')] [System.Diagnostics.CodeAnalysis.SuppressMessage('PSAvoidUsingEmptyCatchBlock', '')] param( [String[]]$Tag, - [String[]]$ExcludeTag = @("Integration"), - [String]$PSGalleryAPIKey, - [String]$GithubAccessToken + [String[]]$ExcludeTag = @("Integration") ) $WarningPreference = "Continue" @@ -28,31 +27,23 @@ catch { } Set-StrictMode -Version Latest -Import-Module "$PSScriptRoot/Tools/BuildTools.psm1" -Force -ErrorAction Stop - -if ($BuildTask -notin @("SetUp", "InstallDependencies")) { - Import-Module BuildHelpers -Force -ErrorAction Stop - Invoke-Init -} - #region SetUp -# Synopsis: Proxy task -task Init { Invoke-Init } +task Setup GetNextVersion +# Synopsis: Initialize the build environment +task Init { + Import-Module "$PSScriptRoot/Tools/BuildTools.psm1" -Force -ErrorAction Stop -# Synopsis: Create an initial environment for developing on the module -task SetUp InstallDependencies, Build - -# Synopsis: Install all module used for the development of this module -task InstallDependencies { - Install-Dependency + Import-Module BuildHelpers -Force -ErrorAction Stop + Set-BuildEnvironment -BuildOutput '$ProjectPath/Release' -ErrorAction SilentlyContinue + $env:BHInvokeBuild = "true" } # Synopsis: Get the next version for the build -task GetNextVersion { +task GetNextVersion Init, { $manifestVersion = [Version](Get-Metadata -Path $env:BHPSModuleManifest) try { $env:CurrentOnlineVersion = [Version](Find-Module -Name $env:BHProjectName).Version - $nextOnlineVersion = Get-NextNugetPackageVersion -Name $env:BHProjectName + $nextOnlineVersion = Get-NextNugetPackageVersion -Name $env:BHProjectName -ErrorAction Stop if ( ($manifestVersion.Major -gt $nextOnlineVersion.Major) -or ($manifestVersion.Minor -gt $nextOnlineVersion.Minor) @@ -91,7 +82,7 @@ switch ($true) { #endregion HarmonizeVariables #region DebugInformation -task ShowInfo Init, GetNextVersion, { +task ShowInfo Setup, { Write-Build Gray Write-Build Gray ('Running in: {0}' -f $env:BHBuildSystem) Write-Build Gray '-------------------------------------------------------' @@ -112,42 +103,35 @@ task ShowInfo Init, GetNextVersion, { Write-Build Gray ('OS: {0}' -f $OS) Write-Build Gray ('OS Version: {0}' -f $OSVersion) Write-Build Gray -} +} , RemoveBuildVariables #endregion DebugInformation #region BuildRelease # Synopsis: Build a shippable release -task Build Init, GenerateExternalHelp, CopyModuleFiles, UpdateManifest, CompileModule, PrepareTests +task Build Setup, GenerateExternalHelp, CopyModuleFiles, UpdateManifest, CompileModule # Synopsis: Generate ./Release structure task CopyModuleFiles { # Setup - if (-not (Test-Path "$env:BHBuildOutput/$env:BHProjectName")) { - $null = New-Item -Path "$env:BHBuildOutput/$env:BHProjectName" -ItemType Directory + if (-not (Test-Path "$env:BHBuildOutput")) { + $null = New-Item -Path "$env:BHBuildOutput" -ItemType Directory } # Copy module - Copy-Item -Path "$env:BHModulePath/*" -Destination "$env:BHBuildOutput/$env:BHProjectName" -Recurse -Force + Copy-Item -Path "$env:BHModulePath/*" -Destination "$env:BHBuildOutput" -Recurse -Force # Copy additional files Copy-Item -Path @( "$env:BHProjectPath/CHANGELOG.md" "$env:BHProjectPath/LICENSE" "$env:BHProjectPath/README.md" - ) -Destination "$env:BHBuildOutput/$env:BHProjectName" -Force -} - -# Synopsis: Prepare tests for ./Release -task PrepareTests Init, { - $null = New-Item -Path "$env:BHBuildOutput/Tests" -ItemType Directory -ErrorAction SilentlyContinue - Copy-Item -Path "$env:BHProjectPath/Tests" -Destination $env:BHBuildOutput -Recurse -Force - Copy-Item -Path "$env:BHProjectPath/PSScriptAnalyzerSettings.psd1" -Destination $env:BHBuildOutput -Force + ) -Destination "$env:BHBuildOutput" -Force } # Synopsis: Compile all functions into the .psm1 file -task CompileModule Init, { +task CompileModule { $regionsToKeep = @('Dependencies', 'Configuration') - $targetFile = "$env:BHBuildOutput/$env:BHProjectName/$env:BHProjectName.psm1" + $targetFile = "$env:BHBuildOutput/$env:BHProjectName.psm1" $content = Get-Content -Encoding UTF8 -LiteralPath $targetFile $capture = $false $compiled = "" @@ -165,8 +149,8 @@ task CompileModule Init, { } } - $PublicFunctions = @( Get-ChildItem -Path "$env:BHBuildOutput/$env:BHProjectName/Public/*.ps1" -ErrorAction SilentlyContinue ) - $PrivateFunctions = @( Get-ChildItem -Path "$env:BHBuildOutput/$env:BHProjectName/Private/*.ps1" -ErrorAction SilentlyContinue ) + $PublicFunctions = @( Get-ChildItem -Path "$env:BHBuildOutput/Public/*.ps1" -ErrorAction SilentlyContinue ) + $PrivateFunctions = @( Get-ChildItem -Path "$env:BHBuildOutput/Private/*.ps1" -ErrorAction SilentlyContinue ) foreach ($function in @($PublicFunctions + $PrivateFunctions)) { $compiled += (Get-Content -Path $function.FullName -Raw) @@ -176,11 +160,11 @@ task CompileModule Init, { Set-Content -LiteralPath $targetFile -Value $compiled -Encoding UTF8 -Force Remove-Utf8Bom -Path $targetFile - "Private", "Public" | Foreach-Object { Remove-Item -Path "$env:BHBuildOutput/$env:BHProjectName/$_" -Recurse -Force } + "Private", "Public" | ForEach-Object { Remove-Item -Path "$env:BHBuildOutput/$_" -Recurse -Force } } # Synopsis: Use PlatyPS to generate External-Help -task GenerateExternalHelp Init, { +task GenerateExternalHelp { Import-Module platyPS -Force foreach ($locale in (Get-ChildItem "$env:BHProjectPath/docs" -Attribute Directory)) { New-ExternalHelp -Path "$($locale.FullName)" -OutputPath "$env:BHModulePath/$($locale.Basename)" -Force @@ -190,144 +174,150 @@ task GenerateExternalHelp Init, { } # Synopsis: Update the manifest of the module -task UpdateManifest GetNextVersion, { +task UpdateManifest { Remove-Module $env:BHProjectName -ErrorAction SilentlyContinue Import-Module $env:BHPSModuleManifest -Force $ModuleAlias = @(Get-Alias | Where-Object { $_.ModuleName -eq "$env:BHProjectName" }) - BuildHelpers\Update-Metadata -Path "$env:BHBuildOutput/$env:BHProjectName/$env:BHProjectName.psd1" -PropertyName ModuleVersion -Value $env:NextBuildVersion - # BuildHelpers\Update-Metadata -Path "$env:BHBuildOutput/$env:BHProjectName/$env:BHProjectName.psd1" -PropertyName FileList -Value (Get-ChildItem "$env:BHBuildOutput/$env:BHProjectName" -Recurse).Name - BuildHelpers\Set-ModuleFunctions -Name "$env:BHBuildOutput/$env:BHProjectName/$env:BHProjectName.psd1" -FunctionsToExport ([string[]](Get-ChildItem "$env:BHBuildOutput/$env:BHProjectName/Public/*.ps1").BaseName) - BuildHelpers\Update-Metadata -Path "$env:BHBuildOutput/$env:BHProjectName/$env:BHProjectName.psd1" -PropertyName AliasesToExport -Value '' + Update-Metadata -Path "$env:BHBuildOutput/$env:BHProjectName.psd1" -PropertyName ModuleVersion -Value $env:NextBuildVersion + # BuildHelpers\Update-Metadata -Path "$env:BHBuildOutput/$env:BHProjectName.psd1" -PropertyName FileList -Value (Get-ChildItem "$env:BHBuildOutput" -Recurse).Name + BuildHelpers\Set-ModuleFunctions -Name "$env:BHBuildOutput/$env:BHProjectName.psd1" -FunctionsToExport ([string[]](Get-ChildItem "$env:BHBuildOutput/Public/*.ps1").BaseName) + Update-Metadata -Path "$env:BHBuildOutput/$env:BHProjectName.psd1" -PropertyName AliasesToExport -Value '' if ($ModuleAlias) { - BuildHelpers\Update-Metadata -Path "$env:BHBuildOutput/$env:BHProjectName/$env:BHProjectName.psd1" -PropertyName AliasesToExport -Value @($ModuleAlias.Name) + Update-Metadata -Path "$env:BHBuildOutput/$env:BHProjectName.psd1" -PropertyName AliasesToExport -Value @($ModuleAlias.Name) + } + + $Prerelease = '' + if ("$env:BHBranchName" -notin @('master', 'main')) { + $Prerelease = "$env:BHBranchName".ToLower() -replace '[^a-zA-Z0-9]' } + Update-Metadata -Path "$env:BHBuildOutput/$env:BHProjectName.psd1" -PropertyName Prerelease -Value $Prerelease + } # Synopsis: Create a ZIP file with this build -task Package Init, { +task Package Setup, { Assert-True { Test-Path "$env:BHBuildOutput\$env:BHProjectName" } "Missing files to package" Remove-Item "$env:BHBuildOutput\$env:BHProjectName.zip" -ErrorAction SilentlyContinue - $null = Compress-Archive -Path "$env:BHBuildOutput\$env:BHProjectName" -DestinationPath "$env:BHBuildOutput\$env:BHProjectName.zip" + $null = Compress-Archive -Path "$env:BHBuildOutput\*" -DestinationPath "$env:BHBuildOutput\$env:BHProjectName.zip" } #endregion BuildRelease #region Test -task Test Init, { +task Test Setup, { + $psVersion = $PSVersionTable.PSVersion.ToString() Assert-True { Test-Path $env:BHBuildOutput -PathType Container } "Release path must exist" Remove-Module $env:BHProjectName -ErrorAction SilentlyContinue - <# $params = @{ - Path = "$env:BHBuildOutput/$env:BHProjectName" - Include = '*.ps1', '*.psm1' - Recurse = $True - Exclude = $CodeCoverageExclude - } - $codeCoverageFiles = Get-ChildItem @params #> - - try { - $parameter = @{ - Script = "$env:BHBuildOutput/Tests/*" - Tag = $Tag - ExcludeTag = $ExcludeTag - Show = "Fails" - PassThru = $true - OutputFile = "$env:BHProjectPath/Test-$OS-$($PSVersionTable.PSVersion.ToString()).xml" + $pesterConfiguration = [PesterConfiguration]@{ + Run = @{ + Path = "$env:BHProjectPath/Tests/*" + Exist = $true + Throw = $true + } + Filter = @{ + Tag = $Tag + ExcludeTag = $ExcludeTag + } + TestResult = @{ + Enabled = $true OutputFormat = "NUnitXml" - # CodeCoverage = $codeCoverageFiles + OutputPath = "testResults-$OS-$psVersion.xml" } - $testResults = Invoke-Pester @parameter - - Assert-True ($testResults.FailedCount -eq 0) "$($testResults.FailedCount) Pester test(s) failed." - } - catch { - throw $_ + Output = @{ } } -}, { Init } + + Invoke-Pester -Configuration $pesterConfiguration +}, RemoveTestResults #endregion #region Publish # Synopsis: Publish a new release on github and the PSGallery -task Deploy Init, PublishToGallery, TagReplository, UpdateHomepage +task Publish Setup, PublishToGallery, TagReplository, UpdateHomepage, RemoveBuildVariables # Synpsis: Publish the $release to the PSGallery task PublishToGallery { - Assert-True (-not [String]::IsNullOrEmpty($PSGalleryAPIKey)) "No key for the PSGallery" - Assert-True { Get-Module $env:BHProjectName -ListAvailable } "Module $env:BHProjectName is not available" + $PSGalleryAPIKey = $env:NUGET_API_KEY + # Assert-True (-not [String]::IsNullOrEmpty($PSGalleryAPIKey)) "No key for the PSGallery" + # Assert-True { Get-Module $env:BHProjectName -ListAvailable } "Module $env:BHProjectName is not available" Remove-Module $env:BHProjectName -ErrorAction Ignore + Import-Module "$env:BHBuildOutput/JiraAgilePS" -ErrorAction Stop - Publish-Module -Name $env:BHProjectName -NuGetApiKey $PSGalleryAPIKey -} - -# Synopsis: Setup git -task SetupGit { - git config --global user.email "support@atlassianps.net" - git config --global user.name "AtlassianPS Automated User" + # Publish-Module -Name $env:BHProjectName -NuGetApiKey $PSGalleryAPIKey -WhatIf + Write-Build -Color "Red" "Running 'Publish-Module'" } # Synopsis: push a tag with the version to the git repository -task TagReplository GetNextVersion, Package, SetupGit, { - $releaseText = "Release version $env:NextBuildVersion" - - # Push a tag to the repository - Write-Build Gray "git checkout $ENV:BHBranchName" - cmd /c "git checkout $ENV:BHBranchName 2>&1" - - Write-Build Gray "git tag -a v$env:NextBuildVersion -m `"$releaseText`"" - cmd /c "git tag -a v$env:NextBuildVersion -m `"$releaseText`" 2>&1" - - Write-Build Gray "git push origin v$env:NextBuildVersion" - cmd /c "git push origin v$env:NextBuildVersion 2>&1" - - Write-Build Gray "Publish v$env:NextBuildVersion as a GitHub release" - $release = @{ - AccessToken = $GithubAccessToken - TagName = "v$env:NextBuildVersion" - Name = "Version $env:NextBuildVersion" - ReleaseText = $releaseText - RepositoryOwner = "AtlassianPS" - Artifact = "$env:BHBuildOutput\$env:BHProjectName.zip" - } - Publish-GithubRelease @release +task TagReplository GetNextVersion, Package, { + # $GithubAccessToken = $env:GITHUB_TOKEN + # Assert-True (-not [String]::IsNullOrEmpty($GithubAccessToken)) "No key for the PSGallery" + # $releaseText = "Release version $env:NextBuildVersion" + + # Set-GitUser + + # # Push a tag to the repository + # Write-Build Gray "git checkout $ENV:BHBranchName" + # cmd /c "git checkout $ENV:BHBranchName 2>&1" + + # Write-Build Gray "git tag -a v$env:NextBuildVersion -m `"$releaseText`"" + # cmd /c "git tag -a v$env:NextBuildVersion -m `"$releaseText`" 2>&1" + + # Write-Build Gray "git push origin v$env:NextBuildVersion" + # cmd /c "git push origin v$env:NextBuildVersion 2>&1" + + # Write-Build Gray "Publish v$env:NextBuildVersion as a GitHub release" + # $release = @{ + # AccessToken = $GithubAccessToken + # TagName = "v$env:NextBuildVersion" + # Name = "Version $env:NextBuildVersion" + # ReleaseText = $releaseText + # RepositoryOwner = "AtlassianPS" + # Artifact = "$env:BHBuildOutput\$env:BHProjectName.zip" # TODO: probably not the right file + # } + # Publish-GithubRelease @release + Write-Build "executing Publish-GithubRelease" } # Synopsis: Update the version of this module that the homepage uses -task UpdateHomepage SetupGit, { - try { - Write-Build Gray "git close .../AtlassianPS.github.io --recursive" - $null = cmd /c "git clone https://github.com/AtlassianPS/AtlassianPS.github.io --recursive 2>&1" +task UpdateHomepage { + # try { + # Set-GitUser - Push-Location "AtlassianPS.github.io/" + # Write-Build Gray "git close .../AtlassianPS.github.io --recursive" + # $null = cmd /c "git clone https://github.com/AtlassianPS/AtlassianPS.github.io --recursive 2>&1" - Write-Build Gray "git submodule foreach git pull origin master" - $null = cmd /c "git submodule foreach git pull origin master 2>&1" + # Push-Location "AtlassianPS.github.io/" - Write-Build Gray "git status -s" - $status = cmd /c "git status -s 2>&1" + # Write-Build Gray "git submodule foreach git pull origin master" + # $null = cmd /c "git submodule foreach git pull origin master 2>&1" - if ($status -contains " M modules/$env:BHProjectName") { - Write-Build Gray "git add modules/$env:BHProjectName" - $null = cmd /c "git add modules/$env:BHProjectName 2>&1" + # Write-Build Gray "git status -s" + # $status = cmd /c "git status -s 2>&1" - Write-Build Gray "git commit -m `"Update module $env:BHProjectName`"" - cmd /c "git commit -m `"Update module $env:BHProjectName`" 2>&1" + # if ($status -contains " M modules/$env:BHProjectName") { + # Write-Build Gray "git add modules/$env:BHProjectName" + # $null = cmd /c "git add modules/$env:BHProjectName 2>&1" - Write-Build Gray "git push" - cmd /c "git push 2>&1" - } + # Write-Build Gray "git commit -m `"Update module $env:BHProjectName`"" + # cmd /c "git commit -m `"Update module $env:BHProjectName`" 2>&1" - Pop-Location - } - catch { Write-Warning "Failed to deploy to homepage" } + # Write-Build Gray "git push" + # cmd /c "git push 2>&1" + # } + + # Pop-Location + # } + # catch { Write-Warning "Failed to deploy to homepage" } + Write-Build "Updating homepage" } #endregion Publish #region Cleaning tasks # Synopsis: Clean the working dir -task Clean Init, RemoveGeneratedFiles, RemoveTestResults +task Clean Setup, RemoveGeneratedFiles, RemoveTestResults #, RemoveBuildVariables # Synopsis: Remove generated and temp files. task RemoveGeneratedFiles { @@ -339,8 +329,12 @@ task RemoveGeneratedFiles { task RemoveTestResults { Remove-Item "Test-*.xml" -Force -ErrorAction SilentlyContinue } + +# Synopsis: Remove build variables +task RemoveBuildVariables { + Remove-Item -Path Env:\BH* +} #endregion -task . ShowInfo, Clean, Build, Test +task . Clean, Build, Test -Remove-Item -Path Env:\BH* diff --git a/JiraAgilePS/JiraAgilePS.psd1 b/JiraAgilePS/JiraAgilePS.psd1 index 93e0bec..455ae51 100644 --- a/JiraAgilePS/JiraAgilePS.psd1 +++ b/JiraAgilePS/JiraAgilePS.psd1 @@ -23,6 +23,7 @@ IconUri = 'https://AtlassianPS.org/assets/img/JiraAgilePS.png' ReleaseNotes = 'https://github.com/AtlassianPS/JiraAgilePS/blob/master/CHANGELOG.md' ExternalModuleDependencies = 'JiraPS' + Prerelease = '' } } DefaultCommandPrefix = 'JiraAgile' diff --git a/PSScriptAnalyzerSettings.dev.psd1 b/PSScriptAnalyzerSettings.dev.psd1 new file mode 100644 index 0000000..16d8472 --- /dev/null +++ b/PSScriptAnalyzerSettings.dev.psd1 @@ -0,0 +1,5 @@ +@{ + Severity = @('Error', 'Warning') + # IncludeRules = @() + ExcludeRules = @("PSAvoidOverwritingBuiltInCmdlets", "PSUseToExportFieldsInManifest") +} diff --git a/PSScriptAnalyzerSettings.psd1 b/PSScriptAnalyzerSettings.psd1 index 3ac3b77..cc1c176 100644 --- a/PSScriptAnalyzerSettings.psd1 +++ b/PSScriptAnalyzerSettings.psd1 @@ -1,5 +1,5 @@ @{ Severity = @('Error', 'Warning') # IncludeRules = @() - # ExcludeRules = @() + ExcludeRules = @("PSAvoidOverwritingBuiltInCmdlets") } diff --git a/Tests/Build.tests.ps1 b/Tests/Build.tests.ps1 new file mode 100644 index 0000000..245792b --- /dev/null +++ b/Tests/Build.tests.ps1 @@ -0,0 +1,59 @@ +#requires -modules Configuration +#requires -modules Pester + +BeforeAll { + $relativePath = "$PSScriptRoot/.." + if ($env:BHBuildOutput) { $relativePath = $env:BHBuildOutput } + Remove-Module "JiraAgilePS" -ErrorAction SilentlyContinue + Import-Module "$relativePath/JiraAgilePS" -Force +} +AfterAll { + Remove-Module JiraAgilePS -ErrorAction SilentlyContinue +} + +Describe "Validation of build environment" -Tag Unit { + + BeforeAll { + $module = Get-Module JiraAgilePS + } + + It "is a build" { + $module.Name | Should -Be "JiraAgilePs" + } + + Context "CHANGELOG" { + + BeforeAll { + $changelogFile = "$relativePath/CHANGELOG.md" + } + + It "has a changelog file" { + $changelogFile | Should -Exist + } + + Context "CHANGELOG content" { + + BeforeAll { + function Get-FirstVersionFromChangeLog($Path) { + foreach ($line in (Get-Content $Path)) { + if ($line -match "(?:##|\)\s*\[(?(\d+\.?){1,2})\]") { + return $matches.Version + } + } + } + + $changelogVersion = Get-FirstVersionFromChangeLog -Path $changelogFile + } + + It "has a valid version in the changelog" { + $changelogVersion | Should -Not -BeNullOrEmpty + [Version]($changelogVersion) | Should -BeOfType [Version] + } + + It "has a version changelog that matches the manifest version" { + $metadataFile = $module.Path -replace "psm1", "psd1" + Get-Metadata -Path $metadataFile -PropertyName ModuleVersion | Should -BeLike "$changelogVersion*" + } + } + } +} diff --git a/Tests/Functions/Add-IssueToSprint.Unit.Tests.ps1 b/Tests/Functions/Add-IssueToSprint.Unit.Tests.ps1 new file mode 100644 index 0000000..e69de29 diff --git a/Tests/Functions/Get-Board.Unit.Tests.ps1 b/Tests/Functions/Get-Board.Unit.Tests.ps1 new file mode 100644 index 0000000..e69de29 diff --git a/Tests/Functions/Get-Sprint.Unit.Tests.ps1 b/Tests/Functions/Get-Sprint.Unit.Tests.ps1 new file mode 100644 index 0000000..e69de29 diff --git a/Tests/JiraAgilePS.Tests.ps1 b/Tests/JiraAgilePS.Tests.ps1 new file mode 100644 index 0000000..02adfe4 --- /dev/null +++ b/Tests/JiraAgilePS.Tests.ps1 @@ -0,0 +1,66 @@ +#requires -modules Configuration +#requires -modules Pester + +BeforeAll { + $relativePath = "$PSScriptRoot/.." + if ($env:BHBuildOutput) { $relativePath = $env:BHBuildOutput } + Remove-Module "JiraAgilePS" -ErrorAction SilentlyContinue + Import-Module "$relativePath/JiraAgilePS" -Force +} +AfterAll { + Remove-Module JiraAgilePS -ErrorAction SilentlyContinue +} + +Describe "General project validation" -Tag Unit { + + BeforeAll { + $module = Get-Module JiraAgilePS + $metadataFile = $module.Path -replace "psm1", "psd1" + Remove-Module JiraAgilePS + } + + It "passes Test-ModuleManifest" { + { Test-ModuleManifest -Path $metadataFile -ErrorAction Stop } | Should -Not -Throw + } + + It "module can import without errors" { + { Import-Module $metadataFile } | Should -Not -Throw + } + + It "module exports functions" { + Import-Module $metadataFile + + (Get-Command -Module "JiraAgilePS" | Measure-Object).Count | Should -BeGreaterThan 0 + } + + It "module uses the correct root module" { + Get-Metadata -Path $metadataFile -PropertyName RootModule | Should -Be 'JiraAgilePS.psm1' + } + + It "module uses the correct guid" { + Get-Metadata -Path $metadataFile -PropertyName Guid | Should -Be '4de7d140-4fb6-4ac3-a187-82dcd762ebe9' + } + + It "module uses a valid version" { + [Version](Get-Metadata -Path $metadataFile -PropertyName ModuleVersion) | Should -Not -BeNullOrEmpty + [Version](Get-Metadata -Path $metadataFile -PropertyName ModuleVersion) | Should -BeOfType [Version] + } + + # It "module is imported with default prefix" { + # $prefix = Get-Metadata -Path $metadataFile -PropertyName DefaultCommandPrefix + + # Import-Module $metadataFile -Force -ErrorAction Stop + # (Get-Command -Module "JiraAgilePS").Name | ForEach-Object { + # $_ | Should -Match "\-$prefix" + # } + # } + + # It "module is imported with custom prefix" { + # $prefix = "Wiki" + + # Import-Module $metadataFile -Prefix $prefix -Force -ErrorAction Stop + # (Get-Command -Module "JiraAgilePS").Name | ForEach-Object { + # $_ | Should -Match "\-$prefix" + # } + # } +} diff --git a/Tests/PSScriptAnalyzer.Tests.ps1 b/Tests/PSScriptAnalyzer.Tests.ps1 new file mode 100644 index 0000000..3cbff91 --- /dev/null +++ b/Tests/PSScriptAnalyzer.Tests.ps1 @@ -0,0 +1,64 @@ +#requires -modules Pester +#requires -modules PSScriptAnalyzer + +BeforeDiscovery { + $modulePath = "$PSScriptRoot/../JiraAgilePS" + Import-Module $modulePath + + $psFiles = Get-ChildItem $modulePath -Include *.ps1, *.psm1 -Recurse +} +BeforeAll { + $moduleRoot, $relativePath = "$PSScriptRoot/.." + if ($env:BHBuildOutput) { $relativePath = $env:BHBuildOutput } + Remove-Module "JiraAgilePS" -ErrorAction SilentlyContinue + Import-Module "$relativePath/JiraAgilePS" -Force +} +AfterAll { + Remove-Module JiraAgilePS -ErrorAction SilentlyContinue +} + +Describe "PSScriptAnalyzer Tests" -Tag Unit { + + BeforeAll { + $module = Get-Module "JiraAgilePS" + $modulePath = (Get-Module "JiraAgilePS").Path -replace "JiraAgilePS.psm1", "" + if ($env:BHBuildOutput) { $settingsFile = "$moduleRoot/PSScriptAnalyzerSettings.psd1" } + else { $settingsFile = "$moduleRoot/PSScriptAnalyzerSettings.dev.psd1" } + + $Params = @{ + Path = $modulePath + Settings = $settingsFile + Recurse = $true + Verbose = $false + ErrorVariable = 'ErrorVariable' + ErrorAction = 'SilentlyContinue' + } + $ScriptWarnings = Invoke-ScriptAnalyzer @Params + } + + Describe "" -ForEach $psFiles { + + BeforeAll { + $psFile = $_ + $psFileName = $psFile.BaseName + } + + It "passes all rules" { + $BadLines = $ScriptWarnings | Where-Object { $_.ScriptPath -like $psFile.FullName } + $BadLines | Should -Be $null + } + + It "has no parse errors" { + $Exceptions = $null + + if ($ErrorVariable) { + $Exceptions = $ErrorVariable.Exception.Message | + Where-Object { $_ -match [regex]::Escape($psFile.FullName) } + } + + foreach ($Exception in $Exceptions) { + $Exception | Should -BeNullOrEmpty + } + } + } +} diff --git a/Tests/Project.Tests.ps1 b/Tests/Project.Tests.ps1 new file mode 100644 index 0000000..983e563 --- /dev/null +++ b/Tests/Project.Tests.ps1 @@ -0,0 +1,98 @@ +#requires -modules Pester + +BeforeDiscovery { + $modulePath = "$PSScriptRoot/../JiraAgilePS" + Import-Module $modulePath + + $publicFunctions = Get-ChildItem "$modulePath/Public/*.ps1" | Select-Object -Expand BaseName + $privateFunctions = Get-ChildItem "$modulePath/Private/*.ps1" | Select-Object -Expand BaseName +} +BeforeAll { + $relativePath = "$PSScriptRoot/.." + # if ($env:BHBuildOutput) { $relativePath = $env:BHBuildOutput } ## This test always needs root of the porject + Remove-Module "JiraAgilePS" -ErrorAction SilentlyContinue + Import-Module "$relativePath/JiraAgilePS" -Force +} +AfterAll { + Remove-Module "JiraAgilePS" -ErrorAction SilentlyContinue +} + +Describe "General project validation" -Tag Unit { + + BeforeAll { + $module = Get-Module "JiraAgilePS" + $modulePath = (Get-Module "JiraAgilePS").Path -replace "JiraAgilePS.psm1", "" + $testFiles = Get-ChildItem $PSScriptRoot -Include "*.Tests.ps1" -Recurse + $publicFunctions = Get-ChildItem "$modulePath/Public/*.ps1" | Select-Object -Expand BaseName + } + + Describe "Public functions" { + Describe "<_>" -ForEach @($publicFunctions) { + + It "has a test file" { + $functionName = $_ + $expectedTestFile = "$functionName.Unit.Tests.ps1" + + $testFiles.Name | Should -Contain $expectedTestFile + } + + It "is exported" { + $functionName = $_ + $expectedFunctionName = $functionName -replace "\-", "-$($module.Prefix)" + + $module.ExportedCommands.keys | Should -Contain $expectedFunctionName + } + } + } + + Describe "Private functions" { + Describe "<_>" -ForEach @($privateFunctions) { + # TODO: + # It "has a test file" { + # $functionName = $_ + # $expectedTestFile = "$functionName.Unit.Tests.ps1" + + # $testFiles.Name | Should -Contain $expectedTestFile + # } + + It "is not exported" { + $functionName = $_ + $expectedFunctionName = $functionName -replace "\-", "-$($module.Prefix)" + + $module.ExportedCommands.keys | Should -Not -Contain $expectedFunctionName + } + } + } + + <# + Describe "Classes" { + + foreach ($class in ([AtlassianPS.ServerData].Assembly.GetTypes() | Where-Object IsClass)) { + It "has a test file for $class" { + $expectedTestFile = "$class.Unit.Tests.ps1" + $testFiles.Name | Should -Contain $expectedTestFile + } + } + } + + Describe "Enumeration" { + + foreach ($enum in ([AtlassianPS.ServerData].Assembly.GetTypes() | Where-Object IsEnum)) { + It "has a test file for $enum" { + $expectedTestFile = "$enum.Unit.Tests.ps1" + $testFiles.Name | Should -Contain $expectedTestFile + } + } + } +#> + + Describe "Project stucture" { + + It "defines <_> as dedicated file in 'JiraAgilePS/Public'" -ForEach (Get-Module "JiraAgilePS").ExportedFunctions.Keys { + $functionName = $_ + $function = $functionName.Replace((Get-Module -Name JiraAgilePS).Prefix, '') + + $publicFunctions | Should -Contain $function + } + } +} diff --git a/Tests/Style.Tests.ps1 b/Tests/Style.Tests.ps1 new file mode 100644 index 0000000..7f1f7d0 --- /dev/null +++ b/Tests/Style.Tests.ps1 @@ -0,0 +1,106 @@ +#requires -modules Pester + +BeforeAll { + Import-Module "$PSScriptRoot/../Tools/BuildTools.psm1" -Force -ErrorAction Stop +} + +Describe "Validation of code styling" { + + BeforeAll { + $docFiles = Get-ChildItem "$PSScriptRoot/.." -Include *.md -Recurse + $codeFiles = Get-ChildItem "$PSScriptRoot/.." -Include *.ps1, *.psm1 -Recurse + } + + It "has no trailing whitespace in code files" { + $badLines = @( + foreach ($file in $codeFiles) { + $lines = [System.IO.File]::ReadAllLines($file.FullName) + $lineCount = $lines.Count + + for ($i = 0; $i -lt $lineCount; $i++) { + if ($lines[$i] -match '\s+$') { + 'File: {0}, Line: {1}' -f $file.FullName, ($i + 1) + } + } + } + ) + + if ($badLines.Count -gt 0) { + throw "The following $($badLines.Count) lines contain trailing whitespace: `r`n`r`n$($badLines -join "`r`n")" + } + } + + It "has one newline at the end of the file" { + $badFiles = @( + foreach ($file in @($codeFiles + $docFiles)) { + $string = [System.IO.File]::ReadAllText($file.FullName) + if ($string.Length -gt 0 -and $string[-1] -ne "`n") { + $file.FullName + } + } + ) + + if ($badFiles.Count -gt 0) { + throw "The following files do not end with a newline: `r`n`r`n$($badFiles -join "`r`n")" + } + } + + It "uses UTF-8 for code files" { + $badFiles = @( + foreach ($file in $codeFiles) { + $encoding = Get-FileEncoding -Path $file.FullName + if ($encoding -and $encoding.encoding -ne "UTF8") { + $file.FullName + } + } + ) + + if ($badFiles.Count -gt 0) { + throw "The following files are not encoded with UTF-8 (no BOM): `r`n`r`n$($badFiles -join "`r`n")" + } + } + It "uses UTF-8 for documentation files" { + $badFiles = @( + foreach ($file in $docFiles) { + $encoding = Get-FileEncoding -Path $file.FullName + if ($encoding -and $encoding.encoding -ne "UTF8") { + $file.FullName + } + } + ) + + if ($badFiles.Count -gt 0) { + throw "The following files are not encoded with UTF-8 (no BOM): `r`n`r`n$($badFiles -join "`r`n")" + } + } + + It "uses CRLF as newline character in code files" { + $badFiles = @( + foreach ($file in $codeFiles) { + $string = [System.IO.File]::ReadAllText($file.FullName) + if ($string.Length -gt 0 -and $string -notmatch "\r\n$") { + $file.FullName + } + } + ) + + if ($badFiles.Count -gt 0) { + throw "The following files do not use CRLF as line break: `r`n`r`n$($badFiles -join "`r`n")" + } + } + + It "uses CRLF as newline character in documentation files" { + $badFiles = @( + foreach ($file in $docFiles) { + $string = [System.IO.File]::ReadAllText($file.FullName) + if ($string.Length -gt 0 -and $string -notmatch "\r\n$") { + $file.FullName + } + } + ) + + if ($badFiles.Count -gt 0) { + throw "The following files do not use CRLF as line break: `r`n`r`n$($badFiles -join "`r`n")" + } + } +} diff --git a/Tools/BuildTools.psm1 b/Tools/BuildTools.psm1 index e0c2a6c..5b7d6f1 100644 --- a/Tools/BuildTools.psm1 +++ b/Tools/BuildTools.psm1 @@ -1,16 +1,8 @@ +#requires -Modules PowerShellGet + [CmdletBinding()] param() -function Invoke-Init { - [Alias("Init")] - [CmdletBinding()] - param() - begin { - Set-BuildEnvironment -BuildOutput '$ProjectPath/Release' -ErrorAction SilentlyContinue - Add-ToModulePath -Path $env:BHBuildOutput - } -} - function Assert-True { [CmdletBinding( DefaultParameterSetName = 'ByBool' )] param( @@ -37,14 +29,6 @@ function LogCall { Set-Content -Value "$($MyInvocation.Invocationname) $($MyInvocation.UnBoundArguments -join " ")" -Path "TestDrive:\FunctionCalled.$($MyInvocation.Invocationname).txt" -Force } -function Add-ToModulePath ([String]$Path) { - $PSModulePath = $env:PSModulePath -split ([IO.Path]::PathSeparator) - if ($Path -notin $PSModulePath) { - $PSModulePath += $Path - $env:PSModulePath = $PSModulePath -join ([IO.Path]::PathSeparator) - } -} - function Install-Dependency { [CmdletBinding()] param( @@ -64,214 +48,6 @@ function Install-Dependency { $RequiredModules | Import-Module } -function Get-AppVeyorBuild { - param() - - Assert-True { $env:APPVEYOR_API_TOKEN } "missing api token for AppVeyor." - Assert-True { $env:APPVEYOR_ACCOUNT_NAME } "not an appveyor build." - - $invokeRestMethodSplat = @{ - Uri = "https://ci.appveyor.com/api/projects/$env:APPVEYOR_ACCOUNT_NAME/$env:APPVEYOR_PROJECT_SLUG" - Method = 'GET' - Headers = @{ - "Authorization" = "Bearer $env:APPVEYOR_API_TOKEN" - "Content-type" = "application/json" - } - } - Invoke-RestMethod @invokeRestMethodSplat -} - -function Get-TravisBuild { - param() - - Assert-True { $env:TRAVIS_API_TOKEN } "missing api token for Travis-CI." - Assert-True { $env:APPVEYOR_ACCOUNT_NAME } "not an appveyor build." - - $invokeRestMethodSplat = @{ - Uri = "https://api.travis-ci.org/builds?limit=10" - Method = 'Get' - Headers = @{ - "Authorization" = "token $env:TRAVIS_API_TOKEN" - "Travis-API-Version" = "3" - } - } - Invoke-RestMethod @invokeRestMethodSplat -} - -function Test-IsLastJob { - param() - - if (-not ('AppVeyor' -eq $env:BHBuildSystem)) { - return $true - } - Assert-True { $env:APPVEYOR_JOB_ID } "Invalid Job identifier" - - $buildData = Get-AppVeyorBuild - $lastJob = ($buildData.build.jobs | Select-Object -Last 1).jobId - - if ($lastJob -eq $env:APPVEYOR_JOB_ID) { - return $true - } - else { - return $false - } -} - -function Test-ShouldDeploy { - if (-not ($env:ShouldDeploy -eq $true)) { - return $false - } - # only deploy master branch - if (-not ('master' -eq $env:BHBranchName)) { - return $false - } - # it cannot be a PR - if ($env:APPVEYOR_PULL_REQUEST_NUMBER) { - return $false - } - # only deploy from AppVeyor - if (-not ($env:APPVEYOR_JOB_ID)) { - return $false - } - # must be last job of AppVeyor - if (-not (Test-IsLastJob)) { - return $false - } - # Travis-CI must be finished (if used) - # TODO: (Test-TravisProgress) -and - # it cannot have a commit message that contains "skip-deploy" - if ($env:BHCommitMessage -like '*skip-deploy*') { - return $false - } - - return $true -} - -function Publish-GithubRelease { - param( - [Parameter( Mandatory )] - [ValidateNotNullOrEmpty()] - [String]$GITHUB_ACCESS_TOKEN, - [String]$ProjectOwner = "AtlassianPS", - [String]$ReleaseText, - [Object]$NextBuildVersion - ) - - Assert-True { $env:BHProjectName } "Missing AppVeyor's Repo Name" - - $body = @{ - "tag_name" = "v$NextBuildVersion" - "target_commitish" = "master" - "name" = "v$NextBuildVersion" - "body" = $ReleaseText - "draft" = $false - "prerelease" = $false - } | ConvertTo-Json - - $releaseParams = @{ - Uri = "https://api.github.com/repos/{0}/{1}/releases" -f $ProjectOwner, $env:BHProjectName - Method = 'POST' - Headers = @{ - Authorization = 'Basic ' + [Convert]::ToBase64String( - [Text.Encoding]::ASCII.GetBytes($GITHUB_ACCESS_TOKEN + ":x-oauth-basic") - ) - } - ContentType = 'application/json' - Body = $body - ErrorAction = "Stop" - } - Invoke-RestMethod @releaseParams -} - -function Publish-GithubReleaseArtifact { - param( - [Parameter( Mandatory )] - [ValidateNotNullOrEmpty()] - [String]$GITHUB_ACCESS_TOKEN, - [Uri]$Uri, - [String]$Path - ) - - $body = [System.IO.File]::ReadAllBytes($Path) - $assetParams = @{ - Uri = $Uri - Method = 'POST' - Headers = @{ - Authorization = 'Basic ' + [Convert]::ToBase64String( - [Text.Encoding]::ASCII.GetBytes($GITHUB_ACCESS_TOKEN + ":x-oauth-basic") - ) - } - ContentType = "application/zip" - Body = $body - } - Invoke-RestMethod @assetParams -} - -function Set-AppVeyorBuildNumber { - [System.Diagnostics.CodeAnalysis.SuppressMessage('PSUseShouldProcessForStateChangingFunctions', '')] - param() - - Assert-True { $env:APPVEYOR_REPO_NAME } "Is not an AppVeyor Job" - Assert-True { $env:APPVEYOR_API_TOKEN } "Is missing AppVeyor's API token" - - $separator = "-" - $headers = @{ - "Authorization" = "Bearer $env:APPVEYOR_API_TOKEN" - "Content-type" = "application/json" - } - $apiURL = "https://ci.appveyor.com/api/projects/$env:APPVEYOR_ACCOUNT_NAME/$env:APPVEYOR_PROJECT_SLUG" - $history = Invoke-RestMethod -Uri "$apiURL/history?recordsNumber=2" -Headers $headers -Method Get - if ($history.builds.Count -eq 2) { - $s = Invoke-RestMethod -Uri "$apiURL/settings" -Headers $headers -Method Get - $s.settings.nextBuildNumber = ($s.settings.nextBuildNumber - 1) - Invoke-RestMethod -Uri 'https://ci.appveyor.com/api/projects' -Headers $headers -Body ($s.settings | ConvertTo-Json -Depth 10) -Method Put - $previousVersion = $history.builds[1].version - if ($previousVersion.IndexOf("$separator") -ne "-1") { $previousVersion = $previousVersion.SubString(0, $previousVersion.IndexOf("$separator")) } - Update-AppveyorBuild -Version $previousVersion$separator$((New-Guid).ToString().SubString(0,8)) - } -} - -#region Old -# function allJobsFinished { -# param() - -# if (-not ('AppVeyor' -eq $env:BHBuildSystem)) { -# return $true -# } -# if (-not ($env:APPVEYOR_API_TOKEN)) { -# Write-Warning "Missing `$env:APPVEYOR_API_TOKEN" -# return $true -# } -# if (-not ($env:APPVEYOR_ACCOUNT_NAME)) { -# Write-Warning "Missing `$env:APPVEYOR_ACCOUNT_NAME" -# return $true -# } - -# Test-IsLastJob - -# Write-Host "[IDLE] :: waiting for other jobs to complete" - -# [datetime]$stop = ([datetime]::Now).AddMinutes($env:TimeOutMins) - -# do { -# $project = Get-AppVeyorBuild -# $continue = @() -# $project.build.jobs | Where-Object {$_.jobId -ne $env:APPVEYOR_JOB_ID} | Foreach-Object { -# $job = $_ -# switch -regex ($job.status) { -# "failed" { throw "AppVeyor's Job ($($job.jobId)) failed." } -# "(running|success)" { $continue += $true; continue } -# Default { $continue += $false; Write-Host "new state: $_.status" } -# } -# } -# if ($false -notin $continue) { return $true } -# Start-sleep 5 -# } while (([datetime]::Now) -lt $stop) - -# throw "Test jobs were not finished in $env:TimeOutMins minutes" -# } -#endregion Old - function Get-FileEncoding { <# .SYNOPSIS diff --git a/Tools/build.requirements.psd1 b/Tools/build.requirements.psd1 index ab52d49..6d4a933 100644 --- a/Tools/build.requirements.psd1 +++ b/Tools/build.requirements.psd1 @@ -1,8 +1,10 @@ @( - @{ ModuleName = "JiraPS"; RequiredVersion = "2.12.2" } - @{ ModuleName = "InvokeBuild"; RequiredVersion = "5.5.5" } - @{ ModuleName = "BuildHelpers"; RequiredVersion = "2.0.11" } - @{ ModuleName = "Pester"; RequiredVersion = "4.9.0" } - @{ ModuleName = "platyPS"; RequiredVersion = "0.14.0" } - @{ ModuleName = "PSScriptAnalyzer"; RequiredVersion = "1.18.3" } + "JiraPS" + @{ModuleName = "PowerShellGet"; ModuleVersion = "2.2.5" } + @{ ModuleName = "InvokeBuild"; RequiredVersion = "5.10.4" } + @{ ModuleName = "BuildHelpers"; RequiredVersion = "2.0.16" } + @{ ModuleName = "Configuration"; RequiredVersion = "1.3.1" } + @{ ModuleName = "Pester"; RequiredVersion = "5.5.0" } + @{ ModuleName = "platyPS"; RequiredVersion = "0.14.2" } + @{ ModuleName = "PSScriptAnalyzer"; RequiredVersion = "1.21.0" } ) diff --git a/Tools/setup.ps1 b/Tools/setup.ps1 index a92f112..da64ef6 100644 --- a/Tools/setup.ps1 +++ b/Tools/setup.ps1 @@ -1,23 +1,21 @@ -#requires -Modules @{ ModuleName='PowerShellGet'; ModuleVersion='1.6.0' } +#requires -Module PowerShellGet [CmdletBinding()] [System.Diagnostics.CodeAnalysis.SuppressMessage('PSAvoidUsingWriteHost', '')] param() # PowerShell 5.1 and bellow need the PSGallery to be intialized -if (-not ($gallery = Get-PSRepository -Name PSGallery -ErrorAction SilentlyContinue)) { +if (-not (Get-PSRepository -Name PSGallery -ErrorAction SilentlyContinue)) { Write-Host "Installing PackageProvider NuGet" $null = Install-PackageProvider -Name NuGet -Force -ErrorAction SilentlyContinue } -# Make PSGallery trusted, to aviod a confirmation in the console -if (-not ($gallery.Trusted)) { - Write-Host "Trusting PSGallery" - Set-PSRepository -Name "PSGallery" -InstallationPolicy Trusted -ErrorAction SilentlyContinue +# Update PowerShellGet if needed +if ((Get-Module PowershellGet -ListAvailable)[0].Version -lt [version]"2.2.5") { + Write-Host "Updating PowershellGet" + Install-Module PowershellGet -Scope CurrentUser -Force } -Write-Host "Installing InvokeBuild" -Install-Module InvokeBuild -Scope CurrentUser -Force - Write-Host "Installing Dependencies" -Invoke-Build -Task InstallDependencies +Import-Module "$PSScriptRoot/BuildTools.psm1" -Force +Install-Dependency diff --git a/azure-pipelines.yml b/azure-pipelines.yml deleted file mode 100644 index 56c1bff..0000000 --- a/azure-pipelines.yml +++ /dev/null @@ -1,198 +0,0 @@ - -resources: -- repo: self - clean: true - -trigger: - branches: - include: - - master - - "*" - exclude: - - refs/tag/* - -phases: -- phase: Phase_1 - displayName: Build Module - - condition: succeeded() - queue: - name: Hosted VS2017 - - steps: - - powershell: | - . ./Tools/setup.ps1 - Invoke-Build -Task ShowInfo - displayName: Setup - - - powershell: 'Invoke-Build -Task Clean, Build' - displayName: Build - - - task: PublishBuildArtifacts@1 - displayName: 'Publish Artifact: Built Module' - inputs: - PathtoPublish: Release - ArtifactName: Release - - -- phase: Phase_2 - displayName: Test Module on Windows (PSv5) - - dependsOn: Phase_1 - condition: succeeded() - queue: - name: Hosted VS2017 - - steps: - - task: DownloadBuildArtifacts@0 - displayName: 'Download Build Artifacts' - inputs: - artifactName: Release - downloadPath: '$(Build.SourcesDirectory)' - - - powershell: | - . ./Tools/setup.ps1 - Invoke-Build -Task ShowInfo - displayName: Setup - - - powershell: 'Invoke-Build -Task Test' - displayName: Test - - - task: PublishTestResults@2 - displayName: 'Publish Test Results **/Test*.xml' - inputs: - testRunner: NUnit - testResultsFiles: '**/Test*.xml' - condition: succeededOrFailed() - - -- phase: Phase_3 - displayName: Test Module on Ubuntu - - dependsOn: Phase_1 - condition: succeeded() - queue: - name: Hosted Ubuntu 1604 - - steps: - - task: DownloadBuildArtifacts@0 - displayName: 'Download Build Artifacts' - inputs: - artifactName: Release - downloadPath: '$(Build.SourcesDirectory)' - - - - powershell: | - . ./Tools/setup.ps1 - Invoke-Build -Task ShowInfo - displayName: Setup - - - powershell: 'Invoke-Build -Task Test' - displayName: Test - - - task: PublishTestResults@2 - displayName: 'Publish Test Results **/Test*.xml' - inputs: - testRunner: NUnit - testResultsFiles: '**/Test*.xml' - condition: succeededOrFailed() - - -- phase: Phase_4 - displayName: Test Module on macOS - - dependsOn: Phase_1 - condition: succeeded() - queue: - name: Hosted macOS - - steps: - - task: DownloadBuildArtifacts@0 - displayName: 'Download Build Artifacts' - inputs: - artifactName: Release - downloadPath: '$(Build.SourcesDirectory)' - - - powershell: | - . ./Tools/setup.ps1 - Invoke-Build -Task ShowInfo - displayName: Setup - - - powershell: 'Invoke-Build -Task Test' - displayName: Test - - - task: PublishTestResults@2 - displayName: 'Publish Test Results **/Test*.xml' - inputs: - testRunner: NUnit - testResultsFiles: '**/Test*.xml' - condition: succeededOrFailed() - - -# Waiting for the agent to support pwsh: -# https://github.com/Microsoft/azure-pipelines-image-generation/issues/232 -# - phase: Phase_5 -# displayName: Test Module on Windows (PSv6) - -# dependsOn: Phase_1 -# condition: succeeded() -# queue: -# name: Hosted VS2017 - -# steps: -# - task: DownloadBuildArtifacts@0 -# displayName: 'Download Build Artifacts' -# inputs: -# artifactName: Release -# downloadPath: '$(Build.SourcesDirectory)' - -# - powershell: | -# . ./Tools/setup.ps1 -# Invoke-Build -Task ShowInfo -# displayName: Setup -# pwsh: true - -# - powershell: 'Invoke-Build -Task Test' -# displayName: Test -# pwsh: true - -# - task: PublishTestResults@2 -# displayName: 'Publish Test Results **/Test-*.xml' -# inputs: -# testRunner: NUnit -# testResultsFiles: '**/Test*.xml' -# condition: succeededOrFailed() - -- phase: Phase_6 - displayName: Test Module against Cloud Server - - dependsOn: Phase_1 - condition: succeeded() - queue: - name: Hosted VS2017 - - steps: - - task: DownloadBuildArtifacts@0 - displayName: 'Download Build Artifacts' - inputs: - artifactName: Release - downloadPath: '$(Build.SourcesDirectory)' - - - powershell: | - . ./Tools/setup.ps1 - Invoke-Build -Task ShowInfo - displayName: Setup - - - powershell: 'Invoke-Build -Task Test -Tag "Integration" -ExcludeTag ""' - env: - JiraURI: JiraURI - JiraUser: JiraUser - JiraPass: JiraPass - displayName: Test - - - task: PublishTestResults@2 - displayName: 'Publish Test Results **/Test*.xml' - inputs: - testRunner: NUnit - testResultsFiles: '**/Test*.xml' - condition: succeededOrFailed()