From fd0f97029078d604aadd1ce4d57771a12ea43d7f Mon Sep 17 00:00:00 2001 From: James Brundage Date: Sat, 25 Sep 2021 18:29:19 -0700 Subject: [PATCH 01/12] Adding Steps/Job to create GitHub Releases. --- GitHub/Jobs/ReleaseModule.psd1 | 11 ++++ GitHub/Jobs/TagReleaseAndPublish.psd1 | 13 ++++ GitHub/Steps/ReleaseModule.ps1 | 86 +++++++++++++++++++++++++++ 3 files changed, 110 insertions(+) create mode 100644 GitHub/Jobs/ReleaseModule.psd1 create mode 100644 GitHub/Jobs/TagReleaseAndPublish.psd1 create mode 100644 GitHub/Steps/ReleaseModule.ps1 diff --git a/GitHub/Jobs/ReleaseModule.psd1 b/GitHub/Jobs/ReleaseModule.psd1 new file mode 100644 index 00000000..f3bbffe8 --- /dev/null +++ b/GitHub/Jobs/ReleaseModule.psd1 @@ -0,0 +1,11 @@ +@{ + "runs-on" = "ubuntu-latest" + if = '${{ success() }}' + steps = @( + @{ + name = 'Check out repository' + uses = 'actions/checkout@v2' + }, 'ReleaseModule' + ) +} + diff --git a/GitHub/Jobs/TagReleaseAndPublish.psd1 b/GitHub/Jobs/TagReleaseAndPublish.psd1 new file mode 100644 index 00000000..878c64f6 --- /dev/null +++ b/GitHub/Jobs/TagReleaseAndPublish.psd1 @@ -0,0 +1,13 @@ +@{ + "runs-on" = "ubuntu-latest" + if = '${{ success() }}' + steps = @( + @{ + name = 'Check out repository' + uses = 'actions/checkout@v2' + }, 'TagModuleVersion','ReleaseModule','PublishPowerShellGallery' + ) +} + + + diff --git a/GitHub/Steps/ReleaseModule.ps1 b/GitHub/Steps/ReleaseModule.ps1 new file mode 100644 index 00000000..568e7f45 --- /dev/null +++ b/GitHub/Steps/ReleaseModule.ps1 @@ -0,0 +1,86 @@ +param( +[string] +$ModulePath, + +# The user email associated with a git commit. +[string] +$UserEmail, + +# The user name associated with a git commit. +[string] +$UserName, + +# The tag version format (default value: 'v$(imported.Version)') +# This can expand variables. $imported will contain the imported module. +[string] +$TagVersionFormat = 'v$($imported.Version)' +) + + +$gitHubEvent = if ($env:GITHUB_EVENT_PATH) { + [IO.File]::ReadAllText($env:GITHUB_EVENT_PATH) | ConvertFrom-Json +} else { $null } + + +@" +::group::GitHubEvent +$($gitHubEvent | ConvertTo-Json -Depth 100) +::endgroup:: +"@ | Out-Host + +if (-not ($gitHubEvent.head_commit.message -match "Merge Pull Request #(?\d+)") -and + (-not $gitHubEvent.psobject.properties['inputs'])) { + "::warning::Pull Request has not merged, skipping" | Out-Host + return +} + + + +$imported = +if (-not $ModulePath) { + $orgName, $moduleName = $env:GITHUB_REPOSITORY -split "/" + Import-Module ".\$moduleName.psd1" -Force -PassThru -Global +} else { + Import-Module $modulePath -Force -PassThru -Global +} + +if (-not $imported) { return } + +$targetVersion =$ExecutionContext.InvokeCommand.ExpandString($TagVersionFormat) +$targetReleaseName = $targetVersion +$releasesURL = 'https://api.github.com/repos/${{github.repository}}/releases' +$listOfReleases = Invoke-RestMethod -Uri $releasesURL -Method Get -Headers @{ + "Accept" = "application/vnd.github.v3+json" + "Authorization" = 'Bearer ${{ secrets.GITHUB_TOKEN }}' +} + +$releaseExists = $listOfReleases | Where-Object tag_name -eq $targetVersion + +if ($releaseExists) { + "::warning::Release '$($releaseExists.Name )' Already Exists" | Out-Host + return +} + + +Invoke-RestMethod -Uri $releasesURL -Method Post -Body ( + [Ordered]@{ + owner = '${{github.owner}}' + repo = '${{github.repository}}' + tag_name = $targetVersion + name = "$($imported.Name) $targetVersion" + body = + if ($env:RELEASENOTES) { + $env:RELEASENOTES + } elseif ($imported.PrivateData.PSData.ReleaseNotes) { + $imported.PrivateData.PSData.ReleaseNotes + } else { + "$($imported.Name) $targetVersion" + } + draft = if ($env:RELEASEISDRAFT) { [bool]::Parse($env:RELEASEISDRAFT) } else { $false } + prerelease = if ($env:PRERELEASE) { [bool]::Parse($env:PRERELEASE) } else { $false } + } | ConvertTo-Json +) -Headers @{ + "Accept" = "application/vnd.github.v3+json" + "Content-type" = "application/json" + "Authorization" = 'Bearer ${{ secrets.GITHUB_TOKEN }}' +} From 0d95614f0a4b7df0d9c2946e9f156df90eb55145 Mon Sep 17 00:00:00 2001 From: James Brundage Date: Mon, 27 Sep 2021 20:29:29 -0700 Subject: [PATCH 02/12] Updating ReleaseModule step to use ${{env.GITHUB_API_URL}} --- GitHub/Steps/ReleaseModule.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/GitHub/Steps/ReleaseModule.ps1 b/GitHub/Steps/ReleaseModule.ps1 index 568e7f45..8c96693b 100644 --- a/GitHub/Steps/ReleaseModule.ps1 +++ b/GitHub/Steps/ReleaseModule.ps1 @@ -48,7 +48,7 @@ if (-not $imported) { return } $targetVersion =$ExecutionContext.InvokeCommand.ExpandString($TagVersionFormat) $targetReleaseName = $targetVersion -$releasesURL = 'https://api.github.com/repos/${{github.repository}}/releases' +$releasesURL = '${{env.GITHUB_API_URL}}/repos/${{github.repository}}/releases' $listOfReleases = Invoke-RestMethod -Uri $releasesURL -Method Get -Headers @{ "Accept" = "application/vnd.github.v3+json" "Authorization" = 'Bearer ${{ secrets.GITHUB_TOKEN }}' From 31ed5bc222ed59135645e57935cd15b31e6a98c7 Mon Sep 17 00:00:00 2001 From: James Brundage Date: Mon, 27 Sep 2021 21:20:00 -0700 Subject: [PATCH 03/12] GitHub ReleaseModule step: No longer using env.GITHUB_API_URL. Tracing URL. --- GitHub/Steps/ReleaseModule.ps1 | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/GitHub/Steps/ReleaseModule.ps1 b/GitHub/Steps/ReleaseModule.ps1 index 8c96693b..68e87f10 100644 --- a/GitHub/Steps/ReleaseModule.ps1 +++ b/GitHub/Steps/ReleaseModule.ps1 @@ -48,7 +48,8 @@ if (-not $imported) { return } $targetVersion =$ExecutionContext.InvokeCommand.ExpandString($TagVersionFormat) $targetReleaseName = $targetVersion -$releasesURL = '${{env.GITHUB_API_URL}}/repos/${{github.repository}}/releases' +$releasesURL = 'https://api.github.com/repos/${{github.repository}}/releases' +"Release URL: $releasesURL" | Out-Host $listOfReleases = Invoke-RestMethod -Uri $releasesURL -Method Get -Headers @{ "Accept" = "application/vnd.github.v3+json" "Authorization" = 'Bearer ${{ secrets.GITHUB_TOKEN }}' From 6fd56d5f008db24613cce7092db091653393d3fb Mon Sep 17 00:00:00 2001 From: James Brundage Date: Mon, 27 Sep 2021 22:07:35 -0700 Subject: [PATCH 04/12] Removing old workflow and adding test and publish workflow --- .github/workflows/TestAndPublish.yml | 470 ++++++++++++++++++++++++++ .github/workflows/UpdateModuleTag.yml | 92 ----- 2 files changed, 470 insertions(+), 92 deletions(-) create mode 100644 .github/workflows/TestAndPublish.yml delete mode 100644 .github/workflows/UpdateModuleTag.yml diff --git a/.github/workflows/TestAndPublish.yml b/.github/workflows/TestAndPublish.yml new file mode 100644 index 00000000..8622c818 --- /dev/null +++ b/.github/workflows/TestAndPublish.yml @@ -0,0 +1,470 @@ + +name: Analyze, Test, Tag, and Publish +on: + push: + pull_request: + workflow_dispatch: +jobs: + PowerShellStaticAnalysis: + runs-on: ubuntu-latest + steps: + - name: InstallScriptCop + id: InstallScriptCop + shell: pwsh + run: | + [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 + Install-Module -Name ScriptCop -Repository PSGallery -Force -Scope CurrentUser + Import-Module ScriptCop -Force -PassThru + - name: InstallPSScriptAnalyzer + id: InstallPSScriptAnalyzer + shell: pwsh + run: | + [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 + Install-Module -Name PSScriptAnalyzer -Repository PSGallery -Force -Scope CurrentUser + Import-Module PSScriptAnalyzer -Force -PassThru + - name: InstallPSDevOps + id: InstallPSDevOps + shell: pwsh + run: | + [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 + Install-Module -Name PSDevOps -Repository PSGallery -Force -Scope CurrentUser + Import-Module PSDevOps -Force -PassThru + - name: Check out repository + uses: actions/checkout@v2 + - name: RunScriptCop + id: RunScriptCop + shell: pwsh + run: | + $Parameters = @{} + $Parameters.ModulePath = ${env:ModulePath} + foreach ($k in @($parameters.Keys)) { + if ([String]::IsNullOrEmpty($parameters[$k])) { + $parameters.Remove($k) + } + } + Write-Host "::debug:: RunScriptCop $(@(foreach ($p in $Parameters.GetEnumerator()) {'-' + $p.Key + ' ' + $p.Value}) -join ' ')" + & {param([string]$ModulePath) + Import-Module ScriptCop, PSDevOps -PassThru | Out-Host + + if (-not $ModulePath) { + $orgName, $moduleName = $env:GITHUB_REPOSITORY -split "/" + $ModulePath = ".\$moduleName.psd1" + } + if ($ModulePath -like '*PSDevOps*') { + Remove-Module PSDeVOps # If running ScriptCop on PSDeVOps, we need to remove the global module first. + } + + + $importedModule =Import-Module $ModulePath -Force -PassThru + + $importedModule | Out-Host + + $importedModule | + Test-Command | + Tee-Object -Variable scriptCopIssues | + Out-Host + + foreach ($issue in $scriptCopIssues) { + Write-GitHubWarning -Message "$($issue.ItemWithProblem): $($issue.Problem)" + } + } @Parameters + - name: RunPSScriptAnalyzer + id: RunPSScriptAnalyzer + shell: pwsh + run: | + Import-Module PSScriptAnalyzer, PSDevOps -PassThru | Out-Host + $invokeScriptAnalyzerSplat = @{Path='.\'} + if ($ENV:PSScriptAnalyzer_Recurse) { + $invokeScriptAnalyzerSplat.Recurse = $true + } + $result = Invoke-ScriptAnalyzer @invokeScriptAnalyzerSplat + + foreach ($r in $result) { + if ('information', 'warning' -contains $r.Severity) { + Write-GitHubWarning -Message "$($r.RuleName) : $($r.Message)" -SourcePath $r.ScriptPath -LineNumber $r.Line -ColumnNumber $r.Column + } + elseif ($r.Severity -eq 'Error') { + Write-GitHubError -Message "$($r.RuleName) : $($r.Message)" -SourcePath $r.ScriptPath -LineNumber $r.Line -ColumnNumber $r.Column + } + } + TestPowerShellOnLinux: + runs-on: ubuntu-latest + steps: + - name: InstallPester + id: InstallPester + shell: pwsh + run: | + $Parameters = @{} + $Parameters.PesterMaxVersion = ${env:PesterMaxVersion} + foreach ($k in @($parameters.Keys)) { + if ([String]::IsNullOrEmpty($parameters[$k])) { + $parameters.Remove($k) + } + } + Write-Host "::debug:: InstallPester $(@(foreach ($p in $Parameters.GetEnumerator()) {'-' + $p.Key + ' ' + $p.Value}) -join ' ')" + & {<# + .Synopsis + Installs Pester + .Description + Installs Pester + #> + param( + # The maximum pester version. Defaults to 4.99.99. + [string] + $PesterMaxVersion = '4.99.99' + ) + [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 + Install-Module -Name Pester -Repository PSGallery -Force -Scope CurrentUser -MaximumVersion $PesterMaxVersion -SkipPublisherCheck -AllowClobber + Import-Module Pester -Force -PassThru -MaximumVersion $PesterMaxVersion} @Parameters + - name: Check out repository + uses: actions/checkout@v2 + - name: RunPester + id: RunPester + shell: pwsh + run: | + $Parameters = @{} + $Parameters.ModulePath = ${env:ModulePath} + $Parameters.PesterMaxVersion = ${env:PesterMaxVersion} + foreach ($k in @($parameters.Keys)) { + if ([String]::IsNullOrEmpty($parameters[$k])) { + $parameters.Remove($k) + } + } + Write-Host "::debug:: RunPester $(@(foreach ($p in $Parameters.GetEnumerator()) {'-' + $p.Key + ' ' + $p.Value}) -join ' ')" + & {<# + .Synopsis + Runs Pester + .Description + Runs Pester tests after importing a PowerShell module + #> + param( + # The module path. If not provided, will default to the second half of the repository ID. + [string] + $ModulePath, + # The Pester max version. By default, this is pinned to 4.99.99. + [string] + $PesterMaxVersion = '4.99.99' + ) + + $global:ErrorActionPreference = 'continue' + $global:ProgressPreference = 'silentlycontinue' + + $orgName, $moduleName = $env:GITHUB_REPOSITORY -split "/" + if (-not $ModulePath) { $ModulePath = ".\$moduleName.psd1" } + $importedPester = Import-Module Pester -Force -PassThru -MaximumVersion $PesterMaxVersion + $importedModule = Import-Module $ModulePath -Force -PassThru + $importedPester, $importedModule | Out-Host + + + + $result = + Invoke-Pester -PassThru -Verbose -OutputFile ".\$moduleName.TestResults.xml" -OutputFormat NUnitXml ` + -CodeCoverage "$($importedModule | Split-Path)\*-*.ps1" -CodeCoverageOutputFile ".\$moduleName.Coverage.xml" + + "::set-output name=TotalCount::$($result.TotalCount)", + "::set-output name=PassedCount::$($result.PassedCount)", + "::set-output name=FailedCount::$($result.FailedCount)" | Out-Host + if ($result.FailedCount -gt 0) { + "::debug:: $($result.FailedCount) tests failed" + foreach ($r in $result.TestResult) { + if (-not $r.Passed) { + "::error::$($r.describe, $r.context, $r.name -join ' ') $($r.FailureMessage)" + } + } + throw "::error:: $($result.FailedCount) tests failed" + } + } @Parameters + - name: PublishTestResults + uses: actions/upload-artifact@v2 + with: + name: PesterResults + path: '**.TestResults.xml' + if: ${{always()}} + TagReleaseAndPublish: + runs-on: ubuntu-latest + if: ${{ success() }} + steps: + - name: Check out repository + uses: actions/checkout@v2 + - name: TagModuleVersion + id: TagModuleVersion + shell: pwsh + run: | + $Parameters = @{} + $Parameters.ModulePath = ${env:ModulePath} + $Parameters.UserEmail = ${env:UserEmail} + $Parameters.UserName = ${env:UserName} + $Parameters.TagVersionFormat = ${env:TagVersionFormat} + $Parameters.TagAnnotationFormat = ${env:TagAnnotationFormat} + foreach ($k in @($parameters.Keys)) { + if ([String]::IsNullOrEmpty($parameters[$k])) { + $parameters.Remove($k) + } + } + Write-Host "::debug:: TagModuleVersion $(@(foreach ($p in $Parameters.GetEnumerator()) {'-' + $p.Key + ' ' + $p.Value}) -join ' ')" + & {param( + [string] + $ModulePath, + + # The user email associated with a git commit. + [string] + $UserEmail, + + # The user name associated with a git commit. + [string] + $UserName, + + # The tag version format (default value: 'v$(imported.Version)') + # This can expand variables. $imported will contain the imported module. + [string] + $TagVersionFormat = 'v$($imported.Version)', + + # The tag version format (default value: '$($imported.Name) $(imported.Version)') + # This can expand variables. $imported will contain the imported module. + [string] + $TagAnnotationFormat = '$($imported.Name) $($imported.Version)' + ) + + + $gitHubEvent = if ($env:GITHUB_EVENT_PATH) { + [IO.File]::ReadAllText($env:GITHUB_EVENT_PATH) | ConvertFrom-Json + } else { $null } + + + @" + ::group::GitHubEvent + $($gitHubEvent | ConvertTo-Json -Depth 100) + ::endgroup:: + "@ | Out-Host + + if (-not ($gitHubEvent.head_commit.message -match "Merge Pull Request #(?\d+)") -and + (-not $gitHubEvent.psobject.properties['inputs'])) { + "::warning::Pull Request has not merged, skipping" | Out-Host + return + } + + + + $imported = + if (-not $ModulePath) { + $orgName, $moduleName = $env:GITHUB_REPOSITORY -split "/" + Import-Module ".\$moduleName.psd1" -Force -PassThru -Global + } else { + Import-Module $modulePath -Force -PassThru -Global + } + + if (-not $imported) { return } + + $targetVersion =$ExecutionContext.InvokeCommand.ExpandString($TagVersionFormat) + $existingTags = git tag --list + + @" + Target Version: $targetVersion + + Existing Tags: + $($existingTags -join [Environment]::NewLine) + "@ | Out-Host + + $versionTagExists = $existingTags | Where-Object { $_ -match $targetVersion } + + if ($versionTagExists) { + "::warning::Version $($versionTagExists)" + return + } + + if (-not $UserName) { $UserName = $env:GITHUB_ACTOR } + if (-not $UserEmail) { $UserEmail = "$UserName@github.com" } + git config --global user.email $UserEmail + git config --global user.name $UserName + + git tag -a $targetVersion -m $ExecutionContext.InvokeCommand.ExpandString($TagAnnotationFormat) + git push origin --tags + + if ($env:GITHUB_ACTOR) { + exit 0 + }} @Parameters + - name: ReleaseModule + id: ReleaseModule + shell: pwsh + run: | + $Parameters = @{} + $Parameters.ModulePath = ${env:ModulePath} + $Parameters.UserEmail = ${env:UserEmail} + $Parameters.UserName = ${env:UserName} + $Parameters.TagVersionFormat = ${env:TagVersionFormat} + foreach ($k in @($parameters.Keys)) { + if ([String]::IsNullOrEmpty($parameters[$k])) { + $parameters.Remove($k) + } + } + Write-Host "::debug:: ReleaseModule $(@(foreach ($p in $Parameters.GetEnumerator()) {'-' + $p.Key + ' ' + $p.Value}) -join ' ')" + & {param( + [string] + $ModulePath, + + # The user email associated with a git commit. + [string] + $UserEmail, + + # The user name associated with a git commit. + [string] + $UserName, + + # The tag version format (default value: 'v$(imported.Version)') + # This can expand variables. $imported will contain the imported module. + [string] + $TagVersionFormat = 'v$($imported.Version)' + ) + + + $gitHubEvent = if ($env:GITHUB_EVENT_PATH) { + [IO.File]::ReadAllText($env:GITHUB_EVENT_PATH) | ConvertFrom-Json + } else { $null } + + + @" + ::group::GitHubEvent + $($gitHubEvent | ConvertTo-Json -Depth 100) + ::endgroup:: + "@ | Out-Host + + if (-not ($gitHubEvent.head_commit.message -match "Merge Pull Request #(?\d+)") -and + (-not $gitHubEvent.psobject.properties['inputs'])) { + "::warning::Pull Request has not merged, skipping" | Out-Host + return + } + + + + $imported = + if (-not $ModulePath) { + $orgName, $moduleName = $env:GITHUB_REPOSITORY -split "/" + Import-Module ".\$moduleName.psd1" -Force -PassThru -Global + } else { + Import-Module $modulePath -Force -PassThru -Global + } + + if (-not $imported) { return } + + $targetVersion =$ExecutionContext.InvokeCommand.ExpandString($TagVersionFormat) + $targetReleaseName = $targetVersion + $releasesURL = 'https://api.github.com/repos/${{github.repository}}/releases' + "Release URL: $releasesURL" | Out-Host + $listOfReleases = Invoke-RestMethod -Uri $releasesURL -Method Get -Headers @{ + "Accept" = "application/vnd.github.v3+json" + "Authorization" = 'Bearer ${{ secrets.GITHUB_TOKEN }}' + } + + $releaseExists = $listOfReleases | Where-Object tag_name -eq $targetVersion + + if ($releaseExists) { + "::warning::Release '$($releaseExists.Name )' Already Exists" | Out-Host + return + } + + + Invoke-RestMethod -Uri $releasesURL -Method Post -Body ( + [Ordered]@{ + owner = '${{github.owner}}' + repo = '${{github.repository}}' + tag_name = $targetVersion + name = "$($imported.Name) $targetVersion" + body = + if ($env:RELEASENOTES) { + $env:RELEASENOTES + } elseif ($imported.PrivateData.PSData.ReleaseNotes) { + $imported.PrivateData.PSData.ReleaseNotes + } else { + "$($imported.Name) $targetVersion" + } + draft = if ($env:RELEASEISDRAFT) { [bool]::Parse($env:RELEASEISDRAFT) } else { $false } + prerelease = if ($env:PRERELEASE) { [bool]::Parse($env:PRERELEASE) } else { $false } + } | ConvertTo-Json + ) -Headers @{ + "Accept" = "application/vnd.github.v3+json" + "Content-type" = "application/json" + "Authorization" = 'Bearer ${{ secrets.GITHUB_TOKEN }}' + } + } @Parameters + - name: PublishPowerShellGallery + id: PublishPowerShellGallery + shell: pwsh + run: | + $Parameters = @{} + $Parameters.ModulePath = ${env:ModulePath} + foreach ($k in @($parameters.Keys)) { + if ([String]::IsNullOrEmpty($parameters[$k])) { + $parameters.Remove($k) + } + } + Write-Host "::debug:: PublishPowerShellGallery $(@(foreach ($p in $Parameters.GetEnumerator()) {'-' + $p.Key + ' ' + $p.Value}) -join ' ')" + & {param( + [string] + $ModulePath + ) + $gitHubEvent = if ($env:GITHUB_EVENT_PATH) { + [IO.File]::ReadAllText($env:GITHUB_EVENT_PATH) | ConvertFrom-Json + } else { $null } + + + @" + ::group::GitHubEvent + $($gitHubEvent | ConvertTo-Json -Depth 100) + ::endgroup:: + "@ | Out-Host + + if (-not ($gitHubEvent.head_commit.message -match "Merge Pull Request #(?\d+)") -and + (-not $gitHubEvent.psobject.properties['inputs'])) { + "::warning::Pull Request has not merged, skipping" | Out-Host + return + } + + + $imported = + if (-not $ModulePath) { + $orgName, $moduleName = $env:GITHUB_REPOSITORY -split "/" + Import-Module ".\$moduleName.psd1" -Force -PassThru -Global + } else { + Import-Module $modulePath -Force -PassThru -Global + } + + if (-not $imported) { return } + + $foundModule = try { Find-Module -Name $imported.Name -ErrorAction SilentlyContinue } catch {} + + if ($foundModule -and $foundModule.Version -ge $imported.Version) { + "::warning::Gallery Version of $moduleName is more recent ($($foundModule.Version) >= $($imported.Version))" | Out-Host + } else { + + $gk = '${{secrets.GALLERYKEY}}' + + $rn = Get-Random + $moduleTempFolder = Join-Path $pwd "$rn" + $moduleTempPath = Join-Path $moduleTempFolder $moduleName + New-Item -ItemType Directory -Path $moduleTempPath -Force | Out-Host + + Write-Host "Staging Directory: $ModuleTempPath" + + $imported | Split-Path | + Get-ChildItem -Force | + Where-Object Name -NE $rn | + Copy-Item -Destination $moduleTempPath -Recurse + + $moduleGitPath = Join-Path $moduleTempPath '.git' + Write-Host "Removing .git directory" + if (Test-Path $moduleGitPath) { + Remove-Item -Recurse -Force $moduleGitPath + } + Write-Host "Module Files:" + Get-ChildItem $moduleTempPath -Recurse + Write-Host "Publishing $moduleName [$($imported.Version)] to Gallery" + Publish-Module -Path $moduleTempPath -NuGetApiKey $gk + if ($?) { + Write-Host "Published to Gallery" + } else { + Write-Host "Gallery Publish Failed" + exit 1 + } + } + } @Parameters + diff --git a/.github/workflows/UpdateModuleTag.yml b/.github/workflows/UpdateModuleTag.yml deleted file mode 100644 index d921303b..00000000 --- a/.github/workflows/UpdateModuleTag.yml +++ /dev/null @@ -1,92 +0,0 @@ -name: UpdateModuleTag -on: - workflow_dispatch: - pull_request: - branches: - - main - - master - paths-ignore: - - 'docs/**' - - '*.help.txt' - - '*.md' - -jobs: - UpdateModuleTag: - if: ${{github.event.action == 'closed' && github.event.merged == true}} - runs-on: ubuntu-latest - steps: - - name: Check out repository - uses: actions/checkout@v2 - - name: TagModuleVersion - id: TagModuleVersion - shell: pwsh - run: | - $Parameters = @{} - $Parameters.ModulePath = ${env:ModulePath} - $Parameters.UserEmail = ${env:UserEmail} - $Parameters.UserName = ${env:UserName} - $Parameters.TagVersionFormat = ${env:TagVersionFormat} - $Parameters.TagAnnotationFormat = ${env:TagAnnotationFormat} - foreach ($k in @($parameters.Keys)) { - if ([String]::IsNullOrEmpty($parameters[$k])) { - $parameters.Remove($k) - } - } - Write-Host "::debug:: TagModuleVersion $(@(foreach ($p in $Parameters.GetEnumerator()) {'-' + $p.Key + ' ' + $p.Value}) -join ' ')" - & {param( - [string] - $ModulePath, - - # The user email associated with a git commit. - [string] - $UserEmail, - - # The user name associated with a git commit. - [string] - $UserName, - - # The tag version format (default value: 'v$(imported.Version)') - # This can expand variables. $imported will contain the imported module. - [string] - $TagVersionFormat = 'v$($imported.Version)', - - # The tag version format (default value: '$($imported.Name) $(imported.Version)') - # This can expand variables. $imported will contain the imported module. - [string] - $TagAnnotationFormat = '$($imported.Name) $($imported.Version)' - ) - - $imported = - if (-not $ModulePath) { - $orgName, $moduleName = $env:BUILD_REPOSITORY_ID -split "/" - Import-Module ".\$moduleName.psd1" -Force -PassThru -Global - } else { - Import-Module $modulePath -Force -PassThru -Global - } - - if (-not $imported) { return } - - $targetVersion =$ExecutionContext.InvokeCommand.ExpandString($TagVersionFormat) - - $versionTagExists = git tag --list | Where-Object { $_ -eq $targetVersion } - - if ($versionTagExists) { - "::warning::Version $($versionTagExists)" - return - } - - if (-not $UserName) { $UserName = $env:GITHUB_ACTOR } - if (-not $UserEmail) { $UserEmail = "$UserName@github.com" } - git config --global user.email $UserEmail - git config --global user.name $UserName - - git tag -a $targetVersion -m $ExecutionContext.InvokeCommand.ExpandString($TagAnnotationFormat) - git push --tags - - if ($env:GITHUB_ACTOR) { - exit 0 - } - - - } @Parameters - From 390a4596a8c495d562b5a7b93138764143924762 Mon Sep 17 00:00:00 2001 From: James Brundage Date: Mon, 27 Sep 2021 22:10:08 -0700 Subject: [PATCH 05/12] Adding Workflow Defintion file --- PSDevOps.GitHubWorkflow.psdevops.ps1 | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 PSDevOps.GitHubWorkflow.psdevops.ps1 diff --git a/PSDevOps.GitHubWorkflow.psdevops.ps1 b/PSDevOps.GitHubWorkflow.psdevops.ps1 new file mode 100644 index 00000000..0e228d46 --- /dev/null +++ b/PSDevOps.GitHubWorkflow.psdevops.ps1 @@ -0,0 +1,3 @@ +#requires -Module PSDevOps +New-GitHubWorkflow -Name "Analyze, Test, Tag, and Publish" -On Push, PullRequest, Demand -Job PowerShellStaticAnalysis, TestPowerShellOnLinux, TagReleaseAndPublish | + Set-Content .\.github\workflows\TestAndPublish.yml -Encoding UTF8 -PassThru \ No newline at end of file From 53b4afa274de7803b0eb84a73ac94712251ca022 Mon Sep 17 00:00:00 2001 From: James Brundage Date: Mon, 27 Sep 2021 22:29:37 -0700 Subject: [PATCH 06/12] Updating workflow (providing PAT and skipping coverage) --- .github/workflows/TestAndPublish.yml | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/.github/workflows/TestAndPublish.yml b/.github/workflows/TestAndPublish.yml index 8622c818..f0737c2a 100644 --- a/.github/workflows/TestAndPublish.yml +++ b/.github/workflows/TestAndPublish.yml @@ -125,6 +125,8 @@ jobs: $Parameters = @{} $Parameters.ModulePath = ${env:ModulePath} $Parameters.PesterMaxVersion = ${env:PesterMaxVersion} + $Parameters.NoCoverage = ${env:NoCoverage} + $Parameters.NoCoverage = $parameters.NoCoverage -match 'true'; foreach ($k in @($parameters.Keys)) { if ([String]::IsNullOrEmpty($parameters[$k])) { $parameters.Remove($k) @@ -143,7 +145,11 @@ jobs: $ModulePath, # The Pester max version. By default, this is pinned to 4.99.99. [string] - $PesterMaxVersion = '4.99.99' + $PesterMaxVersion = '4.99.99', + + # If set, will not collect code coverage. + [switch] + $NoCoverage ) $global:ErrorActionPreference = 'continue' @@ -155,11 +161,18 @@ jobs: $importedModule = Import-Module $ModulePath -Force -PassThru $importedPester, $importedModule | Out-Host + $codeCoverageParameters = @{ + CodeCoverage = "$($importedModule | Split-Path)\*-*.ps1" + CodeCoverageOutputFile = ".\$moduleName.Coverage.xml" + } + + if ($NoCoverage) { + $codeCoverageParameters = @{} + } $result = - Invoke-Pester -PassThru -Verbose -OutputFile ".\$moduleName.TestResults.xml" -OutputFormat NUnitXml ` - -CodeCoverage "$($importedModule | Split-Path)\*-*.ps1" -CodeCoverageOutputFile ".\$moduleName.Coverage.xml" + Invoke-Pester -PassThru -Verbose -OutputFile ".\$moduleName.TestResults.xml" -OutputFormat NUnitXml @codeCoverageParameters "::set-output name=TotalCount::$($result.TotalCount)", "::set-output name=PassedCount::$($result.PassedCount)", @@ -467,4 +480,6 @@ jobs: } } } @Parameters - +env: + SYSTEM_ACCESSTOKEN: ${{ secrets.AZUREDEVOPSPAT }} + NoCoverage: true From 17fa9283e9676d8a013a62b7e1a93b5055e34feb Mon Sep 17 00:00:00 2001 From: James Brundage Date: Mon, 27 Sep 2021 22:32:37 -0700 Subject: [PATCH 07/12] Updating Module Version [0.5.5] and Release Notes --- PSDevOps.psd1 | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) diff --git a/PSDevOps.psd1 b/PSDevOps.psd1 index c10a28a3..6d354561 100644 --- a/PSDevOps.psd1 +++ b/PSDevOps.psd1 @@ -1,5 +1,5 @@ @{ - ModuleVersion = '0.5.4.2' + ModuleVersion = '0.5.5' RootModule = 'PSDevOps.psm1' Description = 'PowerShell Tools for DevOps' Guid = 'e6b56c5f-41ac-4ba4-8b88-2c063f683176' @@ -9,6 +9,10 @@ ProjectURI = 'https://github.com/StartAutomating/PSDevOps' LicenseURI = 'https://github.com/StartAutomating/PSDevOps/blob/master/LICENSE' ReleaseNotes = @' +0.5.5: +--- +* Azure DevOps: Adding support for Shared Queries (Fixes #117) +* GitHub Workflows: Adding Job/Step definitions to Release Module 0.5.4.2: --- * Adding Register-ADOArtifactFeed (Fixes #118) @@ -94,17 +98,6 @@ ** PSDevOps now includes a file to generate it's own build ** PublishTest/CodeCoverage Results steps will always() run ** Convert-BuildStep will add a .Name to each script step. -0.4.8 ---- -* Improved Tracing -** New Commands: Write-ADOOutput, Trace-ADOCommand/GitHubCommand -** Renaming Command / Adding Parameters: Set-ADOVariable -> Write-ADOVariable. Added -IsOutput & -IsReadOnly. -** Adding Trace-GitHubCommand/ADOCommand -** Improved logging of parameters in Convert-BuildStep -* New Functionality in Azure DevOps: -** Get-ADOProject now has -TestRun, -TestPlan, -Release, and -PendingApproval (and better progress bars) -** Get-ADOWorkItemType now has -Field -** Commands for Picklists: Add/Get/Remove/Update-ADOPicklist '@ } Colors = @{ From f61221bb14d032c265665d045b5fdc63804553e5 Mon Sep 17 00:00:00 2001 From: James Brundage Date: Mon, 27 Sep 2021 22:33:28 -0700 Subject: [PATCH 08/12] GitHub RunPester Step: Adding -NoCoverage --- GitHub/Steps/RunPester.ps1 | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/GitHub/Steps/RunPester.ps1 b/GitHub/Steps/RunPester.ps1 index 315dfebb..68bcdeeb 100644 --- a/GitHub/Steps/RunPester.ps1 +++ b/GitHub/Steps/RunPester.ps1 @@ -10,7 +10,11 @@ param( $ModulePath, # The Pester max version. By default, this is pinned to 4.99.99. [string] -$PesterMaxVersion = '4.99.99' +$PesterMaxVersion = '4.99.99', + +# If set, will not collect code coverage. +[switch] +$NoCoverage ) $global:ErrorActionPreference = 'continue' @@ -22,11 +26,18 @@ $importedPester = Import-Module Pester -Force -PassThru -MaximumVersion $PesterM $importedModule = Import-Module $ModulePath -Force -PassThru $importedPester, $importedModule | Out-Host +$codeCoverageParameters = @{ +CodeCoverage = "$($importedModule | Split-Path)\*-*.ps1" +CodeCoverageOutputFile = ".\$moduleName.Coverage.xml" +} + +if ($NoCoverage) { + $codeCoverageParameters = @{} +} $result = - Invoke-Pester -PassThru -Verbose -OutputFile ".\$moduleName.TestResults.xml" -OutputFormat NUnitXml ` - -CodeCoverage "$($importedModule | Split-Path)\*-*.ps1" -CodeCoverageOutputFile ".\$moduleName.Coverage.xml" + Invoke-Pester -PassThru -Verbose -OutputFile ".\$moduleName.TestResults.xml" -OutputFormat NUnitXml @codeCoverageParameters "::set-output name=TotalCount::$($result.TotalCount)", "::set-output name=PassedCount::$($result.PassedCount)", From ebf2cc50dbab3dfe688afb7e602de8d191b4d42e Mon Sep 17 00:00:00 2001 From: James Brundage Date: Mon, 27 Sep 2021 22:35:21 -0700 Subject: [PATCH 09/12] Updating Workflow Defintion File --- PSDevOps.GitHubWorkflow.psdevops.ps1 | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/PSDevOps.GitHubWorkflow.psdevops.ps1 b/PSDevOps.GitHubWorkflow.psdevops.ps1 index 0e228d46..5ecbe34b 100644 --- a/PSDevOps.GitHubWorkflow.psdevops.ps1 +++ b/PSDevOps.GitHubWorkflow.psdevops.ps1 @@ -1,3 +1,6 @@ #requires -Module PSDevOps -New-GitHubWorkflow -Name "Analyze, Test, Tag, and Publish" -On Push, PullRequest, Demand -Job PowerShellStaticAnalysis, TestPowerShellOnLinux, TagReleaseAndPublish | +New-GitHubWorkflow -Name "Analyze, Test, Tag, and Publish" -On Push, PullRequest, Demand -Job PowerShellStaticAnalysis, TestPowerShellOnLinux, TagReleaseAndPublish -Environment @{ + SYSTEM_ACCESSTOKEN = '${{ secrets.AZUREDEVOPSPAT }}' + NoCoverage = $true +}| Set-Content .\.github\workflows\TestAndPublish.yml -Encoding UTF8 -PassThru \ No newline at end of file From a0bb3d45776635bdcfcea65182b0fbd53e3a321d Mon Sep 17 00:00:00 2001 From: James Brundage Date: Mon, 27 Sep 2021 22:35:33 -0700 Subject: [PATCH 10/12] Updating Module Version [0.5.5] and Release Notes --- PSDevOps.psd1 | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/PSDevOps.psd1 b/PSDevOps.psd1 index 6d354561..98f59e1f 100644 --- a/PSDevOps.psd1 +++ b/PSDevOps.psd1 @@ -12,7 +12,11 @@ 0.5.5: --- * Azure DevOps: Adding support for Shared Queries (Fixes #117) -* GitHub Workflows: Adding Job/Step definitions to Release Module +* GitHub Workflows: +** Adding Job/Step definitions to Release Module +** Adding -NoCoverage to RunPester Step +** Creating Example workflow that publishes PSDevOps. + 0.5.4.2: --- * Adding Register-ADOArtifactFeed (Fixes #118) From 6cb310641cf21e1063ef9d791abfc85cd7768dfd Mon Sep 17 00:00:00 2001 From: James Brundage Date: Mon, 27 Sep 2021 22:45:54 -0700 Subject: [PATCH 11/12] Updating Module Version [0.5.5] and Release Notes --- PSDevOps.psd1 | 3 +++ 1 file changed, 3 insertions(+) diff --git a/PSDevOps.psd1 b/PSDevOps.psd1 index 98f59e1f..bc6be2cb 100644 --- a/PSDevOps.psd1 +++ b/PSDevOps.psd1 @@ -12,6 +12,9 @@ 0.5.5: --- * Azure DevOps: Adding support for Shared Queries (Fixes #117) +** Get-ADOWorkItem -SharedQuery can get shared queries +** New-ADOWorkItem -WIQL will create shared queries. -FolderName will create folders. +** Remove-ADOWorkItem -QueryID can remove a shared query by ID * GitHub Workflows: ** Adding Job/Step definitions to Release Module ** Adding -NoCoverage to RunPester Step From 2d018d302f08e1ff8cfbf5465dc82f3e085d5902 Mon Sep 17 00:00:00 2001 From: James Brundage Date: Mon, 27 Sep 2021 22:49:52 -0700 Subject: [PATCH 12/12] Updating workflow and source files (being more clear about what is being skipped) --- .github/workflows/TestAndPublish.yml | 6 +++--- GitHub/Steps/PublishPowerShellGallery.ps1 | 2 +- GitHub/Steps/ReleaseModule.ps1 | 2 +- GitHub/Steps/TagModuleVersion.ps1 | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/TestAndPublish.yml b/.github/workflows/TestAndPublish.yml index f0737c2a..fc29aa1e 100644 --- a/.github/workflows/TestAndPublish.yml +++ b/.github/workflows/TestAndPublish.yml @@ -252,7 +252,7 @@ jobs: if (-not ($gitHubEvent.head_commit.message -match "Merge Pull Request #(?\d+)") -and (-not $gitHubEvent.psobject.properties['inputs'])) { - "::warning::Pull Request has not merged, skipping" | Out-Host + "::warning::Pull Request has not merged, skipping Tagging" | Out-Host return } @@ -343,7 +343,7 @@ jobs: if (-not ($gitHubEvent.head_commit.message -match "Merge Pull Request #(?\d+)") -and (-not $gitHubEvent.psobject.properties['inputs'])) { - "::warning::Pull Request has not merged, skipping" | Out-Host + "::warning::Pull Request has not merged, skipping GitHub release" | Out-Host return } @@ -428,7 +428,7 @@ jobs: if (-not ($gitHubEvent.head_commit.message -match "Merge Pull Request #(?\d+)") -and (-not $gitHubEvent.psobject.properties['inputs'])) { - "::warning::Pull Request has not merged, skipping" | Out-Host + "::warning::Pull Request has not merged, skipping Gallery Publish" | Out-Host return } diff --git a/GitHub/Steps/PublishPowerShellGallery.ps1 b/GitHub/Steps/PublishPowerShellGallery.ps1 index f70f877b..44c587da 100644 --- a/GitHub/Steps/PublishPowerShellGallery.ps1 +++ b/GitHub/Steps/PublishPowerShellGallery.ps1 @@ -15,7 +15,7 @@ $($gitHubEvent | ConvertTo-Json -Depth 100) if (-not ($gitHubEvent.head_commit.message -match "Merge Pull Request #(?\d+)") -and (-not $gitHubEvent.psobject.properties['inputs'])) { - "::warning::Pull Request has not merged, skipping" | Out-Host + "::warning::Pull Request has not merged, skipping Gallery Publish" | Out-Host return } diff --git a/GitHub/Steps/ReleaseModule.ps1 b/GitHub/Steps/ReleaseModule.ps1 index 68e87f10..b34b606f 100644 --- a/GitHub/Steps/ReleaseModule.ps1 +++ b/GitHub/Steps/ReleaseModule.ps1 @@ -30,7 +30,7 @@ $($gitHubEvent | ConvertTo-Json -Depth 100) if (-not ($gitHubEvent.head_commit.message -match "Merge Pull Request #(?\d+)") -and (-not $gitHubEvent.psobject.properties['inputs'])) { - "::warning::Pull Request has not merged, skipping" | Out-Host + "::warning::Pull Request has not merged, skipping GitHub release" | Out-Host return } diff --git a/GitHub/Steps/TagModuleVersion.ps1 b/GitHub/Steps/TagModuleVersion.ps1 index f60a41ad..8b998314 100644 --- a/GitHub/Steps/TagModuleVersion.ps1 +++ b/GitHub/Steps/TagModuleVersion.ps1 @@ -35,7 +35,7 @@ $($gitHubEvent | ConvertTo-Json -Depth 100) if (-not ($gitHubEvent.head_commit.message -match "Merge Pull Request #(?\d+)") -and (-not $gitHubEvent.psobject.properties['inputs'])) { - "::warning::Pull Request has not merged, skipping" | Out-Host + "::warning::Pull Request has not merged, skipping Tagging" | Out-Host return }