├── .templates ├── default │ ├── milestone.sbn │ ├── issue-note.sbn │ ├── issues.sbn │ ├── issue-details.sbn │ ├── index.sbn │ ├── create │ │ └── footer.sbn │ └── release-info.sbn ├── contributors │ ├── milestone.sbn │ ├── issues.sbn │ ├── issue-details.sbn │ ├── contributor-details.sbn │ ├── contributors.sbn │ ├── create │ │ └── footer.sbn │ ├── index.sbn │ ├── release-info.sbn │ └── issue-note.sbn └── no │ └── issues │ ├── milestone.sbn │ ├── issues.sbn │ ├── release-info.sbn │ ├── index.sbn │ └── create │ └── footer.sbn ├── .gitignore ├── GitVersion.yml ├── src ├── Plugins │ ├── Report │ │ ├── r_er.png │ │ ├── r_ok.png │ │ ├── text.ps1 │ │ ├── markdown_funcs.ps1 │ │ └── markdown.ps1 │ ├── Report.ps1 │ ├── Snippet.ps1 │ ├── Gitter.ps1 │ ├── Mail.ps1 │ ├── RunInfo.ps1 │ ├── Gist.ps1 │ ├── History.ps1 │ ├── PullRequest.ps1 │ ├── GitLab.ps1 │ ├── Git.ps1 │ └── GitReleases.ps1 ├── Private │ ├── is_url.ps1 │ ├── is_version.ps1 │ ├── check_url.ps1 │ ├── request.ps1 │ ├── AUPackage.ps1 │ └── AUVersion.ps1 ├── Chocolatey-AU.psm1 ├── Public │ ├── Get-RemoteChecksum.ps1 │ ├── Push-Package.ps1 │ ├── Get-AUPackages.ps1 │ ├── Set-DescriptionFromReadme.ps1 │ ├── Get-Version.ps1 │ ├── Get-RemoteFiles.ps1 │ └── Test-Package.ps1 └── Chocolatey-AU.psd1 ├── .github ├── dependabot.yml ├── ISSUE_TEMPLATE │ ├── config.yml │ ├── zFeatureRequest.yml │ ├── zReportIssue.yml │ └── zNewRelease.md ├── workflows │ ├── build-module.yml │ └── label-sync.yml └── PULL_REQUEST_TEMPLATE.md ├── chocolatey ├── tools │ ├── chocolateyInstall.ps1 │ ├── chocolateyUninstall.ps1 │ └── install.ps1 └── chocolatey-au.nuspec ├── tests ├── test_package │ ├── update.ps1 │ ├── tools │ │ └── chocolateyInstall.ps1 │ └── test_package.nuspec ├── test_package_with_streams │ ├── test_package_with_streams.json │ ├── update.ps1 │ ├── tools │ │ └── chocolateyInstall.ps1 │ └── test_package_with_streams.nuspec ├── General.Tests.ps1 ├── AUPackage.Tests.ps1 ├── Get-Version.Tests.ps1 ├── Update-AUPackages.Streams.Tests.ps1 ├── Update-AUPackages.Tests.ps1 └── Update-Package.Tests.ps1 ├── DEVEL.md ├── GitReleaseManager.yaml ├── scripts └── Install-AU.ps1 ├── Migrating-AU-to-Chocolatey-AU.md ├── PSScriptAnalyzerSettings.psd1 ├── .teamcity └── settings.kts ├── Plugins.md ├── Chocolatey-AU.build.ps1 └── CHANGELOG.md /.templates/default/milestone.sbn: -------------------------------------------------------------------------------- 1 | 2 | {{ milestone.target.description }} 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /code_drop 2 | /tests/.vscode/launch.json 3 | /.vscode/launch.json 4 | -------------------------------------------------------------------------------- /.templates/contributors/milestone.sbn: -------------------------------------------------------------------------------- 1 | 2 | {{ milestone.target.description }} 3 | -------------------------------------------------------------------------------- /.templates/no/issues/milestone.sbn: -------------------------------------------------------------------------------- 1 | 2 | {{ milestone.target.description }} 3 | -------------------------------------------------------------------------------- /.templates/no/issues/issues.sbn: -------------------------------------------------------------------------------- 1 | 2 | This release had no issues associated with it. 3 | -------------------------------------------------------------------------------- /GitVersion.yml: -------------------------------------------------------------------------------- 1 | next-version: 1.0.0 2 | ignore: 3 | commits-before: 2022-10-31T12:08:00 4 | -------------------------------------------------------------------------------- /.templates/default/issue-note.sbn: -------------------------------------------------------------------------------- 1 | - {{ issue.title }} - see [#{{ issue.public_number}}]({{ issue.html_url }}). 2 | -------------------------------------------------------------------------------- /.templates/default/issues.sbn: -------------------------------------------------------------------------------- 1 | 2 | {{ for issue_label in issue_labels 3 | include 'issue-details' 4 | end }} 5 | -------------------------------------------------------------------------------- /.templates/contributors/issues.sbn: -------------------------------------------------------------------------------- 1 | 2 | {{ for issue_label in issue_labels 3 | include 'issue-details' 4 | end }} 5 | -------------------------------------------------------------------------------- /src/Plugins/Report/r_er.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chocolatey-community/chocolatey-au/HEAD/src/Plugins/Report/r_er.png -------------------------------------------------------------------------------- /src/Plugins/Report/r_ok.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chocolatey-community/chocolatey-au/HEAD/src/Plugins/Report/r_ok.png -------------------------------------------------------------------------------- /src/Private/is_url.ps1: -------------------------------------------------------------------------------- 1 | # Returns [bool] 2 | function is_url([string] $Url ) { 3 | [Uri]::IsWellFormedUriString($URL, [UriKind]::Absolute) 4 | } 5 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: github-actions 4 | directory: / 5 | schedule: 6 | interval: daily 7 | -------------------------------------------------------------------------------- /.templates/default/issue-details.sbn: -------------------------------------------------------------------------------- 1 | ### {{ issue_label }} 2 | 3 | {{ for issue in issues.items[issue_label] 4 | include 'issue-note' 5 | end }} 6 | -------------------------------------------------------------------------------- /.templates/contributors/issue-details.sbn: -------------------------------------------------------------------------------- 1 | ### {{ issue_label }} 2 | {{ for issue in issues.items[issue_label] 3 | include 'issue-note' 4 | end }} 5 | 6 | -------------------------------------------------------------------------------- /src/Private/is_version.ps1: -------------------------------------------------------------------------------- 1 | # Returns [bool] 2 | function is_version( [string] $Version ) { 3 | return [AUVersion]::TryParse($Version, [ref]($__)) 4 | } 5 | -------------------------------------------------------------------------------- /chocolatey/tools/chocolateyInstall.ps1: -------------------------------------------------------------------------------- 1 | $ErrorActionPreference = 'Stop' 2 | 3 | $toolsPath = Split-Path $MyInvocation.MyCommand.Definition 4 | & "$toolsPath/install.ps1" 5 | -------------------------------------------------------------------------------- /chocolatey/tools/chocolateyUninstall.ps1: -------------------------------------------------------------------------------- 1 | $ErrorActionPreference = 'Stop' 2 | 3 | $toolsPath = Split-Path $MyInvocation.MyCommand.Definition 4 | & "$toolsPath/install.ps1" -Remove 5 | -------------------------------------------------------------------------------- /tests/test_package/update.ps1: -------------------------------------------------------------------------------- 1 | function global:au_SearchReplace() { 2 | @{} 3 | } 4 | 5 | function global:au_GetLatest() { 6 | @{ Version = '1.2.3' } 7 | } 8 | 9 | update 10 | -------------------------------------------------------------------------------- /.templates/contributors/contributor-details.sbn: -------------------------------------------------------------------------------- 1 | Profile image for contributor {{contributor.login}} -------------------------------------------------------------------------------- /.templates/no/issues/release-info.sbn: -------------------------------------------------------------------------------- 1 | {{ 2 | if commits.count > 0 3 | }}As part of this release we had [{{ commits.count }} {{ commits.count | string.pluralize "commit" "commits" }}]({{ commits.html_url }}). 4 | {{ end -}} 5 | -------------------------------------------------------------------------------- /tests/test_package_with_streams/test_package_with_streams.json: -------------------------------------------------------------------------------- 1 | { 2 | "1.2": "1.2.3", 3 | "1.3": "1.3.1", 4 | "1.4": "1.4-beta1", 5 | "stable": "1.2.3", 6 | "beta": "1.3.1", 7 | "dev": "1.4-beta1" 8 | } 9 | -------------------------------------------------------------------------------- /src/Chocolatey-AU.psm1: -------------------------------------------------------------------------------- 1 | #requires -version 3 2 | 3 | $paths = "Private", "Public" 4 | foreach ($path in $paths) { 5 | Get-ChildItem ([System.IO.Path]::Combine($PSScriptRoot, $path, '*.ps1')) | ForEach-Object { . $_.FullName } 6 | } 7 | -------------------------------------------------------------------------------- /.templates/contributors/contributors.sbn: -------------------------------------------------------------------------------- 1 | 2 | 3 | ### Contributors 4 | 5 | {{ contributors.count }} contributors made this release possible. 6 | 7 | {{ for contributor in contributors.items 8 | include 'contributor-details' 9 | end }} -------------------------------------------------------------------------------- /.templates/default/index.sbn: -------------------------------------------------------------------------------- 1 | {{- 2 | include 'release-info' 3 | if milestone.target.description 4 | include 'milestone' 5 | end 6 | include 'issues' | string.rstrip 7 | if template_kind == "CREATE" 8 | include 'create/footer' 9 | end 10 | ~}} 11 | -------------------------------------------------------------------------------- /.templates/no/issues/index.sbn: -------------------------------------------------------------------------------- 1 | {{- 2 | include 'release-info' 3 | if milestone.target.description 4 | include 'milestone' 5 | end 6 | include 'issues' | string.rstrip 7 | if template_kind == "CREATE" 8 | include 'create/footer' 9 | end 10 | ~}} 11 | -------------------------------------------------------------------------------- /tests/test_package_with_streams/update.ps1: -------------------------------------------------------------------------------- 1 | function global:au_SearchReplace() { 2 | @{} 3 | } 4 | 5 | function global:au_GetLatest() { 6 | @{ Streams = [ordered] @{ 7 | '1.4' = @{ Version = '1.4-beta1' } 8 | '1.3' = @{ Version = '1.3.1' } 9 | '1.2' = @{ Version = '1.2.3' } 10 | } } 11 | } 12 | 13 | update 14 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/config.yml: -------------------------------------------------------------------------------- 1 | blank_issues_enabled: false 2 | contact_links: 3 | - name: Ask Question In Chat 4 | url: https://ch0.co/community-support 5 | about: Chat with our community and ask your question. 6 | - name: Ask Question By Email 7 | url: http://groups.google.com/group/chocolatey 8 | about: If you prefer to use email, you can ask your question here. 9 | -------------------------------------------------------------------------------- /.templates/default/create/footer.sbn: -------------------------------------------------------------------------------- 1 | {{ if config.create.include_footer }} 2 | 3 | ### {{ config.create.footer_heading }} 4 | 5 | {{ if config.create.milestone_replace_text 6 | replace_milestone_title config.create.footer_content config.create.milestone_replace_text milestone.target.title 7 | else 8 | config.create.footer_content 9 | end 10 | end }} 11 | -------------------------------------------------------------------------------- /tests/test_package/tools/chocolateyInstall.ps1: -------------------------------------------------------------------------------- 1 | $ErrorActionPreference = 'Stop' 2 | 3 | $packageName = 'test_package' 4 | $url32 = Get-Command choco.exe | ForEach-Object Source 5 | $checksum32 = '' 6 | 7 | $params = @{ 8 | packageName = $packageName 9 | fileFullPath = "$PSScriptRoot\choco.exe" 10 | Url = "file:///$url32" 11 | } 12 | Get-ChocolateyWebFile @params 13 | -------------------------------------------------------------------------------- /.templates/contributors/create/footer.sbn: -------------------------------------------------------------------------------- 1 | {{ if config.create.include_footer }} 2 | 3 | ### {{ config.create.footer_heading }} 4 | 5 | {{ if config.create.milestone_replace_text 6 | replace_milestone_title config.create.footer_content config.create.milestone_replace_text milestone.target.title 7 | else 8 | config.create.footer_content 9 | end 10 | end }} 11 | -------------------------------------------------------------------------------- /.templates/contributors/index.sbn: -------------------------------------------------------------------------------- 1 | {{- 2 | include 'release-info' 3 | if milestone.target.description != "" 4 | include 'milestone' 5 | end 6 | include 'issues' | string.rstrip 7 | if contributors.count > 0 8 | include 'contributors' 9 | end 10 | if template_kind == "CREATE" 11 | include 'create/footer' 12 | end 13 | ~}} 14 | -------------------------------------------------------------------------------- /.templates/no/issues/create/footer.sbn: -------------------------------------------------------------------------------- 1 | {{ if config.create.include_footer }} 2 | 3 | ### {{ config.create.footer_heading }} 4 | 5 | {{ if config.create.milestone_replace_text 6 | replace_milestone_title config.create.footer_content config.create.milestone_replace_text milestone.target.title 7 | else 8 | config.create.footer_content 9 | end 10 | end }} 11 | -------------------------------------------------------------------------------- /tests/test_package_with_streams/tools/chocolateyInstall.ps1: -------------------------------------------------------------------------------- 1 | $ErrorActionPreference = 'Stop' 2 | 3 | $packageName = 'test_package_with_streams' 4 | $url32 = Get-Command choco.exe | ForEach-Object Source 5 | $checksum32 = '' 6 | 7 | $params = @{ 8 | packageName = $packageName 9 | fileFullPath = "$PSScriptRoot\choco.exe" 10 | Url = "file:///$url32" 11 | } 12 | Get-ChocolateyWebFile @params 13 | -------------------------------------------------------------------------------- /src/Private/check_url.ps1: -------------------------------------------------------------------------------- 1 | # Returns nothing if url is valid, error otherwise 2 | function check_url( [string] $Url, [int]$Timeout, $ExcludeType='text/html', $Options ) { 3 | if (!(is_url $Url)) { return "URL syntax is invalid" } 4 | 5 | try 6 | { 7 | $response = request $url $Timeout -Options $Options 8 | if ($response.ContentType -like "*${ExcludeType}*") { return "Bad content type '$ExcludeType'" } 9 | } 10 | catch { 11 | return "Can't validate URL`n$_" 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/Public/Get-RemoteChecksum.ps1: -------------------------------------------------------------------------------- 1 | # Author: Miodrag Milic 2 | # Last Change: 26-Nov-2016. 3 | 4 | <# 5 | .SYNOPSIS 6 | Download file from internet and calculate its checksum 7 | 8 | #> 9 | function Get-RemoteChecksum( [string] $Url, $Algorithm='sha256', $Headers ) { 10 | $fn = [System.IO.Path]::GetTempFileName() 11 | Invoke-WebRequest $Url -OutFile $fn -UseBasicParsing -Headers $Headers 12 | $res = Get-FileHash $fn -Algorithm $Algorithm | ForEach-Object Hash 13 | Remove-Item $fn -ea ignore 14 | return $res.ToLower() 15 | } 16 | 17 | -------------------------------------------------------------------------------- /src/Private/request.ps1: -------------------------------------------------------------------------------- 1 | function request( [string]$Url, [int]$Timeout, $Options ) { 2 | if ([string]::IsNullOrWhiteSpace($url)) {throw 'The URL is empty'} 3 | $request = [System.Net.WebRequest]::Create($Url) 4 | if ($Timeout) { $request.Timeout = $Timeout*1000 } 5 | 6 | if ($Options.Headers) { 7 | $Options.Headers.Keys | ForEach-Object { 8 | if ([System.Net.WebHeaderCollection]::IsRestricted($_)) { 9 | $key = $_.Replace('-','') 10 | $request.$key = $Options.Headers[$_] 11 | } 12 | else { 13 | $request.Headers.add($_, $Options.Headers[$_]) 14 | } 15 | } 16 | } 17 | 18 | $response = $request.GetResponse() 19 | $response.Close() 20 | $response 21 | } 22 | -------------------------------------------------------------------------------- /.templates/default/release-info.sbn: -------------------------------------------------------------------------------- 1 | {{ 2 | if issues.count > 0 3 | if commits.count > 0 4 | }}As part of this release we had [{{ commits.count }} {{ commits.count | string.pluralize "commit" "commits" }}]({{ commits.html_url }}) which resulted in [{{ issues.count }} {{ issues.count | string.pluralize "issue" "issues" }}]({{ milestone.target.html_url }}?{{ milestone.query_string }}) being closed. 5 | {{ else 6 | }}As part of this release we had [{{ issues.count }} {{ issues.count | string.pluralize "issue" "issues" }}]({{ milestone.target.html_url }}?{{ milestone.query_string }}) closed. 7 | {{ end 8 | else if commits.count > 0 9 | }}As part of this release we had [{{ commits.count }} {{ commits.count | string.pluralize "commit" "commits" }}]({{ commits.html_url }}). 10 | {{ end -}} 11 | -------------------------------------------------------------------------------- /.templates/contributors/release-info.sbn: -------------------------------------------------------------------------------- 1 | {{ 2 | if issues.count > 0 3 | if commits.count > 0 4 | }}As part of this release we had [{{ commits.count }} {{ commits.count | string.pluralize "commit" "commits" }}]({{ commits.html_url }}) which resulted in [{{ issues.count }} {{ issues.count | string.pluralize "issue" "issues" }}]({{ milestone.target.html_url }}?{{ milestone.query_string }}) being closed. 5 | {{ else 6 | }}As part of this release we had [{{ issues.count }} {{ issues.count | string.pluralize "issue" "issues" }}]({{ milestone.target.html_url }}?{{ milestone.query_string }}) closed. 7 | {{ end 8 | else if commits.count > 0 9 | }}As part of this release we had [{{ commits.count }} {{ commits.count | string.pluralize "commit" "commits" }}]({{ commits.html_url }}). 10 | {{ end -}} 11 | -------------------------------------------------------------------------------- /.github/workflows/build-module.yml: -------------------------------------------------------------------------------- 1 | name: Chocolatey-AU Builds 2 | 3 | on: 4 | # Trigger on pushes and on pull requests 5 | push: 6 | branches: 7 | - main 8 | - master 9 | - develop 10 | pull_request: 11 | 12 | # Allows you to run this workflow manually from the Actions tab 13 | workflow_dispatch: 14 | 15 | jobs: 16 | # Build on Windows 17 | windows-build: 18 | runs-on: windows-2019 19 | steps: 20 | - uses: actions/checkout@v6 21 | with: 22 | fetch-depth: 0 23 | - name: Build Chocolatey-AU module 24 | run: .\build.ps1 -Task CI -Verbose -ErrorAction Stop 25 | - name: Upload Windows build results 26 | uses: actions/upload-artifact@v6 27 | # Always upload build results 28 | if: ${{ always() }} 29 | with: 30 | name: build-results 31 | path: | 32 | code_drop/** 33 | -------------------------------------------------------------------------------- /src/Plugins/Report.ps1: -------------------------------------------------------------------------------- 1 | # Author: Miodrag Milic 2 | # Last Change: 10-Nov-2016. 3 | <# 4 | .SYNOPSIS 5 | Create different types of reports about the current run. 6 | 7 | .DESCRIPTION 8 | The plugin saves state of all packages in a file that can be used locally or 9 | uploaded via other plugins to remote (such as Gist or Mail). 10 | #> 11 | 12 | param( 13 | $Info, 14 | 15 | # Type of the report, currently 'markdown' or 'text' 16 | [string] $Type = 'markdown', 17 | 18 | # Path where to save the report 19 | [string] $Path = 'Update-AUPackages.md', 20 | 21 | # Report parameters 22 | [HashTable] $Params 23 | ) 24 | 25 | Write-Host "Saving $Type report: $Path" 26 | 27 | $Type = ([System.IO.Path]::Combine($PSScriptRoot, 'Report', "$Type.ps1")) 28 | if (!(Test-Path $Type )) { throw "Report type not found: '$Type" } 29 | 30 | $result = & $Type 31 | $result | Out-File $Path 32 | -------------------------------------------------------------------------------- /tests/test_package/test_package.nuspec: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | test_package 5 | 1.2.3 6 | Test Package 7 | Miodrag Milić 8 | Miodrag Milić 9 | http://www.gnu.org/copyleft/gpl.html 10 | https://github.com/majkinetor/au 11 | false 12 | This is a test package for Pester 13 | This is a test package for Pester 14 | test pester 15 | 16 | 17 | 18 | None 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /tests/General.Tests.ps1: -------------------------------------------------------------------------------- 1 | remove-module Chocolatey-AU -ea ignore 2 | import-module $PSScriptRoot\..\Chocolatey-AU\Chocolatey-AU.psm1 # Tests require the private functions exported 3 | 4 | Describe 'General' { 5 | $saved_pwd = $pwd 6 | 7 | BeforeEach { 8 | Set-Location $TestDrive 9 | Remove-Item -Recurse -Force TestDrive:\test_package -ea ignore 10 | Copy-Item -Recurse -Force $PSScriptRoot\test_package TestDrive:\test_package 11 | } 12 | 13 | It 'considers au_root global variable when looking for packages' { 14 | $path = 'TestDrive:\packages\test_package2' 15 | New-Item -Type Directory $path -Force 16 | Copy-Item -Recurse -Force $PSScriptRoot\test_package\* $path 17 | 18 | $global:au_root = Split-Path $path 19 | $res = lsau 20 | 21 | $res | Should Not BeNullOrEmpty 22 | $res[0].Name | Should Be 'test_package2' 23 | } 24 | 25 | Set-Location $saved_pwd 26 | } 27 | -------------------------------------------------------------------------------- /tests/test_package_with_streams/test_package_with_streams.nuspec: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | test_package_with_streams 5 | 1.2.3 6 | Test Package with Streams 7 | Miodrag Milić 8 | Miodrag Milić 9 | http://www.gnu.org/copyleft/gpl.html 10 | https://github.com/majkinetor/au 11 | false 12 | This is a test package with streams for Pester 13 | This is a test package with streams for Pester 14 | test streams pester 15 | 16 | 17 | 18 | None 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /DEVEL.md: -------------------------------------------------------------------------------- 1 | # Development 2 | 3 | Development of Chocolatey-AU requires Powershell 5+. 4 | 5 | The `build.ps1` script is used during development and has the following tasks: 6 | 7 | - `Clean` 8 | - Remove the Output directory. 9 | - `Build` 10 | - Build the module into a usable state. 11 | - `Test` 12 | - Run the Pester tests on the module. 13 | - `CreateChocolateyPackage` 14 | - Turn the built module into a Chocolatey package. 15 | 16 | 17 | ## Build and test 18 | 19 | The built module will be available in the `Output` directory. 20 | 21 | ``` 22 | ./build.ps1 23 | ``` 24 | The following example commands can be run from the repository root: 25 | 26 | | Description | Command | 27 | | :--- | :--- | 28 | | Run just the build and do not run the Pester Tests | `./build -Task Build` | 29 | | Run the build the same way that CI will run it | `./build.ps1 -Task CI -Verbose -ErrorAction Stop` | 30 | | Clean temporary build files | `./build.ps1 -Task Clean` | 31 | | Create a Chocolatey package | `./build.ps1 -Task CreateChocolateyPackage` | 32 | -------------------------------------------------------------------------------- /GitReleaseManager.yaml: -------------------------------------------------------------------------------- 1 | issue-labels-include: 2 | - Breaking Change 3 | - Deprecate 4 | - Enhancement 5 | - Bug 6 | - Documentation 7 | - Dependency Change 8 | issue-labels-exclude: 9 | - Build Automation 10 | - NO RELEASE NOTES 11 | issue-labels-alias: 12 | - name: Documentation 13 | header: Documentation 14 | plural: Documentation 15 | - name: Bug 16 | header: Bug Fix 17 | plural: Bug Fixes 18 | - name: Deprecate 19 | header: Deprecated Feature 20 | plural: Deprecated Features 21 | create: 22 | include-sha-section: true 23 | sha-section-heading: "SHA256 Hashes of the release artifacts" 24 | sha-section-line-format: "- `{1}\t{0}`" 25 | include-contributors: true 26 | close: 27 | use-issue-comments: true 28 | set-due-date: true 29 | issue-comment: |- 30 | :tada: This issue has been resolved in version {milestone} :tada: 31 | 32 | The release is available on: 33 | 34 | - [GitHub Release](https://github.com/{owner}/{repository}/releases/tag/{milestone}) 35 | - [Chocolatey Community Repository](https://community.chocolatey.org/packages/{repository}/{milestone}) 36 | - [PowerShell Gallery](https://www.powershellgallery.com/packages/{repository}/{milestone}) 37 | 38 | Your **[GitReleaseManager](https://github.com/GitTools/GitReleaseManager)** bot :package: :rocket: 39 | 40 | -------------------------------------------------------------------------------- /src/Public/Push-Package.ps1: -------------------------------------------------------------------------------- 1 | # Author: Miodrag Milic 2 | # Last Change: 22-Oct-2016. 3 | 4 | <# 5 | .SYNOPSIS 6 | Push latest (or all) created package(s) to the Chocolatey community repository. 7 | 8 | .DESCRIPTION 9 | The function uses they API key from the file api_key in current or parent directory, environment variable 10 | or cached nuget API key. 11 | #> 12 | function Push-Package() { 13 | param( 14 | [switch] $All 15 | ) 16 | $api_key = if (Test-Path api_key) { Get-Content api_key } 17 | elseif (Test-Path (Join-Path '..' 'api_key')) { Get-Content (Join-Path '..' 'api_key') } 18 | elseif ($Env:api_key) { $Env:api_key } 19 | 20 | $push_url = if ($Env:au_PushUrl) { $Env:au_PushUrl } 21 | else { 'https://push.chocolatey.org' } 22 | 23 | $force_push = if ($Env:au_ForcePush) { '--force' } 24 | else { '' } 25 | 26 | $packages = Get-ChildItem *.nupkg | Sort-Object -Property CreationTime -Descending 27 | if (!$All) { $packages = $packages | Select-Object -First 1 } 28 | if (!$packages) { throw 'There is no nupkg file in the directory'} 29 | if ($api_key) { 30 | $packages | ForEach-Object { choco push $_.Name --api-key $api_key --source $push_url $force_push } 31 | } else { 32 | $packages | ForEach-Object { choco push $_.Name --source $push_url $force_push } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/Public/Get-AUPackages.ps1: -------------------------------------------------------------------------------- 1 | # Author: Miodrag Milic 2 | # Last Change: 12-Nov-2016. 3 | 4 | <# 5 | .SYNOPSIS 6 | Get AU packages 7 | 8 | .DESCRIPTION 9 | 10 | Returns list of directories that have update.ps1 script in them and package name 11 | doesn't start with the '_' char (unpublished packages, not considered by Update-AUPackages 12 | function). 13 | 14 | Function looks in the directory pointed to by the global variable $au_root or, if not set, 15 | the current directory. 16 | 17 | .EXAMPLE 18 | gau p* 19 | 20 | Get all automatic packages that start with 'p' in the current directory. 21 | 22 | .EXAMPLE 23 | $au_root = 'c:\packages'; lsau 'cpu-z*','p*','copyq' 24 | 25 | Get all automatic packages in the directory 'c:\packages' that start with 'cpu-z' or 'p' and package which name is 'copyq'. 26 | #> 27 | function Get-AUPackages( [string[]] $Name ) { 28 | $root = $global:au_root 29 | if (!$root) { $root = $pwd } 30 | 31 | Get-ChildItem ([System.IO.Path]::Combine($root, '*', 'update.ps1')) | ForEach-Object { 32 | $packageDir = Get-Item (Split-Path $_) 33 | 34 | if ($Name -and $Name.Length -gt 0) { 35 | $m = $Name | Where-Object { $packageDir.Name -like $_ } 36 | if (!$m) { return } 37 | } 38 | 39 | if ($packageDir.Name -like '_*') { return } 40 | $packageDir 41 | } 42 | } 43 | 44 | Set-Alias gau Get-AuPackages 45 | Set-Alias lsau Get-AuPackages 46 | -------------------------------------------------------------------------------- /src/Public/Set-DescriptionFromReadme.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | Updates nuspec file description from README.md 4 | 5 | .DESCRIPTION 6 | This script should be called in au_AfterUpdate to put the text in the README.md 7 | into description tag of the Nuspec file. The current description will be replaced. 8 | 9 | You need to call this function manually only if you want to pass it custom parameters. 10 | In that case use NoReadme parameter of the Update-Package. 11 | 12 | .EXAMPLE 13 | function global:au_AfterUpdate { Set-DescriptionFromReadme -Package $args[0] -SkipLast 2 -SkipFirst 2 } 14 | #> 15 | function Set-DescriptionFromReadme{ 16 | param( 17 | [AUPackage] $Package, 18 | # Number of start lines to skip from the README.md, by default 0. 19 | [int] $SkipFirst=0, 20 | # Number of end lines to skip from the README.md, by default 0. 21 | [int] $SkipLast=0, 22 | # Readme file path 23 | [string] $ReadmePath = 'README.md' 24 | ) 25 | 26 | "Setting package description from $ReadmePath" 27 | 28 | $description = Get-Content $ReadmePath -Encoding UTF8 29 | $endIdx = $description.Length - $SkipLast 30 | $description = $description | Select-Object -Index ($SkipFirst..$endIdx) | Out-String 31 | 32 | $cdata = $Package.NuspecXml.CreateCDataSection($description) 33 | $xml_Description = $Package.NuspecXml.GetElementsByTagName('description')[0] 34 | $xml_Description.RemoveAll() 35 | $xml_Description.AppendChild($cdata) | Out-Null 36 | 37 | $Package.SaveNuspec() 38 | } 39 | -------------------------------------------------------------------------------- /src/Plugins/Snippet.ps1: -------------------------------------------------------------------------------- 1 | # Author: dimqua 2 | # Last Change: 11-Oct-2018. 3 | <# 4 | .SYNOPSIS 5 | Upload update history report to Gitlab snippet. 6 | 7 | .DESCRIPTION 8 | Plugin uploads update history report (created by Report plugin) to the snippet with the given id and filename. You can use gitlab.com instance (default) or self-hosted one. 9 | #> 10 | param( 11 | $Info, 12 | 13 | # Snippet id 14 | [string] $Id, 15 | 16 | # Gitlab API Token, create in User Settings -> Access Tokens -> Create personal access token 17 | # Make sure token has 'api' scope. 18 | [string] $ApiToken, 19 | 20 | # File paths to attach to snippet 21 | [string[]] $Path, 22 | 23 | # Snippet file name 24 | [string] $FileName = 'Update-AUPackages.md', 25 | 26 | # GitLab instance's (sub)domain name 27 | [string] $Domain = 'gitlab.com' 28 | 29 | ) 30 | 31 | # Create snippet 32 | Get-ChildItem $Path | ForEach-Object { 33 | $file_name = Split-Path $_ -Leaf 34 | $content = Get-Content $_ -Raw 35 | $snippet = '{"content": "' + $content + '"}' 36 | } 37 | 38 | $params = @{ 39 | ContentType = 'application/json' 40 | Method = "PUT" 41 | Uri = "https://$Domain/api/v4/snippets/$Id" 42 | Body = ($snippet | ConvertTo-Json).replace('"{\"content\": \"','{"content": "').replace('\"}"','"') + ', "file_name": "' + $FileName + '"}' 43 | Headers = @{ 'PRIVATE-TOKEN'=$ApiToken } 44 | } 45 | 46 | # Request 47 | $res = Invoke-WebRequest @params 48 | "https://$Domain/snippets/$Id" 49 | -------------------------------------------------------------------------------- /.github/workflows/label-sync.yml: -------------------------------------------------------------------------------- 1 | name: Sync labels 2 | on: 3 | workflow_dispatch: 4 | schedule: 5 | # Run at the end of the day (most likely UTC) 6 | - cron: "0 0 * * *" 7 | push: 8 | branches: 9 | - main 10 | - master 11 | - develop 12 | paths: 13 | - '.github/workflows/label-sync.yml' 14 | # Uncomment the following line if using a repository specific label file, also remove this comment line 15 | # - '.github/labels.yml' 16 | 17 | jobs: 18 | labels: 19 | # We use ubuntu as the image, as it is typically faster and cheaper (on private repos). 20 | runs-on: ubuntu-latest 21 | 22 | steps: 23 | # Uncomment the following uses statement block if using a repository specific label file, also remove this comment line 24 | #- uses: actions/checkout@v4 25 | # with: 26 | # sparse-checkout: .github/labels.yml 27 | - uses: EndBug/label-sync@v2 28 | with: 29 | config-file: | 30 | https://raw.githubusercontent.com/chocolatey/.github/main/.github/labels.yml 31 | # Uncomment the following line if using a repository specific label file, also remove this comment line 32 | # .github/labels.yml 33 | request-token: ${{ secrets.SYNC_TOKEN }} # Used when getting the config files. 34 | delete-other-labels: true # After initial run, and verification change this to true 35 | dry-run: false 36 | token: ${{ secrets.SYNC_TOKEN }} # Used when updating the labels on the repository. 37 | 38 | 39 | -------------------------------------------------------------------------------- /.templates/contributors/issue-note.sbn: -------------------------------------------------------------------------------- 1 | {{ 2 | func IssueDescription 3 | if $0.is_pull_request 4 | $description = "[!" + $0.public_number + "]" 5 | else 6 | $description = "[#" + $0.public_number + "]" 7 | end 8 | $description = $description + "(" + $0.html_url + ")" 9 | if $1 10 | $description = $0.title + "." + "\n - See " + $description 11 | end 12 | if $0.user 13 | $description = $description + " by [" + $0.user.login + "](" + $0.user.html_url + ")" 14 | end 15 | if $0.linked_issues 16 | $description = $description + LinkedIssuesDescription($0.linked_issues) + "." 17 | end 18 | ret $description 19 | end 20 | func LinkedIssuesDescription 21 | $countPRs = 0 22 | $countIssues = 0 23 | for linkedIssue in $0 24 | if linkedIssue.is_pull_request 25 | if $countPRs == 0 26 | $resolvedBy = ", resolved in " 27 | else 28 | $resolvedBy = $resolvedBy + ", " 29 | end 30 | $resolvedBy = $resolvedBy + IssueDescription(linkedIssue, false) 31 | $countPRs = $countPRs + 1 32 | else 33 | if $countIssues == 0 34 | $raisedIn = " raised in " 35 | else 36 | $raisedIn = $raisedIn + ", " 37 | end 38 | $raisedIn = $raisedIn + IssueDescription(linkedIssue, false) 39 | $countIssues = $countIssues + 1 40 | end 41 | end 42 | ret $raisedIn + $resolvedBy 43 | end 44 | }} 45 | - {{ IssueDescription(issue, true) }} -------------------------------------------------------------------------------- /src/Plugins/Gitter.ps1: -------------------------------------------------------------------------------- 1 | # Author: Kim Nordmo 2 | # Last Change: 2018-06-13 3 | <# 4 | .SYNOPSIS 5 | Publishes the package update status to gitter. 6 | 7 | .PARAMETER WebHookUrl 8 | This is the cusotm webhook url created through gitter integrations. 9 | 10 | .PARAMETER MessageFormat 11 | The format of the message that is meant to be published on gitter. 12 | {0} = The total number of automated packages. 13 | {1} = The number of updated packages, 14 | {2} = The number of published packages. 15 | {3} = The number of failed packages. 16 | {4} = The url to the github gist. 17 | #> 18 | param( 19 | $Info, 20 | [string]$WebHookUrl, 21 | [string]$MessageFormat = "[Update Status:{0} packages.`n {1} updated, {2} Published, {3} Failed]({4})" 22 | ) 23 | 24 | if (!$WebHookUrl) { return } # If we don't have a webhookurl we can't push status messages, so ignore. 25 | 26 | $updatedPackages = @($Info.result.updated).Count 27 | $publishedPackages = @($Info.result.pushed).Count 28 | $failedPackages = $Info.error_count.total 29 | $gistUrl = $Info.plugin_results.Gist -split '\n' | Select-Object -Last 1 30 | $packageCount = $Info.result.all.Length 31 | 32 | $gitterMessage = ($MessageFormat -f $packageCount, $updatedPackages, $publishedPackages, $failedPackages, $gistUrl) 33 | 34 | $arguments = @{ 35 | Body = if ($failedPackages -gt 0) { "message=$gitterMessage&level=error" } else { "message=$gitterMessage" } 36 | UseBasicParsing = $true 37 | Uri = $WebHookUrl 38 | ContentType = 'application/x-www-form-urlencoded' 39 | Method = 'Post' 40 | } 41 | 42 | "Submitting message to gitter" 43 | Invoke-RestMethod @arguments 44 | "Message submitted to gitter" -------------------------------------------------------------------------------- /src/Plugins/Mail.ps1: -------------------------------------------------------------------------------- 1 | # Author: Miodrag Milic 2 | # Last Change: 12-Nov-2016. 3 | 4 | param( 5 | $Info, 6 | [string] $To, 7 | [string] $From, 8 | [string] $Server, 9 | [string] $UserName, 10 | [string] $Password, 11 | [int] $Port, 12 | [string[]] $Attachment, 13 | [switch] $EnableSsl, 14 | [string] $UserMessage, 15 | # Do not send only on errors 16 | [switch] $SendAlways 17 | ) 18 | 19 | if (($Info.error_count.total -eq 0) -and !$SendAlways) { 20 | Write-Host 'Mail not sent as there are no errors (override with SendAlways param)' 21 | return 22 | } 23 | 24 | $errors_word = if ($Info.error_count.total -eq 1) { 'error' } else { 'errors' } 25 | 26 | # Create mail message 27 | 28 | if (!$From) { $From = "Update-AUPackages@{0}.{1}" -f $Env:UserName, $Env:ComputerName } 29 | 30 | $msg = New-Object System.Net.Mail.MailMessage $from, $To 31 | $msg.IsBodyHTML = $true 32 | 33 | if ($Info.error_count.total -eq 0) { 34 | $msg.Subject = "AU: run was OK" 35 | $msg.Body = $Info.stats | Out-String 36 | } 37 | else { 38 | $context = "with errors " 39 | $msg.Subject = "AU: $($info.error_count.total) $errors_word during update" 40 | $msg.Body = @" 41 |
42 | $($Info.error_count.total) $errors_word during update.
43 | $UserMessage
44 | $($info.error_info | Out-String)
45 | 
46 | "@ 47 | } 48 | 49 | $Attachment | ForEach-Object { if ($_) { $msg.Attachments.Add($_)} } 50 | 51 | # Send mail message 52 | $smtp = new-object Net.Mail.SmtpClient($Server) 53 | if ($UserName) { $smtp.Credentials = new-object System.Net.NetworkCredential($UserName, $Password) } 54 | if ($Port) { $smtp.Port = $Port } 55 | $smtp.EnableSsl = $EnableSsl 56 | $smtp.Send($msg) 57 | 58 | Write-Host "Mail ${context}sent to $To" 59 | -------------------------------------------------------------------------------- /scripts/Install-AU.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | Intall AU from git repository using given version. Can also be used to install development branches. 3 | Git tags are treated as autoritative AU release source. 4 | 5 | This script is used for build server. 6 | #> 7 | 8 | [CmdletBinding()] 9 | param( 10 | # If parsable to [version], exact AU version will be installed. Example: '2016.10.30' 11 | # If not parsable to [version] it is assumed to be name of the AU git branch. Example: 'master' 12 | # If empty string or $null, latest release (git tag) will be installed. 13 | [string] $Version 14 | ) 15 | 16 | $ErrorActionPreference = 'STOP' 17 | $git_url = 'https://github.com/chocolatey-community/chocolatey-au.git' 18 | 19 | if (!(Get-Command git -ea 0)) { throw 'Git must be installed' } 20 | [version]$git_version = (git --version) -replace 'git|version|\.windows' 21 | if ($git_version -lt [version]2.5) { throw 'Git version must be higher then 2.5' } 22 | 23 | $is_latest = [string]::IsNullOrWhiteSpace($Version) 24 | $is_branch = !($is_latest -or [version]::TryParse($Version, [ref]($_))) 25 | 26 | Push-Location $PSScriptRoot\.. 27 | 28 | if ($is_latest) { $Version = (git tag | ForEach-Object { [version]$_ } | Sort-Object -desc | Select-Object -first 1).ToString() } 29 | if ($is_branch) { 30 | $branches = git branch -r -q | ForEach-Object { $_.Replace('origin/','').Trim() } 31 | if ($branches -notcontains $Version) { throw "Chocolatey-AU branch '$Version' doesn't exist" } 32 | if ($Version -ne 'master') { git fetch -q origin "${Version}:${Version}" } 33 | } else { 34 | $tags = git tag 35 | if ($tags -notcontains $Version ) { throw "Chocolatey-AU version '$Version' doesn't exist"} 36 | } 37 | 38 | git checkout -q $Version 39 | 40 | ./build.ps1 -Task Build 41 | .\code_drop\temp\chocolateyPackage\tools\install.ps1 42 | 43 | Pop-Location 44 | -------------------------------------------------------------------------------- /src/Plugins/RunInfo.ps1: -------------------------------------------------------------------------------- 1 | # Author: Miodrag Milic 2 | # Last Change: 21-Sep-2016. 3 | 4 | <# 5 | .SYNOPSIS 6 | Save run info to the file and exclude sensitive information. 7 | 8 | .DESCRIPTION 9 | Run this plugin as the last one to save all other info produced during the run. 10 | To load it for inspection use `$info = Import-CliXml update_info.xml`. 11 | #> 12 | param( 13 | $Info, 14 | 15 | #Path to XML file to save 16 | [string] $Path = 'update_info.xml', 17 | 18 | #Match options with those words to erase 19 | [string[]] $Exclude = @('password', 'apikey') 20 | ) 21 | 22 | function deep_clone { 23 | param($DeepCopyObject) 24 | 25 | $memStream = new-object IO.MemoryStream 26 | $formatter = new-object Runtime.Serialization.Formatters.Binary.BinaryFormatter 27 | $formatter.Serialize($memStream,$DeepCopyObject) 28 | $memStream.Position=0 29 | $formatter.Deserialize($memStream) 30 | } 31 | 32 | # Runinfo must save its own run results directly in Info 33 | function result($msg) { $Info.plugin_results.RunInfo += $msg; Write-Host $msg } 34 | 35 | $Info.plugin_results.RunInfo = @() 36 | $format = '{0,-15}{1}' 37 | 38 | $orig_opts = $Info.Options 39 | $opts = deep_clone $orig_opts 40 | $excluded = '' 41 | foreach ($w in $Exclude) { 42 | foreach ($key in $Info.Options.Keys) { 43 | if ($Info.Options.$key -is [HashTable]) { 44 | foreach ($subkey in $Info.Options.$key.Keys) { 45 | if ($subkey -like "*$w*") { 46 | $excluded += "$key.$subkey " 47 | $opts.$key.$subkey = '*****' 48 | } 49 | } 50 | } 51 | } 52 | } 53 | 54 | if ($excluded) { result ($format -f 'Excluded:', $excluded) } 55 | result ($format -f 'File:', $Path) 56 | $Info.Options = $opts 57 | $Info | Export-CliXML $Path 58 | $Info.Options = $orig_opts 59 | -------------------------------------------------------------------------------- /chocolatey/chocolatey-au.nuspec: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | chocolatey-au 6 | Chocolatey Automatic Package Updater Module 7 | $version$ 8 | Miodrag Milić, Chocolatey Community 9 | Miodrag Milić, Chocolatey Community 10 | Chocolatey-AU is Powershell module that helps you to automate Chocolatey package updates 11 | 12 | https://github.com/chocolatey-community/chocolatey-au 13 | admin powershell module package chocolatey update 14 | Miodrag Milić, Chocolatey Community 15 | https://www.gnu.org/licenses/gpl-2.0.txt 16 | false 17 | https://github.com/chocolatey-community/chocolatey-au/releases/$version$ 18 | https://github.com/chocolatey-community/chocolatey-au/blob/develop/README.md 19 | https://github.com/chocolatey-community/chocolatey-au/issues 20 | https://github.com/chocolatey-community/chocolatey-au/issues 21 | https://github.com/chocolatey-community/chocolatey-au 22 | https://github.com/chocolatey-community/chocolatey-au/tree/develop/chocolatey 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /src/Public/Get-Version.ps1: -------------------------------------------------------------------------------- 1 | # Author: Thomas Démoulins 2 | 3 | <# 4 | .SYNOPSIS 5 | Parses a semver-like object from a string in a flexible manner. 6 | 7 | .DESCRIPTION 8 | This function parses a string containing a semver-like version 9 | and returns an object that represents both the version (with up to 4 parts) 10 | and optionally a pre-release and a build metadata. 11 | 12 | The parsing is quite flexible: 13 | - the version can be in the middle of a url or sentence 14 | - first version found is returned 15 | - there can be no hyphen between the version and the pre-release 16 | - extra spaces are ignored 17 | - optional delimiters can be provided to help parsing the string 18 | 19 | .EXAMPLE 20 | Get-Version 'Last version: 1.2.3 beta 3.' 21 | 22 | Returns 1.2.3-beta3 23 | 24 | .EXAMPLE 25 | Get-Version 'https://github.com/atom/atom/releases/download/v1.24.0-beta2/AtomSetup.exe' 26 | 27 | Return 1.24.0-beta2 28 | 29 | .EXAMPLE 30 | Get-Version 'http://mirrors.kodi.tv/releases/windows/win32/kodi-17.6-Krypton-x86.exe' -Delimiter '-' 31 | 32 | Return 17.6 33 | #> 34 | function Get-Version { 35 | [CmdletBinding()] 36 | param( 37 | # Version string to parse. 38 | [Parameter(Mandatory=$true)] 39 | [string] $Version, 40 | # Optional delimiter(s) to help locate the version in the string: the version must start and end with one of these chars. 41 | [char[]] $Delimiter 42 | ) 43 | if ($Delimiter) { 44 | $delimiters = $Delimiter -join '' 45 | @('\', ']', '^', '-') | ForEach-Object { $delimiters = $delimiters.Replace($_, "\$_") } 46 | $regex = $Version | Select-String -Pattern "[$delimiters](\d+\.\d+[^$delimiters]*)[$delimiters]" -AllMatches 47 | foreach ($match in $regex.Matches) { 48 | $reference = [ref] $null 49 | if ([AUVersion]::TryParse($match.Groups[1], $reference, $false)) { 50 | return $reference.Value 51 | } 52 | } 53 | } 54 | return [AUVersion]::Parse($Version, $false) 55 | } 56 | -------------------------------------------------------------------------------- /Migrating-AU-to-Chocolatey-AU.md: -------------------------------------------------------------------------------- 1 | # Migrating From `AU` To `Chocolatey-AU` 2 | 3 | With the [`1.0.0` release](https://github.com/chocolatey-community/chocolatey-au/releases/tag/1.0.0) of `Chocolatey-AU`, there is a need to migrate to the new package name. 4 | 5 | How you migrate from `AU` to `Chocolatey-AU` will depend on how you used `AU` in your repository. Below are some scenarios, but if you encounter a scenario not yet covered, please reach out in the [Chocolatey Community](https://ch0.co/community). 6 | 7 | ## Your Repository Currently Clones the Original `AU` Repository 8 | 9 | If you are cloning the [original `AU` repository](https://github.com/majkinetor/au/) and building the module from there, you will want to update to clone the Chocolatey Community `Chocolatey-AU` repository: `https://github.com/chocolatey-community/chocolatey-au.git` instead. Once that has been done, you will want to [amend your update scripts](#amending-your-update-scripts) to use the `Chocolatey-AU` PowerShell Module instead of `AU`. 10 | 11 | ## Your Repository Installs AU From the Chocolatey Community Repository 12 | 13 | If you are installing `AU` from the [Chocolatey Community Repository](https://community.chocolatey.org/), you will want to update it to `choco install chocolatey-au --confirm` instead of `choco install au -y`. Once that has been done, you will want to [update your update scripts](#amending-your-update-scripts) to use the `Chocolatey-AU` PowerShell Module instead of `AU`. 14 | 15 | ## Your Repository Installs AU From the Powershell Gallery 16 | 17 | If you are installing `AU` from the [PowerShell Gallery](https://powershellgallery.com), you will want to amend your code to `Install-Module Chocolatey-AU` from `Install-Module AU`. Once that has been done, you will want to [amend your update scripts](#amending-your-update-scripts) to use the `Chocolatey-AU` PowerShell Module instead of `AU`. 18 | 19 | ## Amending Your Update Scripts 20 | 21 | Once your repository uses the new module name, you will need to amend your `update.ps1` scripts to use the new module name. This is as simple as replacing `AU` with `Chocolatey-AU` for the `Import-Module` calls, or any `#requires -Modules` in your scripts. 22 | -------------------------------------------------------------------------------- /src/Plugins/Report/text.ps1: -------------------------------------------------------------------------------- 1 | $UserMessage = $Params.UserMessage 2 | $Title = if ($Params.Title) { $Params.Title } else { 'Update-AUPackages' } 3 | 4 | #============================================================================== 5 | 6 | function title($txt) { "`r`n{0}`r`n{1}`r`n" -f $txt,('-'*$txt.Length) } 7 | function indent($txt, $level=4) { $txt -split "`n" | ForEach-Object { ' '*$level + $_ } } 8 | 9 | $now = $Info.startTime.ToUniversalTime().ToString('yyyy-MM-dd HH:mm') 10 | $au_version = Get-Module Chocolatey-AU -ListAvailable | ForEach-Object Version | Select-Object -First 1 | ForEach-Object { "$_" } 11 | $package_no = $Info.result.all.Length 12 | 13 | "{0,-15}{1}" -f 'Title:', $Title 14 | "{0,-15}{1}" -f 'Time:', $now 15 | "{0,-15}{1}" -f 'AU version:', $au_version 16 | "{0,-15}{1}" -f 'AU packages:', $package_no 17 | 18 | $errors_word = if ($Info.error_count.total -eq 1) {'error'} else {'errors' } 19 | if ($Info.error_count.total) { 20 | "LAST RUN HAD $($Info.error_count.total) $errors_word !!!" } 21 | else { 22 | "Last run was OK" 23 | } 24 | 25 | ""; $Info.stats 26 | 27 | ""; $UserMessage; "" 28 | 29 | if ($Info.pushed) { 30 | title Pushed 31 | $Info.result.pushed | Select-Object 'Name', 'Updated', 'Pushed', 'RemoteVersion', 'NuspecVersion' | Format-Table | Out-String | Set-Variable r 32 | indent $r 2 33 | 34 | $Info.result.pushed | ForEach-Object { $_.Name; indent $_.Result; "" } 35 | } 36 | 37 | if ($Info.error_count.total) { 38 | title Errors 39 | $Info.result.errors | Select-Object 'Name', 'NuspecVersion', 'Error' | Format-Table | Out-String | Set-Variable r 40 | indent $r 2 41 | 42 | $Info.result.errors | ForEach-Object { $_.Name; indent $_.Error; "" } 43 | } 44 | 45 | 46 | if ($Info.result.ignored) { 47 | title Ignored 48 | $Info.result.ignored | Format-Table | Select-Object 'Name', 'NuspecVersion', 'IgnoreMessage' | Format-Table | Out-String | Set-Variable r 49 | indent $r 2 50 | } 51 | 52 | $ok = $Info.result.ok | Where-Object { !$_.Pushed } 53 | if ($ok) { 54 | title OK 55 | $ok | Select-Object 'Name', 'Updated', 'RemoteVersion', 'NuspecVersion' | Format-Table | Out-String | Set-Variable r 56 | indent $r 2 57 | 58 | $ok | ForEach-Object { $_.Name; indent $_.Result; "" } 59 | } 60 | 61 | -------------------------------------------------------------------------------- /tests/AUPackage.Tests.ps1: -------------------------------------------------------------------------------- 1 | remove-module Chocolatey-AU -ea ignore 2 | import-module $PSScriptRoot\..\Chocolatey-AU\Chocolatey-AU.psm1 # Tests require the private functions exported 3 | 4 | Describe 'AUPackage' -Tag aupackage { 5 | InModuleScope Chocolatey-AU { 6 | It 'throws an error when intanciating without a path' { 7 | { [AUPackage]::new('') } | Should Throw 'empty' 8 | } 9 | 10 | It 'throws an error when intanciating without a hashtable' { 11 | { [AUPackage]::new([hashtable] $null) } | Should Throw 'empty' 12 | } 13 | 14 | It 'can serialize and deserialize' { 15 | $expected = @{ 16 | Path = 'path' 17 | Name = 'name' 18 | Updated = $true 19 | Pushed = $true 20 | RemoteVersion = '1.2.3' 21 | NuspecVersion = '0.1.2' 22 | Result = 'result1,result2,result3' -split ',' 23 | Error = 'error' 24 | NuspecPath = 'nuspecPath' 25 | Ignored = $true 26 | IgnoreMessage = 'ignoreMessage' 27 | StreamsPath = 'streamsPath' 28 | Streams = [PSCustomObject] @{ 29 | '0.1' = @{ 30 | NuspecVersion = '0.1.2' 31 | Path = 'path' 32 | Name = 'name' 33 | Updated = $true 34 | RemoteVersion = '1.2.3' 35 | } 36 | '0.2' = @{ 37 | NuspecVersion = '0.2.2' 38 | Path = 'path' 39 | Name = 'name' 40 | Updated = $true 41 | RemoteVersion = '1.2.3' 42 | } 43 | } 44 | } 45 | 46 | $package = [AUPackage]::new($expected) 47 | $actual = $package.Serialize() 48 | 49 | $expected.Keys | Where-Object { $_ -ne 'Streams' } | ForEach-Object { 50 | $actual.$_ | Should Be $expected.$_ 51 | } 52 | $expected.Streams.psobject.Properties | ForEach-Object { 53 | $actual.Streams.$_ | Should Be $expected.Streams.$_ 54 | } 55 | } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /PSScriptAnalyzerSettings.psd1: -------------------------------------------------------------------------------- 1 | @{ 2 | IncludeRules = @( 3 | 'PSUseBOMForUnicodeEncodedFile', 4 | 'PSMisleadingBacktick', 5 | 'PSAvoidUsingCmdletAliases', 6 | 'PSAvoidTrailingWhitespace', 7 | 'PSAvoidSemicolonsAsLineTerminators', 8 | 'PSUseCorrectCasing', 9 | 'PSPlaceOpenBrace', 10 | 'PSPlaceCloseBrace', 11 | 'PSAlignAssignmentStatement', 12 | 'PSUseConsistentWhitespace', 13 | 'PSUseConsistentIndentation' 14 | ) 15 | 16 | Rules = @{ 17 | 18 | <# 19 | PSAvoidUsingCmdletAliases = @{ 20 | 'allowlist' = @('') 21 | }#> 22 | 23 | PSAvoidSemicolonsAsLineTerminators = @{ 24 | Enable = $true 25 | } 26 | 27 | PSUseCorrectCasing = @{ 28 | Enable = $true 29 | } 30 | 31 | PSPlaceOpenBrace = @{ 32 | Enable = $true 33 | OnSameLine = $true 34 | NewLineAfter = $true 35 | IgnoreOneLineBlock = $false 36 | } 37 | 38 | PSPlaceCloseBrace = @{ 39 | Enable = $true 40 | NewLineAfter = $true 41 | IgnoreOneLineBlock = $false 42 | NoEmptyLineBefore = $true 43 | } 44 | 45 | PSAlignAssignmentStatement = @{ 46 | Enable = $true 47 | CheckHashtable = $true 48 | } 49 | 50 | PSUseConsistentIndentation = @{ 51 | Enable = $true 52 | Kind = 'space' 53 | PipelineIndentation = 'IncreaseIndentationForFirstPipeline' 54 | IndentationSize = 4 55 | } 56 | 57 | PSUseConsistentWhitespace = @{ 58 | Enable = $true 59 | CheckInnerBrace = $true 60 | CheckOpenBrace = $true 61 | CheckOpenParen = $true 62 | CheckOperator = $true 63 | CheckPipe = $true 64 | CheckPipeForRedundantWhitespace = $false 65 | CheckSeparator = $true 66 | CheckParameter = $false 67 | IgnoreAssignmentOperatorInsideHashTable = $true 68 | } 69 | } 70 | } -------------------------------------------------------------------------------- /src/Plugins/Gist.ps1: -------------------------------------------------------------------------------- 1 | # Author: Miodrag Milic 2 | # Last Change: 10-Nov-2016. 3 | <# 4 | .SYNOPSIS 5 | Upload files to Github gist platform. 6 | 7 | .DESCRIPTION 8 | Plugin uploads one or more local files to the gist with the given id 9 | #> 10 | param( 11 | $Info, 12 | 13 | # Gist id, leave empty to create a new gist 14 | [string] $Id, 15 | 16 | # Github ApiKey, create in Github profile -> Settings -> Personal access tokens -> Generate new token 17 | # Make sure token has 'gist' scope set. 18 | [string] $ApiKey, 19 | 20 | # File paths to attach to gist 21 | [string[]] $Path, 22 | 23 | # Gist description 24 | [string] $Description = "Update-AUPackages Report #powershell #chocolatey", 25 | 26 | # GitHub API base url, overridable for GitHub Enterprise installations 27 | [string] $GitHubAPI = "https://api.github.com", 28 | 29 | # If the Gist should be created as public or not, ignored when Id is provided 30 | [bool] $PublicGist = $true 31 | ) 32 | 33 | # Create gist 34 | $gist = @{ 35 | description = $Description 36 | public = $PublicGist 37 | files = @{} 38 | } 39 | 40 | Get-ChildItem $Path | ForEach-Object { 41 | $name = Split-Path $_ -Leaf 42 | $content = Get-Content $_ -Raw 43 | $gist.files[$name] = @{content = "$content"} 44 | } 45 | 46 | # request 47 | 48 | #https://github.com/majkinetor/au/issues/142 49 | if ($PSVersionTable.PSVersion.major -ge 6) { 50 | $AvailableTls = [enum]::GetValues('Net.SecurityProtocolType') | Where-Object { $_ -ge 'Tls' } # PowerShell 6+ does not support SSL3, so use TLS minimum 51 | $AvailableTls.ForEach({[Net.ServicePointManager]::SecurityProtocol = [Net.ServicePointManager]::SecurityProtocol -bor $_}) 52 | } else { 53 | [System.Net.ServicePointManager]::SecurityProtocol = 3072 -bor 768 -bor [System.Net.SecurityProtocolType]::Tls -bor [System.Net.SecurityProtocolType]::Ssl3 54 | } 55 | 56 | $params = @{ 57 | ContentType = 'application/json' 58 | Method = if ($Id) { "PATCH" } else { "POST" } 59 | Uri = if ($Id) { "$GitHubAPI/gists/$Id" } else { "$GitHubAPI/gists" } 60 | Body = $gist | ConvertTo-Json 61 | UseBasicparsing = $true 62 | Headers = @{ 'Accept' = 'application/vnd.github.v3+json' } 63 | } 64 | 65 | if ($ApiKey) { 66 | $params.Headers['Authorization'] = ('Basic ' + [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes($ApiKey))) 67 | } 68 | 69 | $Response = Invoke-WebRequest @params 70 | if ($Response.StatusCode -in @(200, 201, 304)) { 71 | $JsonResponse = $Response.Content | ConvertFrom-Json 72 | $GistURL = $JsonResponse.html_url 73 | $Revision = $JsonResponse.history[0].version 74 | Write-Output "$GistURL/$Revision" 75 | } 76 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | 25 | 26 | ## Description Of Changes 27 | 28 | 29 | ## Motivation and Context 30 | 31 | 32 | ## Testing 33 | 37 | ### Operating Systems Testing 38 | 43 | 44 | ## Change Types Made 45 | 46 | 47 | * [ ] Bug fix (non-breaking change). 48 | * [ ] Feature / Enhancement (non-breaking change). 49 | * [ ] Breaking change (fix or feature that could cause existing functionality to change). 50 | * [ ] Documentation changes. 51 | * [ ] PowerShell code changes. 52 | 53 | ## Change Checklist 54 | 55 | * [ ] Requires a change to the documentation. 56 | * [ ] Documentation has been updated. 57 | * [ ] Tests to cover my changes, have been added. 58 | * [ ] All new and existing tests passed? 59 | * [ ] PowerShell code changes: PowerShell v3 compatibility checked? 60 | 61 | ## Related Issue 62 | 64 | 65 | Fixes # 66 | 67 | 68 | -------------------------------------------------------------------------------- /src/Plugins/History.ps1: -------------------------------------------------------------------------------- 1 | # Author: Miodrag Milic 2 | # Last Change: 09-Dec-2016. 3 | 4 | <# 5 | .SYNOPSIS 6 | Create update history as markdown report 7 | 8 | .DESCRIPTION 9 | Shows one date per line and all of the packages pushed to the Chocolatey community 10 | repository during that day. First letter of the package name links to report 11 | (produced by the Report plugin), the rest links to the actuall commit (produced by the Git plugin). 12 | #> 13 | param( 14 | $Info, 15 | 16 | #Number of dates to show in the report 17 | $Lines=30, 18 | 19 | #Github user repository, used to create commit links 20 | $Github_UserRepo = 'chocolatey/chocolatey-coreteampackages', 21 | 22 | #Package Source Repository Root URL. Use for non-github source repositories. (If specified used to create commit links instead of Github_UserRepo.) 23 | $PackageSourceRootUrl, 24 | 25 | #File path where to save the markdown report 26 | $Path = "Update-History.md" 27 | ) 28 | 29 | if (!$PackageSourceRootUrl) {$PackageSourceRootUrl = "https://github.com/$Github_UserRepo"} 30 | 31 | Write-Host "Saving history to $Path" 32 | 33 | $res=[System.Collections.Specialized.OrderedDictionary]@{} 34 | $log = git --no-pager log -q --grep '^AU: ' --date iso --no-merges --all | Out-String 35 | $all_commits = $log | Select-String 'commit(.|\n)+?(?=\ncommit )' -AllMatches 36 | foreach ($commit in $all_commits.Matches.Value) { 37 | $commit = $commit -split '\n' 38 | 39 | $id = $commit[0].Replace('commit','').Trim().Substring(0,7) 40 | $date = $commit[2].Replace('Date:','').Trim() 41 | $date = ([datetime]$date).Date.ToString("yyyy-MM-dd") 42 | $report = $commit[5].Replace('[skip ci]','').Trim() 43 | [array] $packages = ($commit[4] -replace '^\s+AU:.+?(-|:) |\[skip ci\]').Trim().ToLower() 44 | 45 | $packages_md = $packages -split ' ' | ForEach-Object { 46 | $first = $_.Substring(0,1).ToUpper(); $rest = $_.Substring(1) 47 | if ($report) { 48 | "[$first]($report)[$rest]($PackageSourceRootUrl/commit/$id)" 49 | } else { 50 | "[$_]($PackageSourceRootUrl/commit/$id)" 51 | } 52 | } 53 | 54 | if (!$res.Contains($date)) { $res.$date=@() } 55 | $res.$date += $packages_md 56 | } 57 | 58 | $res = $res.Keys | Select-Object -First $Lines | ForEach-Object { $r=[System.Collections.Specialized.OrderedDictionary]@{} } { $r[$_] = $res[$_] } {$r} 59 | 60 | $history = @" 61 | # Update History 62 | 63 | Showing maximum $Lines dates. 64 | Click on the first letter of the package name to see its report and on the remaining letters to see its git commit. 65 | 66 | --- 67 | 68 | "@ 69 | foreach ($kv in $res.GetEnumerator()) { $history += "`n{0} ({2}) {1}`n" -f "**$($kv.Key)**", "$($kv.Value -join ' – ')", $kv.Value.Length } 70 | $history | Out-File $Path 71 | -------------------------------------------------------------------------------- /.teamcity/settings.kts: -------------------------------------------------------------------------------- 1 | import jetbrains.buildServer.configs.kotlin.v2019_2.* 2 | import jetbrains.buildServer.configs.kotlin.v2019_2.buildFeatures.XmlReport 3 | import jetbrains.buildServer.configs.kotlin.v2019_2.buildFeatures.xmlReport 4 | import jetbrains.buildServer.configs.kotlin.v2019_2.buildFeatures.PullRequests 5 | import jetbrains.buildServer.configs.kotlin.v2019_2.buildFeatures.pullRequests 6 | import jetbrains.buildServer.configs.kotlin.v2019_2.buildSteps.powerShell 7 | import jetbrains.buildServer.configs.kotlin.v2019_2.triggers.vcs 8 | 9 | project { 10 | buildType(ChocolateyAU) 11 | } 12 | 13 | object ChocolateyAU : BuildType({ 14 | id = AbsoluteId("ChocolateyAU") 15 | name = "Build" 16 | 17 | artifactRules = """ 18 | +:code_drop/** 19 | """.trimIndent() 20 | 21 | params { 22 | param("env.vcsroot.branch", "%vcsroot.branch%") 23 | param("env.Git_Branch", "%teamcity.build.vcs.branch.ChocolateyAU_ChocolateyAUVcsRoot%") 24 | param("teamcity.git.fetchAllHeads", "true") 25 | password("env.POWERSHELLGALLERY_API_KEY", "credentialsJSON:a61d4adf-3db8-5bb0-848c-cd207665665f", display = ParameterDisplay.HIDDEN, readOnly = true) 26 | password("env.GITHUB_PAT", "%system.GitHubPAT%", display = ParameterDisplay.HIDDEN, readOnly = true) 27 | } 28 | 29 | vcs { 30 | root(DslContext.settingsRoot) 31 | 32 | branchFilter = """ 33 | +:* 34 | """.trimIndent() 35 | } 36 | 37 | steps { 38 | step { 39 | name = "Include Signing Keys" 40 | type = "PrepareSigningEnvironment" 41 | } 42 | powerShell { 43 | name = "Build Module" 44 | formatStderrAsError = true 45 | scriptMode = script { 46 | content = """ 47 | try { 48 | & .\build.ps1 -Task CI -Verbose -ErrorAction Stop 49 | } 50 | catch { 51 | ${'$'}_ | Out-String | Write-Host -ForegroundColor Red 52 | exit 1 53 | } 54 | """.trimIndent() 55 | } 56 | noProfile = false 57 | param("jetbrains_powershell_script_file", "build.ps1") 58 | } 59 | } 60 | 61 | triggers { 62 | vcs { 63 | branchFilter = """ 64 | 65 | """.trimIndent() 66 | } 67 | } 68 | 69 | features { 70 | xmlReport { 71 | reportType = XmlReport.XmlReportType.NUNIT 72 | rules = "code_drop/**/*.xml" 73 | } 74 | pullRequests { 75 | provider = github { 76 | authType = token { 77 | token = "%system.GitHubPAT%" 78 | } 79 | } 80 | } 81 | } 82 | }) 83 | -------------------------------------------------------------------------------- /chocolatey/tools/install.ps1: -------------------------------------------------------------------------------- 1 | #requires -version 2 2 | 3 | <# 4 | .SYNOPSIS 5 | Chocolatey-AU install script 6 | 7 | .NOTES 8 | Always install Chocolatey-AU versionless in Program Files to support older PowerShell versions ( v < 5 ) 9 | Multiple Chocolatey-AU versions can be installed using Install-Module if needed (on Posh 5+). 10 | #> 11 | param( 12 | #If given it is path to the module to be installed. 13 | #If not given, use first build directory and if doesn't exist, try scripts folder. 14 | [string] $module_path, 15 | 16 | #Remove module from the system. 17 | [switch] $Remove 18 | ) 19 | 20 | $ErrorActionPreference = 'Stop' 21 | 22 | $module_name = 'Chocolatey-AU' 23 | 24 | if ($PSVersionTable.PSEdition -ne "Core") { 25 | $module_dst = "$Env:ProgramFiles\WindowsPowerShell\Modules" 26 | } else { 27 | $module_dst = "$Env:ProgramFiles\PowerShell\Modules" 28 | } 29 | 30 | Remove-Item -Force -Recurse "$module_dst\$module_name" -ErrorAction ignore 31 | if ($Remove) { remove-module $module_name -ea ignore; Write-Host "Module $module_name removed"; return } 32 | 33 | Write-Host "`n==| Starting $module_name installation`n" 34 | 35 | if (!$module_path) { 36 | if (Test-Path $PSScriptRoot\_build\*) { 37 | $module_path = (Get-ChildItem $PSScriptRoot\_build\* -ea ignore | Sort-Object CreationDate -desc | Select-Object -First 1 -Expand FullName) + '/' + $module_name 38 | } else { 39 | $module_path = "$PSScriptRoot\$module_name" 40 | if (!(Test-Path $module_path)) { throw "module_path not specified and scripts directory doesn't contain the module" } 41 | } 42 | } 43 | $module_path = Resolve-Path $module_path 44 | 45 | if (!(Test-Path $module_path)) { throw "Module path invalid: '$module_path'" } 46 | 47 | Write-Host "Module path: '$module_path'" 48 | 49 | New-Item -ItemType Directory "$module_dst/$module_name" -ErrorAction Ignore | Out-Null 50 | 51 | Copy-Item -Recurse -Force $module_path $module_dst 52 | 53 | $res = Get-Module $module_name -ListAvailable | Where-Object { (Split-Path $_.ModuleBase) -eq $module_dst } 54 | if (!$res) { throw 'Module installation failed' } 55 | 56 | Write-Host "`n$($res.Name) version $($res.Version) installed successfully at '$module_dst\$module_name'" 57 | 58 | $functions = $res.ExportedFunctions.Keys 59 | 60 | import-module $module_dst\$module_name -force 61 | $aliases = get-alias | Where-Object { $_.Source -eq $module_name } 62 | 63 | if ($functions.Length) { 64 | $functions | ForEach-Object { 65 | [PSCustomObject]@{ Function = $_; Alias = $aliases | Where-Object Definition -eq $_ } 66 | } | ForEach-Object { Write-Host ("`n {0,-20} {1}`n -------- -----" -f 'Function', 'Alias') } { 67 | Write-Host (" {0,-20} {1}" -f $_.Function, "$($_.Alias)") 68 | } 69 | } 70 | 71 | remove-module $module_name 72 | Write-Host "`nTo learn more about ${module_name}: man about_${module_name}" 73 | Write-Host "See help for any function: man updateall`n" 74 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/zFeatureRequest.yml: -------------------------------------------------------------------------------- 1 | name: Enhancement / Feature Request 2 | description: Is there additional functionality you would love us to consider? 3 | labels: ["Enhancement"] 4 | 5 | body: 6 | - type: markdown 7 | attributes: 8 | value: | 9 | Ensure you have read over [Submitting Issues](https://github.com/chocolatey/.github/blob/main/SUBMITTING-ISSUES.md) and you are opening this issue in the correct repository. 10 | 11 | Please check to see if your problem already exists with a quick search of the issues. Start with one relevant term and then add others if you get too many results. 12 | 13 | **NOTE: Keep in mind we have a [Code Of Conduct](https://github.com/chocolatey/.github/blob/main/CODE_OF_CONDUCT.md) that we expect folks to observe when they are looking for support in the Chocolatey community.** 14 | 15 | Name your issue appropriately: give it a sentence that reads well enough for anyone seeing this in the release notes to know what it is. 16 | 17 | When writing out the issue details, please ensure you are writing it as if you were explaining it to somebody else, even if you will be working on and resolving the issue yourself. 18 | This helps others to understand the reasons for the issue and for it to be searchable in the future. 19 | - type: checkboxes 20 | attributes: 21 | label: Checklist 22 | description: Before continuing, make sure you have done the following. 23 | options: 24 | - label: I have verified this is the correct repository for opening this issue. 25 | required: true 26 | - label: I have verified no other issues exist related to my request. 27 | required: true 28 | - type: textarea 29 | id: problem-related 30 | attributes: 31 | label: Is Your Feature Request Related To A Problem? Please describe. 32 | description: | 33 | In your own words, please describe the problem that would be fixed by introducing the feature or enhancement you request. 34 | validations: 35 | required: false 36 | - type: textarea 37 | id: solution 38 | attributes: 39 | label: Describe The Solution. Why is it needed? 40 | description: | 41 | In your own words, please describe the solution and what you want to happen. 42 | validations: 43 | required: true 44 | - type: textarea 45 | id: additional-context 46 | attributes: 47 | label: Additional Context 48 | description: | 49 | Please include any other information here that you feel may be relevant to the feature you want implemented that is not covered in the previous sections. 50 | - type: textarea 51 | id: related-issues 52 | attributes: 53 | label: Related Issues 54 | description: | 55 | Include any links to other issues that are related to this request. 56 | placeholder: | 57 | - Issue # 58 | - Issue # 59 | validations: 60 | required: false -------------------------------------------------------------------------------- /src/Plugins/Report/markdown_funcs.ps1: -------------------------------------------------------------------------------- 1 | function md_fix_newline($Text) { 2 | $Text -replace "\.`n", "\.`n " | Out-String 3 | } 4 | 5 | function md_title($Title, $Level=2 ) { 6 | "" 7 | "#"*$Level + ' ' + $Title | Out-String 8 | "" 9 | } 10 | 11 | function md_code($Text) { 12 | "`n" + '```' 13 | ($Text -join "`n").Trim() 14 | '```' + "`n" 15 | } 16 | 17 | function md_table($result, $Columns, $MaxErrorLength=150) { 18 | if (!$Columns) { $Columns = 'Name', 'Updated', 'Pushed', 'RemoteVersion', 'NuspecVersion', 'Error' } 19 | $res = '|' + ($Columns -join '|') + "|`r`n" 20 | $res += ((1..$Columns.Length | ForEach-Object { '|---' }) -join '') + "|`r`n" 21 | if ( !$au_GalleryPackageRootUrl ) { 22 | $au_GalleryPackageRootUrl = if ($env:au_GalleryPackageRootUrl) { $env:au_GalleryPackageRootUrl } else { 23 | if ($au_GalleryUrl) { "$au_GalleryUrl/packages" } else { 'https://chocolatey.org/packages' } 24 | } 25 | } 26 | 27 | $result | ForEach-Object { 28 | $o = $_ | Select-Object ` 29 | @{ N='Icon' 30 | E={'' -f $_.NuspecXml.package.metadata.iconUrl, $IconSize } 31 | }, 32 | @{ N='Name' 33 | E={"[{0}]($au_GalleryPackageRootUrl/{0}/{1})" -f $_.Name, $(if ($_.Updated) { $_.RemoteVersion } else {$_.NuspecVersion }) } 34 | }, 35 | @{ N='Updated' 36 | E={ 37 | $r = "[{0}](#{1})" -f $_.Updated, $_.Name.Replace('.','').ToLower() 38 | $r += if ($_.Updated) { ' 🔸' } 39 | $r += if ($_.Streams) { ' 🕄' } 40 | $r += if (Get-ChildItem $_.Path -Recurse -Include VERIFICATION.txt) { ' 📥' } 41 | $r 42 | } 43 | }, 44 | 'Pushed', 45 | @{ N='RemoteVersion' 46 | E={"[{0}]({1})" -f $_.RemoteVersion, $_.NuspecXml.package.metadata.projectUrl } 47 | }, 48 | @{ N='NuspecVersion' 49 | E={"[{0}]({1})" -f $_.NuspecVersion, $_.NuspecXml.package.metadata.packageSourceUrl } 50 | }, 51 | @{ N='Error' 52 | E={ 53 | $err = ("$($_.Error)" -replace "`r?`n", '; ').Trim() 54 | if ($err) { 55 | if ($err.Length -gt $MaxErrorLength) { $err = $err.Substring(0,$MaxErrorLength) + ' ...' } 56 | "[{0}](#{1})" -f $err, $_.Name.ToLower() 57 | } 58 | } 59 | }, 60 | 'Ignored', 61 | 'IgnoreMessage' 62 | 63 | $res += ((1..$Columns.Length | ForEach-Object { $col = $Columns[$_-1]; '|' + $o.$col }) -join '') + "|`r`n" 64 | } 65 | 66 | $res 67 | } 68 | -------------------------------------------------------------------------------- /src/Plugins/PullRequest.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | Creates a GitHub pull request for the updated packages. 4 | 5 | .DESCRIPTION 6 | This plugin will open a GitHub pull request for the commits created by the Git plugin, which of course needs to run first. 7 | It has options to add assignees and reviewers to the created pull request and, supports on-prem GitHub Enterprise Server. 8 | #> 9 | param( 10 | $Info, 11 | 12 | # Git branch to create a GitHub pull request for 13 | [string]$Branch, 14 | 15 | # Target Git branch for the GitHub pull request 16 | [string]$BaseBranch = "master", 17 | 18 | # GitHub usernames to be added to the list of assignees 19 | [string[]]$Assignees = @(), 20 | 21 | # GitHub usernames to be added to the list of reviewers 22 | [string[]]$Reviewers = @(), 23 | 24 | # GitHub team slugs to be added to the list of reviewers 25 | [string[]]$TeamReviewers = @(), 26 | 27 | # GitHub API base URL, overridable for GitHub Enterprise installations 28 | [string]$GitHubAPI = "https://api.github.com", 29 | 30 | # Github ApiKey, create in GitHub profile -> Settings -> Personal access tokens -> Generate new token 31 | [string]$ApiKey 32 | ) 33 | 34 | if ($Info.result.updated.Length -eq 0) { Write-Host "No package updated, skipping"; return } 35 | 36 | $ErrorActionPreference = "Stop" 37 | 38 | $origin = git config --get remote.origin.url 39 | $originParts = $origin -split {$_ -eq "/" -or $_ -eq ":"} 40 | $owner = $originParts[-2] 41 | $repo = $originParts[-1] -replace "\.git$", "" 42 | 43 | #https://github.com/majkinetor/au/issues/142 44 | if ($PSVersionTable.PSVersion.major -ge 6) { 45 | $AvailableTls = [enum]::GetValues('Net.SecurityProtocolType') | Where-Object { $_ -ge 'Tls' } # PowerShell 6+ does not support SSL3, so use TLS minimum 46 | $AvailableTls.ForEach({[Net.ServicePointManager]::SecurityProtocol = [Net.ServicePointManager]::SecurityProtocol -bor $_}) 47 | } else { 48 | [System.Net.ServicePointManager]::SecurityProtocol = 3072 -bor 768 -bor [System.Net.SecurityProtocolType]::Tls -bor [System.Net.SecurityProtocolType]::Ssl3 49 | } 50 | 51 | $data = @{ 52 | title = git log -1 --pretty="%s" 53 | head = $Branch 54 | base = $BaseBranch 55 | } 56 | $params = @{ 57 | ContentType = 'application/json' 58 | Method = "POST" 59 | Uri = "$GitHubAPI/repos/$owner/$repo/pulls" 60 | Body = $data | ConvertTo-Json 61 | UseBasicparsing = $true 62 | Headers = @{ 63 | 'Accept' = 'application/vnd.github.v3+json' 64 | 'Authorization' = ('Basic ' + [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes($ApiKey))) 65 | } 66 | } 67 | $response = Invoke-WebRequest @params 68 | $jsonResponse = $response.Content | ConvertFrom-Json 69 | $prUrl = $jsonResponse.html_url 70 | $prNumber = $jsonResponse.number 71 | 72 | if ($Assignees) { 73 | $data = @{ 74 | assignees = $Assignees 75 | } 76 | $params['Uri'] = "$GitHubAPI/repos/$owner/$repo/issues/$prNumber/assignees" 77 | $params['Body'] = $data | ConvertTo-Json 78 | $response = Invoke-WebRequest @params 79 | } 80 | 81 | if ($Reviewers -or $TeamReviewers) { 82 | $data = @{ 83 | reviewers = $Reviewers 84 | team_reviewers = $TeamReviewers 85 | } 86 | $params['Uri'] = "$GitHubAPI/repos/$owner/$repo/pulls/$prNumber/requested_reviewers" 87 | $params['Body'] = $data | ConvertTo-Json 88 | $response = Invoke-WebRequest @params 89 | } 90 | 91 | Write-Host "Pull request sucessfully created: $prUrl" 92 | -------------------------------------------------------------------------------- /src/Plugins/GitLab.ps1: -------------------------------------------------------------------------------- 1 | # Author: Josh Ameli 2 | # Based off of the Git plugin by Miodrag Milic 3 | # Last Change: 20-Aug-2019. 4 | 5 | # https://www.appveyor.com/docs/how-to/git-push/ 6 | 7 | param( 8 | $Info, 9 | 10 | # GitLab username 11 | [string] $User, 12 | 13 | # GitLab API key. 14 | [string] $API_Key, 15 | 16 | # Repository HTTP(S) URL 17 | [string]$PushURL, 18 | 19 | # Force git commit when package is updated but not pushed. 20 | [switch] $Force, 21 | 22 | # Commit strategy: 23 | # single - 1 commit with all packages 24 | # atomic - 1 commit per package 25 | # atomictag - 1 commit and tag per package 26 | [ValidateSet('single', 'atomic', 'atomictag')] 27 | [string]$commitStrategy = 'single', 28 | 29 | # Branch name 30 | [string]$Branch = 'master' 31 | ) 32 | 33 | [array]$packages = if ($Force) { $Info.result.updated } else { $Info.result.pushed } 34 | if ($packages.Length -eq 0) { Write-Host "No package updated, skipping"; return } 35 | 36 | $root = Split-Path $packages[0].Path 37 | 38 | Push-Location $root 39 | $origin = git config --get remote.origin.url 40 | $origin -match '(?<=:/+)[^/]+' | Out-Null 41 | $machine = $Matches[0] 42 | 43 | ### Construct RepoURL to be set as new origin 44 | $RepoURL = ( 45 | $PushURL.split('://')[0] ` 46 | + "://" ` 47 | + $User ` 48 | + ":" ` 49 | + $API_Key ` 50 | + "@" ` 51 | + $PushURL.TrimStart( 52 | $( 53 | $PushURL.split('://')[0] ` 54 | + "://" 55 | ) 56 | ) 57 | ) 58 | 59 | ### Set new push URL 60 | git remote set-url origin $RepoURL 61 | 62 | ### Ensure local is up-to-date to avoid conflicts 63 | Write-Host "Executing git pull" 64 | git checkout -q $Branch 65 | git pull -q origin $Branch 66 | 67 | ### Commit 68 | if ($commitStrategy -like 'atomic*') { 69 | $packages | ForEach-Object { 70 | Write-Host "Adding update package to git repository: $($_.Name)" 71 | git add -u $_.Path 72 | git status 73 | 74 | Write-Host "Commiting $($_.Name)" 75 | $message = "AU: $($_.Name) upgraded from $($_.NuspecVersion) to $($_.RemoteVersion)" 76 | $gist_url = $Info.plugin_results.Gist -split '\n' | Select-Object -Last 1 77 | $snippet_url = $Info.plugin_results.Snippet -split '\n' | Select-Object -Last 1 78 | git commit -m "$message`n[skip ci] $gist_url $snippet_url" --allow-empty 79 | 80 | if ($commitStrategy -eq 'atomictag') { 81 | $tagcmd = "git tag -a $($_.Name)-$($_.RemoteVersion) -m '$($_.Name)-$($_.RemoteVersion)'" 82 | Invoke-Expression $tagcmd 83 | } 84 | } 85 | } 86 | else { 87 | Write-Host "Adding updated packages to git repository: $( $packages | % Name)" 88 | $packages | ForEach-Object { git add -u $_.Path } 89 | git status 90 | 91 | Write-Host "Commiting" 92 | $message = "AU: $($packages.Length) updated - $($packages | % Name)" 93 | $gist_url = $Info.plugin_results.Gist -split '\n' | Select-Object -Last 1 94 | $snippet_url = $Info.plugin_results.Snippet -split '\n' | Select-Object -Last 1 95 | git commit -m "$message`n[skip ci] $gist_url $snippet_url" --allow-empty 96 | 97 | } 98 | 99 | ### Push 100 | Write-Host "Pushing changes" 101 | git push -q 102 | if ($commitStrategy -eq 'atomictag') { 103 | write-host 'Atomic Tag Push' 104 | git push -q --tags 105 | } 106 | Pop-Location 107 | 108 | git remote set-url origin $origin 109 | -------------------------------------------------------------------------------- /src/Plugins/Git.ps1: -------------------------------------------------------------------------------- 1 | # Author: Miodrag Milic 2 | # Last Change: 09-Nov-2016. 3 | 4 | # https://www.appveyor.com/docs/how-to/git-push/ 5 | 6 | param( 7 | $Info, 8 | 9 | # Git username 10 | [string] $User, 11 | 12 | # Git password. You can use Github Token here if you omit username. 13 | [string] $Password, 14 | 15 | # Force git commit when package is updated but not pushed. 16 | [switch] $Force, 17 | 18 | # Add the package to the repository if it was created during the update process. 19 | [switch] $AddNew, 20 | 21 | # Commit strategy: 22 | # single - 1 commit with all packages 23 | # atomic - 1 commit per package 24 | # atomictag - 1 commit and tag per package 25 | [ValidateSet('single', 'atomic', 'atomictag')] 26 | [string]$commitStrategy = 'single', 27 | 28 | # Branch name 29 | [string]$Branch = 'master' 30 | ) 31 | 32 | [array]$packages = if ($Force) { $Info.result.updated } else { $Info.result.pushed } 33 | if ($packages.Length -eq 0) { Write-Host "No package updated, skipping"; return } 34 | 35 | $root = Split-Path $packages[0].Path 36 | Push-Location $root 37 | $origin = git config --get remote.origin.url 38 | $origin -match '(?<=:/+)[^/]+' | Out-Null 39 | $machine = $Matches[0] 40 | 41 | if ($User -and $Password) { 42 | Write-Host "Setting credentials for: $machine" 43 | 44 | if ( "machine $server" -notmatch (Get-Content ~/_netrc)) { 45 | Write-Host "Credentials already found for machine: $machine" 46 | } 47 | "machine $machine", "login $User", "password $Password" | Out-File -Append ~/_netrc -Encoding ascii 48 | } elseif ($Password) { 49 | Write-Host "Setting oauth token for: $machine" 50 | git config --global credential.helper store 51 | Add-Content "$env:USERPROFILE\.git-credentials" "https://${Password}:x-oauth-basic@$machine`n" 52 | } 53 | 54 | Write-Host "Checking out & resetting $Branch branch" 55 | git checkout -q -B $Branch 56 | 57 | Write-Host "Executing git pull" 58 | git pull -q origin $Branch 59 | 60 | $gitAddArgs = @() 61 | if (-not $AddNew) 62 | { 63 | $gitAddArgs += @('--update') 64 | } 65 | 66 | if ($commitStrategy -like 'atomic*') { 67 | $packages | ForEach-Object { 68 | Write-Host "Adding update package to git repository: $($_.Name)" 69 | git add @gitAddArgs $_.Path 70 | git status 71 | 72 | Write-Host "Commiting $($_.Name)" 73 | $message = "AU: $($_.Name) upgraded from $($_.NuspecVersion) to $($_.RemoteVersion)" 74 | $gist_url = $Info.plugin_results.Gist -split '\n' | Select-Object -Last 1 75 | $snippet_url = $Info.plugin_results.Snippet -split '\n' | Select-Object -Last 1 76 | git commit -m "$message`n[skip ci] $gist_url $snippet_url" --allow-empty 77 | 78 | if ($commitStrategy -eq 'atomictag') { 79 | $tagcmd = "git tag -a $($_.Name)-$($_.RemoteVersion) -m '$($_.Name)-$($_.RemoteVersion)'" 80 | Invoke-Expression $tagcmd 81 | } 82 | } 83 | } 84 | else { 85 | Write-Host "Adding updated packages to git repository: $( $packages | % Name)" 86 | $packages | ForEach-Object { git add @gitAddArgs $_.Path } 87 | git status 88 | 89 | Write-Host "Commiting" 90 | $message = "AU: $($packages.Length) updated - $($packages | % Name)" 91 | $gist_url = $Info.plugin_results.Gist -split '\n' | Select-Object -Last 1 92 | $snippet_url = $Info.plugin_results.Snippet -split '\n' | Select-Object -Last 1 93 | git commit -m "$message`n[skip ci] $gist_url $snippet_url" --allow-empty 94 | 95 | } 96 | Write-Host "Pushing changes" 97 | git push -q origin $Branch 98 | if ($commitStrategy -eq 'atomictag') { 99 | write-host 'Atomic Tag Push' 100 | git push -q --tags 101 | } 102 | Pop-Location 103 | -------------------------------------------------------------------------------- /src/Plugins/Report/markdown.ps1: -------------------------------------------------------------------------------- 1 | . (Join-Path $PSScriptRoot 'markdown_funcs.ps1') 2 | 3 | $Github_UserRepo = $Params.Github_UserRepo 4 | $UserMessage = $Params.UserMessage 5 | $NoAppVeyor = $Params.NoAppVeyor 6 | $IconSize = if ($Params.IconSize) { $Params.IconSize } else { 32 } 7 | $NoIcons = $Params.NoIcons 8 | $Title = if ($Params.Title) { $Params.Title } else { 'Update-AUPackages' } 9 | 10 | # Optional Parameters for non github.com source code repositories 11 | # If PackageSourceRoot is specified, links will be drived from it instead of $Github_UserRepo 12 | $PackageSourceRootUrl = if ($Params.PackageSourceRootUrl) { $Params.PackageSourceRootUrl } elseif ($Params.Github_UserRepo) { "https://github.com/$Github_UserRepo" } else { 'https://github.com/majkinetor/au-packages-template' } 13 | $PackageSourceBranch = if ($Params.PackageSourceBranch) { $Params.PackageSourceBranch } else { 'master' } 14 | 15 | #======================================================================================= 16 | 17 | $now = $Info.startTime.ToUniversalTime().ToString('yyyy-MM-dd HH:mm') 18 | $au_version = Get-Module Chocolatey-AU -ListAvailable | ForEach-Object Version | Select-Object -First 1 | ForEach-Object { "$_" } 19 | $package_no = $Info.result.all.Length 20 | 21 | $update_all_url = "$PackageSourceRootUrl/blob/$PackageSourceBranch/update_all.ps1" 22 | 23 | $icon_ok = 'https://cdn.jsdelivr.net/gh/majkinetor/au@master/AU/Plugins/Report/r_ok.png' 24 | $icon_er = 'https://cdn.jsdelivr.net/gh/majkinetor/au@master/AU/Plugins/Report/r_er.png' 25 | 26 | "# $Title" 27 | 28 | #=== Header =============================== 29 | if (!$NoAppVeyor -and $Github_UserRepo) { "[![](https://ci.appveyor.com/api/projects/status/github/${Github_UserRepo}?svg=true)](https://ci.appveyor.com/project/$Github_UserRepo/build/$Env:APPVEYOR_BUILD_NUMBER)" } 30 | 31 | @" 32 | [![$package_no](https://img.shields.io/badge/AU%20packages-$($package_no)-red.svg)](#ok) 33 | [![$au_version](https://img.shields.io/badge/AU-$($au_version)-blue.svg)](https://www.powershellgallery.com/packages/AU) 34 | [![](http://transparent-favicon.info/favicon.ico)](#)[![](http://transparent-favicon.info/favicon.ico)](#) 35 | **UTC**: $now [![](http://transparent-favicon.info/favicon.ico)](#) [$Github_UserRepo]($PackageSourceRootUrl) 36 | 37 | _This file is automatically generated by the [update_all.ps1]($update_all_url) script using the [Chocolatey-AU module](https://github.com/chocolatey-community/chocolatey-au)._ 38 | "@ 39 | 40 | "`n$UserMessage`n" 41 | 42 | #=== Body =============================== 43 | 44 | $errors_word = if ($Info.error_count.total -eq 1) {'error'} else {'errors' } 45 | if ($Info.error_count.total) { 46 | " **LAST RUN HAD $($Info.error_count.total) [$($errors_word.ToUpper())](#errors) !!!**" } 47 | else { 48 | " **Last run was OK**" 49 | } 50 | 51 | "" 52 | md_fix_newline $Info.stats 53 | 54 | $columns = 'Icon', 'Name', 'Updated', 'Pushed', 'RemoteVersion', 'NuspecVersion' 55 | if ($NoIcons) { $columns = $columns[1.10] } 56 | if ($Info.pushed) { 57 | md_title Pushed 58 | md_table $Info.result.pushed -Columns $columns 59 | } 60 | 61 | if ($Info.error_count.total) { 62 | md_title Errors 63 | md_table $Info.result.errors -Columns ($columns + 'Error' | Where-Object { ('Updated', 'Pushed') -notcontains $_ } ) 64 | $Info.result.errors | ForEach-Object { 65 | md_title $_.Name -Level 3 66 | md_code "$($_.Error)" 67 | } 68 | } 69 | 70 | if ($Info.result.ignored) { 71 | md_title Ignored 72 | md_table $Info.result.ignored -Columns 'Icon', 'Name', 'NuspecVersion', 'IgnoreMessage' 73 | } 74 | 75 | if ($Info.result.ok) { 76 | md_title OK 77 | md_table $Info.result.ok -Columns $columns 78 | $Info.result.ok | ForEach-Object { 79 | md_title $_.Name -Level 3 80 | md_code $_.Result 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /src/Public/Get-RemoteFiles.ps1: -------------------------------------------------------------------------------- 1 | # Author: Miodrag Milic 2 | # Last Change: 22-Feb-2017. 3 | 4 | <# 5 | .SYNOPSIS 6 | Get Latest URL32 and/or URL64 into tools directory. 7 | 8 | .DESCRIPTION 9 | This function will download the binaries pointed to by $Latest.URL32 and $Latest.URL64. 10 | The function is used to embed binaries into the Chocolatey package. 11 | 12 | The function will keep original remote file name but it will add suffix _x32 or _x64. 13 | This is intentional because you can use those to match particular installer via wildcards, 14 | e.g. `gi *_x32.exe`. 15 | 16 | #> 17 | function Get-RemoteFiles { 18 | param ( 19 | # Delete existing file having $Latest.FileType extension. 20 | # Otherwise, when state of the package remains after the update, older installers 21 | # will pile up and may get included in the updated package. 22 | [switch] $Purge, 23 | 24 | # Do not add arch suffix (_x32 or _64) at the end of the filename 25 | [switch] $NoSuffix, 26 | 27 | # Override remote file name, use this one as a base. Suffixes _x32/_x64 are added. 28 | # Use this parameter if remote URL doesn't contain file name but generated hash. 29 | [string] $FileNameBase, 30 | 31 | # By default last URL part is used as a file name. Use this paramter to skip parts 32 | # if file name is specified earlier in the path. 33 | [int] $FileNameSkip=0, 34 | 35 | # Sets the algorithm to use when calculating checksums 36 | # This defaults to sha256 37 | [ValidateSet('md5','sha1','sha256','sha384','sha512')] 38 | [string] $Algorithm = 'sha256' 39 | ) 40 | 41 | function name4url($url) { 42 | if ($FileNameBase) { return $FileNameBase } 43 | $res = $url -split '/' | Select-Object -Last 1 -Skip $FileNameSkip 44 | $res -replace '\.[^.]+$' 45 | } 46 | 47 | function ext() { 48 | if ($Latest.FileType) { return $Latest.FileType } 49 | $url = $Latest.Url32; if (!$url) { $url = $Latest.Url64 } 50 | if ($url -match '(?<=\.)[^.]+$') { return $Matches[0] } 51 | } 52 | 53 | New-Item -Type Directory tools -ea 0 | Out-Null 54 | $toolsPath = Resolve-Path tools 55 | 56 | $ext = ext 57 | if (!$ext) { throw 'Unknown file type' } 58 | 59 | if ($Purge) { 60 | Write-Host 'Purging' $ext 61 | $purgePath = "$toolsPath{0}*.$ext" -f [IO.Path]::DirectorySeparatorChar 62 | Remove-Item -Force $purgePath -ea ignore 63 | } 64 | 65 | function headers($client) { 66 | if ($Latest.Options.Headers) { 67 | $Latest.Options.Headers.GetEnumerator() | ForEach-Object { $client.Headers.Add($_.Key, $_.Value) | Out-Null } 68 | } 69 | } 70 | 71 | try { 72 | $client = New-Object System.Net.WebClient 73 | 74 | if ($Latest.Url32) { 75 | headers($client) 76 | $base_name = name4url $Latest.Url32 77 | $file_name = "{0}{2}.{1}" -f $base_name, $ext, $(if ($NoSuffix) { '' } else {'_x32'}) 78 | $file_path = Join-Path $toolsPath $file_name 79 | 80 | Write-Host "Downloading to $file_name -" $Latest.Url32 81 | $client.DownloadFile($Latest.URL32, $file_path) 82 | $global:Latest.Checksum32 = Get-FileHash $file_path -Algorithm $Algorithm | ForEach-Object Hash 83 | $global:Latest.ChecksumType32 = $Algorithm 84 | $global:Latest.FileName32 = $file_name 85 | } 86 | 87 | if ($Latest.Url64) { 88 | headers($client) 89 | $base_name = name4url $Latest.Url64 90 | $file_name = "{0}{2}.{1}" -f $base_name, $ext, $(if ($NoSuffix) { '' } else {'_x64'}) 91 | $file_path = Join-Path $toolsPath $file_name 92 | 93 | Write-Host "Downloading to $file_name -" $Latest.Url64 94 | $client.DownloadFile($Latest.URL64, $file_path) 95 | $global:Latest.Checksum64 = Get-FileHash $file_path -Algorithm $Algorithm | ForEach-Object Hash 96 | $global:Latest.ChecksumType64 = $Algorithm 97 | $global:Latest.FileName64 = $file_name 98 | } 99 | } catch{ throw $_ } finally { $client.Dispose() } 100 | } 101 | -------------------------------------------------------------------------------- /src/Private/AUPackage.ps1: -------------------------------------------------------------------------------- 1 | class AUPackage { 2 | [string] $Path 3 | [string] $Name 4 | [bool] $Updated 5 | [bool] $Pushed 6 | [string] $RemoteVersion 7 | [string] $NuspecVersion 8 | [string[]] $Result 9 | [string] $Error 10 | [string] $NuspecPath 11 | [xml] $NuspecXml 12 | [bool] $Ignored 13 | [string] $IgnoreMessage 14 | [string] $StreamsPath 15 | [System.Collections.Specialized.OrderedDictionary] $Streams 16 | 17 | AUPackage([string] $Path ){ 18 | if ([String]::IsNullOrWhiteSpace( $Path )) { throw 'Package path can not be empty' } 19 | 20 | $this.Path = $Path 21 | $this.Name = Split-Path -Leaf $Path 22 | 23 | $this.NuspecPath = '{0}{2}{1}.nuspec' -f $this.Path, $this.Name, [IO.Path]::DirectorySeparatorChar 24 | if (!(Get-Item $this.NuspecPath -ea ignore)) { throw 'No nuspec file found in the package directory' } 25 | 26 | $this.NuspecXml = [AUPackage]::LoadNuspecFile( $this.NuspecPath ) 27 | $this.NuspecVersion = $this.NuspecXml.package.metadata.version 28 | 29 | $this.StreamsPath = '{0}{2}{1}.json' -f $this.Path, $this.Name, [IO.Path]::DirectorySeparatorChar 30 | $this.Streams = [AUPackage]::LoadStreams( $this.StreamsPath ) 31 | } 32 | 33 | [hashtable] GetStreamDetails() { 34 | return @{ 35 | Path = $this.Path 36 | Name = $this.Name 37 | Updated = $this.Updated 38 | RemoteVersion = $this.RemoteVersion 39 | } 40 | } 41 | 42 | static [xml] LoadNuspecFile( $NuspecPath ) { 43 | $nu = New-Object xml 44 | $nu.PSBase.PreserveWhitespace = $true 45 | $nu.Load($NuspecPath) 46 | return $nu 47 | } 48 | 49 | SaveNuspec(){ 50 | $Utf8NoBomEncoding = New-Object System.Text.UTF8Encoding($False) 51 | [System.IO.File]::WriteAllText($this.NuspecPath, $this.NuspecXml.InnerXml, $Utf8NoBomEncoding) 52 | } 53 | 54 | static [System.Collections.Specialized.OrderedDictionary] LoadStreams( $streamsPath ) { 55 | if (!(Test-Path $streamsPath)) { return $null } 56 | $res = [System.Collections.Specialized.OrderedDictionary] @{} 57 | $versions = Get-Content $streamsPath | ConvertFrom-Json 58 | $versions.psobject.Properties | ForEach-Object { 59 | $stream = $_.Name 60 | $res.Add($stream, @{ NuspecVersion = $versions.$stream }) 61 | } 62 | return $res 63 | } 64 | 65 | UpdateStream( $stream, $version ){ 66 | $s = $stream.ToString() 67 | $v = $version.ToString() 68 | if (!$this.Streams) { $this.Streams = [System.Collections.Specialized.OrderedDictionary] @{} } 69 | if (!$this.Streams.Contains($s)) { $this.Streams.$s = @{} } 70 | if ($this.Streams.$s -ne 'ignore') { $this.Streams.$s.NuspecVersion = $v } 71 | $versions = [System.Collections.Specialized.OrderedDictionary] @{} 72 | $this.Streams.Keys | ForEach-Object { 73 | $versions.Add($_, $this.Streams.$_.NuspecVersion) 74 | } 75 | $versions | ConvertTo-Json | Set-Content $this.StreamsPath -Encoding UTF8 76 | } 77 | 78 | Backup() { 79 | $d = ([System.IO.Path]::Combine([System.IO.Path]::GetTempPath(), 'au', $this.Name)) 80 | 81 | Remove-Item (Join-Path $d '*') -Recurse -ea 0 82 | Copy-Item . (Join-Path $d '_backup') -Recurse 83 | } 84 | 85 | [string] SaveAndRestore() { 86 | $d = ([System.IO.Path]::Combine([System.IO.Path]::GetTempPath(), 'au', $this.Name)) 87 | 88 | Copy-Item . (Join-Path $d '_output') -Recurse 89 | Remove-Item (Join-Path '.' '*') -Recurse 90 | Copy-Item ([System.IO.Path]::Combine($d, '_backup', '*')) . -Recurse 91 | 92 | return (Join-Path $d '_output') 93 | } 94 | 95 | AUPackage( [hashtable] $obj ) { 96 | if (!$obj) { throw 'Obj can not be empty' } 97 | $obj.Keys | Where-Object { $_ -ne 'Streams' } | ForEach-Object { 98 | $this.$_ = $obj.$_ 99 | } 100 | if ($obj.Streams) { 101 | $this.Streams = [System.Collections.Specialized.OrderedDictionary] @{} 102 | $obj.Streams.psobject.Properties | ForEach-Object { 103 | $this.Streams.Add($_.Name, $_.Value) 104 | } 105 | } 106 | } 107 | 108 | [hashtable] Serialize() { 109 | $res = @{} 110 | $this | Get-Member -Type Properties | Where-Object { $_.Name -ne 'Streams' } | ForEach-Object { 111 | $property = $_.Name 112 | $res.Add($property, $this.$property) 113 | } 114 | if ($this.Streams) { 115 | $res.Add('Streams', [PSCustomObject] $this.Streams) 116 | } 117 | return $res 118 | } 119 | } 120 | -------------------------------------------------------------------------------- /src/Public/Test-Package.ps1: -------------------------------------------------------------------------------- 1 | # Author: Miodrag Milic 2 | # Last Change: 15-Nov-2016. 3 | 4 | <# 5 | .SYNOPSIS 6 | Test Chocolatey package 7 | 8 | .DESCRIPTION 9 | The function can test install, uninistall or both and provide package parameters during test. 10 | It will force install and then remove the Chocolatey package if called without arguments. 11 | 12 | It accepts either nupkg or nuspec path. If none specified, current directory will be searched 13 | for any of them. 14 | 15 | .EXAMPLE 16 | Test-Package -Install 17 | 18 | Test the install of the package from the current directory. 19 | 20 | .LINK 21 | https://github.com/chocolatey/choco/wiki/CreatePackages#testing-your-package 22 | #> 23 | function Test-Package { 24 | param( 25 | # If file, path to the .nupkg or .nuspec file for the package. 26 | # If directory, latest .nupkg or .nuspec file wil be looked in it. 27 | # If ommited current directory will be used. 28 | $Nu, 29 | 30 | # Test chocolateyInstall.ps1 only. 31 | [switch] $Install, 32 | 33 | # Test chocolateyUninstall.ps1 only. 34 | [switch] $Uninstall, 35 | 36 | # Package parameters 37 | [string] $Parameters, 38 | 39 | # Path to chocolatey-test-environment: https://github.com/majkinetor/chocolatey-test-environment 40 | [string] $Vagrant = $Env:au_Vagrant, 41 | 42 | # Open new shell window 43 | [switch] $VagrantOpen, 44 | 45 | # Do not remove existing packages from vagrant package directory 46 | [switch] $VagrantNoClear 47 | ) 48 | 49 | if (!$Install -and !$Uninstall) { $Install = $true } 50 | 51 | if (!$Nu) { $dir = Get-Item $pwd } 52 | else { 53 | if (!(Test-Path $Nu)) { throw "Path not found: $Nu" } 54 | $Nu = Get-Item $Nu 55 | $dir = if ($Nu.PSIsContainer) { $Nu; $Nu = $null } else { $Nu.Directory } 56 | } 57 | 58 | if (!$Nu) { 59 | $Nu = Get-Item $dir/*.nupkg | Sort-Object -Property CreationTime -Descending | Select-Object -First 1 60 | if (!$Nu) { $Nu = Get-Item $dir/*.nuspec } 61 | if (!$Nu) { throw "Can't find nupkg or nuspec file in the directory" } 62 | } 63 | 64 | if ($Nu.Extension -eq '.nuspec') { 65 | Write-Host "Nuspec file given, running choco pack" 66 | choco pack -r $Nu.FullName --OutputDirectory $Nu.DirectoryName | Write-Host 67 | if ($LASTEXITCODE -ne 0) { throw "choco pack failed with $LastExitCode"} 68 | $Nu = Get-Item ([System.IO.Path]::Combine($Nu.DirectoryName, '*.nupkg')) | Sort-Object -Property CreationTime -Descending | Select-Object -First 1 69 | } elseif ($Nu.Extension -ne '.nupkg') { throw "File is not nupkg or nuspec file" } 70 | 71 | #At this point Nu is nupkg file 72 | 73 | $package_name = $Nu.Name -replace '(\.\d+)+(-[^-]+)?\.nupkg$' 74 | $package_version = ($Nu.BaseName -replace $package_name).Substring(1) 75 | 76 | Write-Host "`nPackage info" 77 | Write-Host " Path:".PadRight(15) $Nu 78 | Write-Host " Name:".PadRight(15) $package_name 79 | Write-Host " Version:".PadRight(15) $package_version 80 | if ($Parameters) { Write-Host " Parameters:".PadRight(15) $Parameters } 81 | if ($Vagrant) { Write-Host " Vagrant: ".PadRight(15) $Vagrant } 82 | 83 | if ($Vagrant) { 84 | Write-Host "`nTesting package using vagrant" 85 | 86 | if (!$VagrantNoClear) { 87 | Write-Host 'Removing existing vagrant packages' 88 | Remove-Item ([System.IO.Path]::Combine($Vagrant, 'packages', '*.nupkg')) -ea ignore 89 | Remove-Item ([System.IO.Path]::Combine($Vagrant, 'packages', '*.xml')) -ea ignore 90 | } 91 | 92 | Copy-Item $Nu (Join-Path $Vagrant 'packages') 93 | $options_file = "$package_name.$package_version.xml" 94 | @{ Install = $Install; Uninstall = $Uninstall; Parameters = $Parameters } | Export-CliXML ([System.IO.Path]::Combine($Vagrant, 'packages', $options_file)) 95 | if ($VagrantOpen) { 96 | Start-Process powershell -Verb Open -ArgumentList "-NoProfile -NoExit -Command `$Env:http_proxy=`$Env:https_proxy=`$Env:ftp_proxy=`$Env:no_proxy=''; cd $Vagrant; vagrant up" 97 | } else { 98 | powershell -NoProfile -Command "`$Env:http_proxy=`$Env:https_proxy=`$Env:ftp_proxy=`$Env:no_proxy=''; cd $Vagrant; vagrant up" 99 | } 100 | return 101 | } 102 | 103 | if ($Install) { 104 | Write-Host "`nTesting package install" 105 | choco install -y -r $package_name --version $package_version --source "'$($Nu.DirectoryName);https://chocolatey.org/api/v2/'" --force --packageParameters "'$Parameters'" | Write-Host 106 | if ($LASTEXITCODE -ne 0) { throw "choco install failed with $LastExitCode"} 107 | } 108 | 109 | if ($Uninstall) { 110 | Write-Host "`nTesting package uninstall" 111 | choco uninstall -y -r $package_name | Write-Host 112 | if ($LASTEXITCODE -ne 0) { throw "choco uninstall failed with $LastExitCode"} 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /src/Private/AUVersion.ps1: -------------------------------------------------------------------------------- 1 | class AUVersion : System.IComparable { 2 | [version] $Version 3 | [string] $Prerelease 4 | [string] $BuildMetadata 5 | 6 | AUVersion([version] $version, [string] $prerelease, [string] $buildMetadata) { 7 | if (!$version) { throw 'Version cannot be null.' } 8 | $this.Version = $version 9 | $this.Prerelease = $prerelease 10 | $this.BuildMetadata = $buildMetadata 11 | } 12 | 13 | AUVersion($input) { 14 | if (!$input) { throw 'Input cannot be null.' } 15 | $v = [AUVersion]::Parse($input -as [string]) 16 | $this.Version = $v.Version 17 | $this.Prerelease = $v.Prerelease 18 | $this.BuildMetadata = $v.BuildMetadata 19 | } 20 | 21 | static [AUVersion] Parse([string] $input) { return [AUVersion]::Parse($input, $true) } 22 | 23 | static [AUVersion] Parse([string] $input, [bool] $strict) { 24 | if (!$input) { throw 'Version cannot be null.' } 25 | $reference = [ref] $null 26 | if (![AUVersion]::TryParse($input, $reference, $strict)) { throw "Invalid version: $input." } 27 | return $reference.Value 28 | } 29 | 30 | static [bool] TryParse([string] $input, [ref] $result) { return [AUVersion]::TryParse($input, $result, $true) } 31 | 32 | static [bool] TryParse([string] $input, [ref] $result, [bool] $strict) { 33 | $result.Value = [AUVersion] $null 34 | if (!$input) { return $false } 35 | $pattern = [AUVersion]::GetPattern($strict) 36 | if ($input -notmatch $pattern) { return $false } 37 | $reference = [ref] $null 38 | if (![version]::TryParse($Matches['version'], $reference)) { return $false } 39 | $pr = $Matches['prerelease'] 40 | $bm = $Matches['buildMetadata'] 41 | if ($pr -and !$strict) { $pr = $pr.Replace(' ', '.') } 42 | if ($bm -and !$strict) { $bm = $bm.Replace(' ', '.') } 43 | # for now, chocolatey does only support SemVer v1 (no dot separated identifiers in pre-release): 44 | if ($pr -and $strict -and $pr -like '*.*') { return $false } 45 | if ($bm -and $strict -and $bm -like '*.*') { return $false } 46 | if ($pr) { $pr = $pr.Replace('.', '') } 47 | if ($bm) { $bm = $bm.Replace('.', '') } 48 | # 49 | $result.Value = [AUVersion]::new($reference.Value, $pr, $bm) 50 | return $true 51 | } 52 | 53 | hidden static [string] GetPattern([bool] $strict) { 54 | $versionPattern = '(?\d+(?:\.\d+){1,3})' 55 | if ($strict) { 56 | $identifierPattern = "[0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*" 57 | return "^$versionPattern(?:-(?$identifierPattern))?(?:\+(?$identifierPattern))?`$" 58 | } else { 59 | $identifierPattern = "[0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+| \d+)*" 60 | return "$versionPattern(?:[- ]*(?$identifierPattern))?(?:[+ *](?$identifierPattern))?" 61 | } 62 | } 63 | 64 | [AUVersion] WithVersion([version] $version) { return [AUVersion]::new($version, $this.Prerelease, $this.BuildMetadata) } 65 | 66 | [int] CompareTo($obj) { 67 | if ($obj -eq $null) { return 1 } 68 | if ($obj -isnot [AUVersion]) { throw "AUVersion expected: $($obj.GetType())" } 69 | $t = $this.GetParts() 70 | $o = $obj.GetParts() 71 | for ($i = 0; $i -lt $t.Length -and $i -lt $o.Length; $i++) { 72 | if ($t[$i].GetType() -ne $o[$i].GetType()) { 73 | $t[$i] = [string] $t[$i] 74 | $o[$i] = [string] $o[$i] 75 | } 76 | if ($t[$i] -gt $o[$i]) { return 1 } 77 | if ($t[$i] -lt $o[$i]) { return -1 } 78 | } 79 | if ($t.Length -eq 1 -and $o.Length -gt 1) { return 1 } 80 | if ($o.Length -eq 1 -and $t.Length -gt 1) { return -1 } 81 | if ($t.Length -gt $o.Length) { return 1 } 82 | if ($t.Length -lt $o.Length) { return -1 } 83 | return 0 84 | } 85 | 86 | [bool] Equals($obj) { return $this.CompareTo($obj) -eq 0 } 87 | 88 | [int] GetHashCode() { return $this.GetParts().GetHashCode() } 89 | 90 | [string] ToString() { 91 | $result = $this.Version.ToString() 92 | if ($this.Prerelease) { $result += "-$($this.Prerelease)" } 93 | if ($this.BuildMetadata) { $result += "+$($this.BuildMetadata)" } 94 | return $result 95 | } 96 | 97 | [string] ToString([int] $fieldCount) { 98 | if ($fieldCount -eq -1) { return $this.Version.ToString() } 99 | return $this.Version.ToString($fieldCount) 100 | } 101 | 102 | hidden [object[]] GetParts() { 103 | $result = @($this.Version) 104 | if ($this.Prerelease) { 105 | $this.Prerelease -split '\.' | ForEach-Object { 106 | # if identifier is exclusively numeric, cast it to an int 107 | if ($_ -match '^[0-9]+$') { 108 | $result += [int] $_ 109 | } else { 110 | $result += $_ 111 | } 112 | } 113 | } 114 | return $result 115 | } 116 | } 117 | 118 | function ConvertTo-AUVersion($Version) { 119 | return [AUVersion] $Version 120 | } 121 | -------------------------------------------------------------------------------- /src/Chocolatey-AU.psd1: -------------------------------------------------------------------------------- 1 | # 2 | # Module manifest for module 'Chocolatey-AU' 3 | # 4 | # Generated by: Miodrag Milic, Chocolatey Community 5 | # 6 | # Generated on: 3/2/2024 7 | # 8 | 9 | @{ 10 | 11 | # Script module or binary module file associated with this manifest. 12 | RootModule = 'Chocolatey-AU.psm1' 13 | 14 | # Version number of this module. 15 | ModuleVersion = '0.1.0' 16 | 17 | # Supported PSEditions 18 | # CompatiblePSEditions = @() 19 | 20 | # ID used to uniquely identify this module 21 | GUID = '274347eb-7f87-4c2d-9813-aed90330286b' 22 | 23 | # Author of this module 24 | Author = 'Miodrag Milic, Chocolatey Community' 25 | 26 | # Company or vendor of this module 27 | CompanyName = 'Chocolatey Software, Inc.' 28 | 29 | # Copyright statement for this module 30 | Copyright = 'Miodrag Milic, Chocolatey Software, Inc.' 31 | 32 | # Description of the functionality provided by this module 33 | Description = 'Chocolatey Automatic Package Updater Module' 34 | 35 | # Minimum version of the Windows PowerShell engine required by this module 36 | PowerShellVersion = '5.0' 37 | 38 | # Name of the Windows PowerShell host required by this module 39 | # PowerShellHostName = '' 40 | 41 | # Minimum version of the Windows PowerShell host required by this module 42 | # PowerShellHostVersion = '' 43 | 44 | # Minimum version of Microsoft .NET Framework required by this module. This prerequisite is valid for the PowerShell Desktop edition only. 45 | # DotNetFrameworkVersion = '' 46 | 47 | # Minimum version of the common language runtime (CLR) required by this module. This prerequisite is valid for the PowerShell Desktop edition only. 48 | # CLRVersion = '' 49 | 50 | # Processor architecture (None, X86, Amd64) required by this module 51 | # ProcessorArchitecture = '' 52 | 53 | # Modules that must be imported into the global environment prior to importing this module 54 | # RequiredModules = @() 55 | 56 | # Assemblies that must be loaded prior to importing this module 57 | # RequiredAssemblies = @() 58 | 59 | # Script files (.ps1) that are run in the caller's environment prior to importing this module. 60 | # ScriptsToProcess = @() 61 | 62 | # Type files (.ps1xml) to be loaded when importing this module 63 | # TypesToProcess = @() 64 | 65 | # Format files (.ps1xml) to be loaded when importing this module 66 | # FormatsToProcess = @() 67 | 68 | # Modules to import as nested modules of the module specified in RootModule/ModuleToProcess 69 | # NestedModules = @() 70 | 71 | # Functions to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no functions to export. 72 | FunctionsToExport = 'Get-AUPackages', 'Get-RemoteChecksum', 'Get-RemoteFiles', 73 | 'Get-Version', 'Push-Package', 'Set-DescriptionFromReadme', 74 | 'Test-Package', 'Update-AUPackages', 'Update-Package' 75 | 76 | # Cmdlets to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no cmdlets to export. 77 | CmdletsToExport = @() 78 | 79 | # Variables to export from this module 80 | VariablesToExport = @() 81 | 82 | # Aliases to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no aliases to export. 83 | AliasesToExport = 'gau', 'lsau', 'update', 'updateall' 84 | 85 | # DSC resources to export from this module 86 | # DscResourcesToExport = @() 87 | 88 | # List of all modules packaged with this module 89 | # ModuleList = @() 90 | 91 | # List of all files packaged with this module 92 | # FileList = @() 93 | 94 | # Private data to pass to the module specified in RootModule/ModuleToProcess. This may also contain a PSData hashtable with additional module metadata used by PowerShell. 95 | PrivateData = @{ 96 | 97 | PSData = @{ 98 | 99 | # Tags applied to this module. These help with module discovery in online galleries. 100 | Tags = 'chocolatey', 'update', 'module', 'package' 101 | 102 | # A URL to the license for this module. 103 | LicenseUri = 'https://www.gnu.org/licenses/gpl-2.0.txt' 104 | 105 | # A URL to the main website for this project. 106 | ProjectUri = 'https://github.com/chocolatey-community/chocolatey-au' 107 | 108 | # A URL to an icon representing this module. 109 | IconUri = 'https://img.chocolatey.org/nupkg/chocolateyicon.png' 110 | 111 | # ReleaseNotes of this module 112 | ReleaseNotes = 'https://github.com/chocolatey-community/chocolatey-au/blob/master/CHANGELOG.md' 113 | 114 | # Flag to indicate whether the module requires explicit user acceptance for install/update/save 115 | # RequireLicenseAcceptance = $false 116 | 117 | # External dependent modules of this module 118 | # ExternalModuleDependencies = @() 119 | } # End of PSData hashtable 120 | } # End of PrivateData hashtable 121 | 122 | # HelpInfo URI of this module 123 | HelpInfoURI = 'https://github.com/chocolatey-community/chocolatey-au/blob/master/README.md' 124 | 125 | # Default prefix for commands exported from this module. Override the default prefix using Import-Module -Prefix. 126 | # DefaultCommandPrefix = '' 127 | } 128 | -------------------------------------------------------------------------------- /src/Plugins/GitReleases.ps1: -------------------------------------------------------------------------------- 1 | # Author: Kim Nordmo 2 | # Last Change: 29-Oct-2017. 3 | 4 | <# 5 | .SYNOPSIS 6 | Creates Github release for updated packages 7 | #> 8 | param( 9 | $Info, 10 | 11 | # Github API token to use when creating/checking releases and uploading artifacts 12 | [string]$ApiToken, 13 | 14 | # What kind of release should be created, either 1 release per date, or 1 release per package and version is supported. 15 | [ValidateSet('date', 'package')] 16 | [string]$releaseType, 17 | 18 | # The text that should be used in the header of the release. 19 | [string]$releaseHeader = $null, 20 | 21 | # The text that should be used in the description of the release. 22 | [string]$releaseDescription = $null, 23 | 24 | # The formatting to use when replacing in release header/description and on date based releases. 25 | [string]$dateFormat = '{0:yyyy-MM-dd}', 26 | 27 | # Force creating a release when a package have been updated and not just been pushed. 28 | [switch]$Force, 29 | 30 | # The name of the branch, to create the release at 31 | [string]$Branch = 'master' 32 | ) 33 | 34 | function GetOrCreateRelease() { 35 | param( 36 | [string]$tagName, 37 | [string]$releaseName, 38 | [string]$releaseDescription, 39 | [string]$repository, 40 | $headers) 41 | 42 | try { 43 | Write-Verbose "Checking for a release using the tag: $tagName..." 44 | $response = Invoke-RestMethod -UseBasicParsing -Uri "https://api.github.com/repos/$repository/releases/tags/$tagName" -Headers $headers | Where-Object tag_name -eq $tagName 45 | if ($response) { 46 | return $response 47 | } 48 | } 49 | catch { 50 | } 51 | 52 | $json = @{ 53 | "tag_name" = $tagName 54 | "target_commitish" = $Branch 55 | "name" = $releaseName 56 | "body" = $releaseDescription 57 | "draft" = $false 58 | "prerelease" = $false 59 | } | ConvertTo-Json -Compress 60 | 61 | Write-Host "Creating the new release $tagName..." 62 | return Invoke-RestMethod -UseBasicParsing -Method Post -Uri "https://api.github.com/repos/$repository/releases" -Body $json -Headers $headers 63 | } 64 | 65 | [array]$packages = if ($Force) { $Info.result.updated } else { $Info.result.pushed } 66 | 67 | if ($packages.Length -eq 0) { Write-Host "No package updated, skipping"; return } 68 | 69 | $packagesToRelease = New-Object 'System.Collections.Generic.List[hashtable]' 70 | 71 | $packages | ForEach-Object { 72 | if ($_.Streams) { 73 | $_.Streams.Values | Where-Object { $_.Updated } | ForEach-Object { 74 | $packagesToRelease.Add(@{ 75 | Name = $_.Name 76 | NuspecVersion = $_.NuspecVersion 77 | RemoteVersion = $_.RemoteVersion 78 | NuFile = Resolve-Path ("$($_.Path)/$($_.Name).$($_.RemoteVersion).nupkg") 79 | }) 80 | } 81 | } 82 | else { 83 | $packagesToRelease.Add(@{ 84 | Name = $_.Name 85 | NuspecVersion = $_.NuspecVersion 86 | RemoteVersion = $_.RemoteVersion 87 | NuFile = Resolve-Path ("$($_.Path)/$($_.Name).$($_.RemoteVersion).nupkg") 88 | }) 89 | } 90 | } 91 | 92 | $origin = git config --get remote.origin.url 93 | 94 | if (!($origin -match "github.com\/([^\/]+\/[^\/\.]+)")) { 95 | Write-Warning "Unable to parse the repository information, skipping..." 96 | return; 97 | } 98 | $repository = $Matches[1] 99 | 100 | $headers = @{ 101 | Authorization = "token $ApiToken" 102 | } 103 | 104 | if ($releaseType -eq 'date' -and !$releaseHeader) { 105 | $releaseHeader = 'Packages updated on ' 106 | } 107 | elseif (!$releaseHeader) { 108 | $releaseHeader = ' ' 109 | } 110 | 111 | if ($releaseType -eq 'date' -and !$releaseDescription) { 112 | $releaseDescription = 'We had packages that were updated on ' 113 | } 114 | elseif (!$releaseDescription) { 115 | $releaseDescription = ' was updated from version to ' 116 | } 117 | 118 | $date = Get-Date -UFormat $dateFormat 119 | 120 | if ($releaseType -eq 'date') { 121 | $release = GetOrCreateRelease ` 122 | -tagName $date ` 123 | -releaseName ($releaseHeader -replace '', $date) ` 124 | -releaseDescription ($releaseDescription -replace '', $date) ` 125 | -repository $repository ` 126 | -headers $headers 127 | 128 | if (!$release) { 129 | Write-Error "Unable to create a new release, please check your permissions..." 130 | return 131 | } 132 | } 133 | 134 | $uploadHeaders = $headers.Clone() 135 | $uploadHeaders['Content-Type'] = 'application/zip' 136 | 137 | $packagesToRelease | ForEach-Object { 138 | # Because we grab all streams previously, we need to ignore 139 | # cases when a stream haven't been updated (no nupkg file created) 140 | if (!$_.NuFile) { return } 141 | 142 | if ($releaseType -eq 'package') { 143 | $releaseName = $releaseHeader -replace '', $_.Name -replace '', $_.RemoteVersion -replace '', $_.NuspecVersion -replace '', $date 144 | $packageDesc = $releaseDescription -replace '', $_.Name -replace '', $_.RemoteVersion -replace '', $_.NuspecVersion -replace '', $date 145 | 146 | $release = GetOrCreateRelease ` 147 | -tagName "$($_.Name)-$($_.RemoteVersion)" ` 148 | -releaseName $releaseName ` 149 | -releaseDescription $packageDesc ` 150 | -repository $repository ` 151 | -headers $headers 152 | } 153 | 154 | $fileName = [System.IO.Path]::GetFileName($_.NuFile) 155 | 156 | $existing = $release.assets | Where-Object name -eq $fileName 157 | if ($existing) { 158 | Write-Verbose "Removing existing $fileName asset..." 159 | Invoke-RestMethod -UseBasicParsing -Uri $existing.url -method Delete -Headers $headers | Out-Null 160 | } 161 | 162 | $uploadUrl = $release.upload_url -replace '\{.*\}$', '' 163 | $rawContent = [System.IO.File]::ReadAllBytes($_.NuFile) 164 | Write-Host "Uploading $fileName asset..." 165 | Invoke-RestMethod -UseBasicParsing -Uri "${uploadUrl}?name=${fileName}&label=$($_.Name) v$($_.RemoteVersion)" -Body $rawContent -Headers $uploadHeaders -Method Post | Out-Null 166 | } 167 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/zReportIssue.yml: -------------------------------------------------------------------------------- 1 | name: Report Issue 2 | description: Did you find unexpected behavior? 3 | labels: ["Bug"] 4 | 5 | body: 6 | - type: markdown 7 | attributes: 8 | value: | 9 | Ensure you have read over [Submitting Issues](https://github.com/chocolatey/.github/blob/main/SUBMITTING-ISSUES.md) and you are opening this issue in the correct repository. 10 | 11 | Please check to see if your problem already exists with a quick search of the issues. Start with one relevant term and then add others if you get too many results. 12 | 13 | **NOTE: Keep in mind we have a [Code Of Conduct](https://github.com/chocolatey/.github/blob/main/CODE_OF_CONDUCT.md) that we expect folks to observe when they are looking for support in the Chocolatey community.** 14 | 15 | Name your issue appropriately: give it a sentence that reads well enough for anyone seeing this in the release notes to know what it is. 16 | 17 | When writing out the issue details, please ensure you are writing it as if you were explaining it to somebody else, even if you will be working on and resolving the issue yourself. 18 | This helps others to understand the reasons for the issue and for it to be searchable in the future. 19 | - type: checkboxes 20 | attributes: 21 | label: Checklist 22 | description: Before continuing, make sure you have done the following. 23 | options: 24 | - label: I confirm there are no unresolved issues reported on the [Chocolatey Status page](https://status.chocolatey.org). 25 | required: true 26 | - label: I have verified this is the correct repository for opening this issue. 27 | required: true 28 | - label: I have verified no other issues exist related to my problem. 29 | required: true 30 | - label: I have verified this is not an issue for a specific package. 31 | required: true 32 | - label: I have verified this issue is not security related. 33 | required: true 34 | - label: I confirm I am using **official**, and **not** unofficial, or modified, Chocolatey products. 35 | required: true 36 | - type: textarea 37 | id: current-behavior 38 | attributes: 39 | label: What You Are Seeing? 40 | description: | 41 | In your own words, please describe the problem that you are experiencing. Please include images if possible, as this can give a clearer indication of the problem. 42 | validations: 43 | required: true 44 | - type: textarea 45 | id: expected-behavior 46 | attributes: 47 | label: What is Expected? 48 | description: | 49 | Instead of the behavior that you were seeing, what did you expect would be happening instead? 50 | validations: 51 | required: true 52 | - type: textarea 53 | id: repeatable-steps 54 | attributes: 55 | label: How Did You Get This To Happen? 56 | description: | 57 | Please include a complete set of _reproducible steps_ that another user or maintainer of the repository can follow to get the same behavior that you are seeing. _Reproducible steps_ should allow _anybody_ who is unfamiliar with your issue or environment to be able to reproduce your issue. This may include code, scripts or other environment configuration. 58 | 59 | **NOTE: We are unlikely to be able to troubleshoot or respond to issues without _reproducible steps_. If you do not complete this section with _reproducible steps_, the issue will be closed.** 60 | placeholder: | 61 | 1. I ran this command `choco source list` 62 | 2. No sources were displayed 63 | 3. I then ran this command `choco blah` 64 | 4. etc. 65 | validations: 66 | required: true 67 | - type: textarea 68 | id: system-details 69 | attributes: 70 | label: System Details 71 | description: | 72 | Please include as many details about your system as possible. Sometimes, a problem may only happen on specific systems, and this information can be vital to resolving your issue. 73 | 74 | At a minimum, include the following pieces of information: 75 | We assume you are using Windows PowerShell, and all example commands given should be run in Windows PowerShell, not in PowerShell Core or CMD. 76 | 77 | * Operating System: To get this information run `[System.Environment]::OSVersion.version.tostring()` 78 | * Windows PowerShell Version: Run `$PSVersionTable` 79 | * Chocolatey CLI Version: Run `choco --version` 80 | * Chocolatey Licensed Extension version (Run `choco list chocolatey.extension --exact` (If running a Chocolatey CLI version less than v2.0.0, add `--local-only`)): 81 | * Chocolatey License type (Professional / Business / ?) 82 | * Terminal/Emulator: Some knowledge from you is necessary here. CMD, Windows PowerShell, PowerShell Core, Microsoft Terminal, Cmder, and more are possible known terminals or emulators. 83 | value: | 84 | * Operating System: 85 | * Windows PowerShell version: 86 | * Chocolatey CLI Version: 87 | * Chocolatey Licensed Extension version: 88 | * Chocolatey License type: 89 | * Terminal/Emulator: 90 | validations: 91 | required: true 92 | - type: textarea 93 | id: installed-packages 94 | attributes: 95 | label: Installed Packages 96 | description: | 97 | Sometimes one or more packages installed may be the cause of the problem. Please include the information from the command `choco list ` (If running a Chocolatey CLI version less than v2.0.0, add `--local-only`). If this is part of the installation of Chocolatey CLI or no packages 98 | are installed (not even Chocolatey); please add `N/A` instead. 99 | render: bash 100 | validations: 101 | required: true 102 | - type: textarea 103 | id: output-log 104 | attributes: 105 | label: Output Log 106 | description: | 107 | Please include the log given by Chocolatey CLI when running in debugging and verbose mode. You can run Chocolatey CLI in debugging and verbose mode using the flags `--debug --verbose`. Alternatively, you can find the log file in the following default location: `C:\ProgramData\chocolatey\logs\chocolatey.log`. 108 | 109 | Before including the output log, make sure of the following: 110 | - There is no sensitive data shared in the log. 111 | - We need ALL OUTPUT, not just what you may believe is relevant. 112 | - We need ALL OUTPUT (including the configuration information). See https://gist.github.com/ferventcoder/b1300b91c167c8ac8205#file-error-txt-L1-L41 for what we need. 113 | - If it is hard to reproduce with debug/verbose, the log file already logs with those parameters. Just grab the relevant section from the log file. 114 | - Preferably link to a gist instead of pasting the entire log in the issue. You can create a new gist here: https://gist.github.com/ (see https://docs.github.com/en/github/writing-on-github/editing-and-sharing-content-with-gists/creating-gists). 115 | render: bash 116 | validations: 117 | required: true 118 | - type: textarea 119 | id: additional-context 120 | attributes: 121 | label: Additional Context 122 | description: | 123 | Please include any other information here that you feel may be relevant to the problem you are seeing but is not covered in the previous sections. -------------------------------------------------------------------------------- /Plugins.md: -------------------------------------------------------------------------------- 1 | # Plugins 2 | 3 | 4 | [Gist](#gist)   [Git](#git)   [GitLab](#gitlab)   [GitReleases](#gitreleases)   [Gitter](#gitter)   [History](#history)   [Mail](#mail)  [PullRequest](#pullrequest) [Report](#report)   [RunInfo](#runinfo)   [Snippet](#snippet) 5 | 6 | --- 7 | 8 | [Chocolatey-AU plugins](Plugins) are [configured](README.md#plugins) using parameters passed in the HashTable contained in the Options under the key that is named by the plugin. So,`$Options.xyz=@{...}` is a plugin if `xyz.ps1` exists in a directory pointed to by the `PluginPath` updateall option. The Chocolatey-AU will then run this script and pass it `$Options.xyz` HashTable as plugin specific options. Chocolatey-AU comes with several integrated plugins that are described below. 9 | 10 | Default [update_all.ps1](https://github.com/majkinetor/au-packages-template/blob/master/update_all.ps1) uses environment variables to configure some options. If you use [AppVeyor](https://github.com/majkinetor/au/wiki/AppVeyor) set those variables in the [.appveyor.yml](https://github.com/majkinetor/au-packages-template/blob/master/.appveyor.yml) and to run it locally use [update_vars.ps1](https://github.com/majkinetor/au-packages-template/blob/master/update_vars_default.ps1). 11 | 12 | ## [Gist](src/Plugins/Gist.ps1) 13 | 14 | **Upload one or more files to gist**. 15 | 16 | To set up plugin to create gist under your user name you need to give it your gist id and authentication: 17 | 18 | * Log into https://gist.github.com with the user you want to use. 19 | * Create an empty gist (secret or not). Grab the id at the end of it - `https://gist.github.com/name/{id}`. Set it as `$Env:gist_id` environment variable. 20 | * Create [Github personal access token](https://help.github.com/articles/creating-an-access-token-for-command-line-use/) and **make sure token has _gist_ scope selected**. Authenticating with username and password isn't supported for security reasons. Set it as `$Env:github_api_key` environment variable. 21 | 22 | 23 | ## [Git](src/Plugins/Git.ps1) 24 | 25 | **Persist modified files**. 26 | 27 | * To use it locally, just ensure `git push` doesn't require credentials and don't set any environment variables. 28 | * To use on build server such as [[AppVeyor]], specify `$Env:username` and `$Env:password`. If you host git repository on Github its preferable to use personal access token. You can use the same token as with gist as long as _**public repo**_ scope is activated. 29 | 30 | ## [GitLab](src/Plugins/GitLab.ps1) 31 | 32 | **Persist modified files**. 33 | 34 | * Same functionality as Git plugin, but tailored to HTTP(S) API-key pushes against a GitLab server. 35 | * To use on build server such as [[AppVeyor]], specify `$Env:gitlab_user`, `$Env:gitlab_apikey`, and `$Env:gitlab_pushurl`. 36 | * `pushurl` must be a full HTTP(S) URL to the repo; the same one you would use to clone it. Internal plugin logic will use this to reconstruct a compatible URL. 37 | 38 | 39 | ## [GitReleases](src/Plugins/GitReleases.ps1) 40 | 41 | **Creates Github release for updated packages**. 42 | 43 | * It is recommended to add the following line `skip_tags: true` in the `appveyor.yml` file to prevent tags from being built. While it may not be necessary, this is used to prevent packages from being submitted again when `[Chocolatey-AU]` or `[PUSH]` is being used in the commit header message. 44 | 45 | ## [Gitter](src/Plugins/Gitter.ps1) 46 | 47 | **Setup project to submit gitter status** 48 | 49 | * First of all, navigate to the gitter channel you wish to have the status listed (you'll need to have permission to add integrations, and need to do it through the webpage). 50 | 1. Click on the icon for room settings, then select `Integrations`. 51 | 2. Select a `Custom` Integration 52 | 3. Copy the unique webhook url listed in the dialog. 53 | 4. Update your appveyor environment variable with your unique webhook, and set the name to `gitter_webhook`. 54 | 5. Navigate to the `update_all.ps1` file in your repository, and update the `$Options` hashtable with the following 55 | ```powershell 56 | Gitter = @{ 57 | WebHookUrl = $env:gitter_webhook 58 | } 59 | ``` 60 | 6. Enjoy your status updates, or frown on failures. 61 | 62 | ## [History](src/Plugins/History.ps1) 63 | 64 | **Create update history as markdown report using git log**. 65 | 66 | Shows one date per line and all of the packages pushed to the Chocolatey community repository during that day. First letter of the package name links to report (produced by Report plugin), the rest links to actuall commit (produced by the Git plugin). 67 | 68 | This plugin requires Git plugin and that clone is done with adequate depth. 69 | 70 | ## [Mail](src/Plugins/Mail.ps1) 71 | 72 | **Send mail notifications on errors or always**. 73 | 74 | * If you use Google mail for error notifications on a build server such as AppVeyor, Google may block authentication from unknown device. To receive those emails enable less secure apps - see [Allowing less secure apps to access your account](https://support.google.com/accounts/answer/6010255?hl=en). 75 | * If you do not want to use your private email for this, create a new Google account and redirect its messages to your private one. This wont affect you if you run the scripts from your own machine from which you usually access the email. 76 | 77 | ## [PullRequest](src/Plugins/PullRequest.ps1) 78 | 79 | **Create GitHub pull request for the updated packages**. 80 | 81 | The plugin will open a GitHub pull request for the commits created by the Git plugin, which of course needs to run first. 82 | It has options to add assignees and reviewers to the created pull request and, supports on-prem GitHub Enterprise Server. 83 | 84 | ## [Report](src/Plugins/Report.ps1) 85 | 86 | **Create different types of reports about the current run**. 87 | 88 | The plugin saves state of all packages in a file that can be used locally or uploaded via other plugins to remote (such as Gist or Mail). 89 | 90 | Report Types and associated Params: 91 | 92 | * **Markdown:** - Markdown report with links 93 | * *Github_UserRepo* - Use in generating the display name of the link to the package source. (Also used to generate the link address when PackageSourceRootUrl is not specified.) 94 | * *IconSize* - Size of package icons. Defaults to 32. 95 | * *NoAppVeyor* - Set to $true if not using AppVeyor. 96 | * *NoIcons* - Set to $true to remove package icons. 97 | * *PackageSourceBranch* - Used in generating link back to update_all script. Defaults to master. 98 | * *PackageSourceRootUrl* - Use in generating links to the package source. Link addresses default to `https://github.com/`. 99 | * *Title* - Title for the report. 100 | * *UserMessage* - Specify to add a message at the top of the report. 101 | * **Text:** - Simple plain text report. 102 | * *Title* - Title for the report. 103 | * *UserMessage* - Specify to add a message at the top of the report. 104 | 105 | ## [RunInfo](src/Plugins/RunInfo.ps1) 106 | 107 | **Save run info to the file and exclude sensitive information**. 108 | 109 | Run this plugin as the last one to save all other info produced during the run in such way that it can be recreated as object. 110 | To load it for inspection use `$info = Import-CliXml update_info.xml`. 111 | 112 | ## [Snippet](src/Plugins/Snippet.ps1) 113 | 114 | **Upload update history report to GitLab snippet**. 115 | 116 | To set up plugin to create snippet under your user name you need to give it your snippet id and authentication: 117 | 118 | * Log into https://gitlab.com/users/sign_in with the user you want to use. 119 | * [Create a snippet](https://gitlab.com/snippets/new) (private or not) with a title and some random content. Grab the id at the end of it - `https://gitlab.com/snippets/{id}`. Set it as `$Env:snippet_id` environment variable. 120 | * Create [GitLab personal access token](https://gitlab.com/profile/personal_access_tokens) and **make sure token has _api_ scope selected**. Authenticating with username and password isn't supported for security reasons. Set it as `$Env:gitlab_api_token` environment variable. 121 | -------------------------------------------------------------------------------- /tests/Get-Version.Tests.ps1: -------------------------------------------------------------------------------- 1 | remove-module Chocolatey-AU -ea ignore 2 | import-module $PSScriptRoot\..\Chocolatey-AU\Chocolatey-AU.psm1 # Tests require the private functions exported 3 | 4 | Describe 'Get-Version' -Tag getversion { 5 | InModuleScope Chocolatey-AU { 6 | It 'should convert a strict version' { 7 | $expectedVersionStart = '1.2' 8 | $expectedVersion = "$expectedVersionStart.3.4" 9 | # for now, chocolatey does only support SemVer v1 (no dot separated identifiers in pre-release): 10 | $expectedPrerelease = 'beta1' 11 | $expectedBuildMetadata = 'xyz001' 12 | # here is the SemVer v2 equivalent: 13 | #$expectedPrerelease = 'beta.1' 14 | #$expectedBuildMetadata = 'xyz.001' 15 | $expected = "$expectedVersion-$expectedPrerelease+$expectedBuildMetadata" 16 | $res = ConvertTo-AUVersion $expected 17 | 18 | $res | Should Not BeNullOrEmpty 19 | $res.Version | Should Be ([version] $expectedVersion) 20 | $res.Prerelease | Should BeExactly $expectedPrerelease 21 | $res.BuildMetadata | Should BeExactly $expectedBuildMetadata 22 | $res.ToString() | Should BeExactly $expected 23 | $res.ToString(2) | Should BeExactly $expectedVersionStart 24 | $res.ToString(-1) | Should BeExactly $expectedVersion 25 | } 26 | 27 | It 'should not convert a non-strict version' { 28 | { ConvertTo-AUVersion '1.2.3.4a' } | Should Throw 29 | { ConvertTo-AUVersion 'v1.2.3.4-beta.1+xyz.001' } | Should Throw 30 | } 31 | 32 | It 'should parse a non strict version' { 33 | $expectedVersion = "1.2.3.4" 34 | # for now, chocolatey does only support SemVer v1 (no dot separated identifiers in pre-release): 35 | $expectedPrerelease = 'beta1' 36 | $expectedBuildMetadata = 'xyz001' 37 | # here is the SemVer v2 equivalent: 38 | #$expectedPrerelease = 'beta.1' 39 | #$expectedBuildMetadata = 'xyz.001' 40 | $res = Get-Version "v$expectedVersion$expectedPrerelease+$expectedBuildMetadata" 41 | 42 | $res | Should Not BeNullOrEmpty 43 | $res.Version | Should Be ([version] $expectedVersion) 44 | $res.Prerelease | Should BeExactly $expectedPrerelease 45 | $res.BuildMetadata | Should BeExactly $expectedBuildMetadata 46 | } 47 | 48 | $testCases = @( 49 | @{A = '1.9.0' ; B = '1.9.0' ; ExpectedResult = 0} 50 | @{A = '1.9.0' ; B = '1.10.0' ; ExpectedResult = -1} 51 | @{A = '1.10.0' ; B = '1.11.0' ; ExpectedResult = -1} 52 | @{A = '1.0.0' ; B = '2.0.0' ; ExpectedResult = -1} 53 | @{A = '2.0.0' ; B = '2.1.0' ; ExpectedResult = -1} 54 | @{A = '2.1.0' ; B = '2.1.1' ; ExpectedResult = -1} 55 | @{A = '1.0.0-alpha' ; B = '1.0.0-alpha' ; ExpectedResult = 0} 56 | @{A = '1.0.0-alpha' ; B = '1.0.0' ; ExpectedResult = -1} 57 | # for now, chocolatey does only support SemVer v1 (no dot separated identifiers in pre-release): 58 | @{A = '1.0.0-alpha1' ; B = '1.0.0-alpha1' ; ExpectedResult = 0} 59 | @{A = '1.0.0-alpha' ; B = '1.0.0-alpha1' ; ExpectedResult = -1} 60 | @{A = '1.0.0-alpha1' ; B = '1.0.0-alphabeta' ; ExpectedResult = -1} 61 | @{A = '1.0.0-alphabeta' ; B = '1.0.0-beta' ; ExpectedResult = -1} 62 | @{A = '1.0.0-beta' ; B = '1.0.0-beta2' ; ExpectedResult = -1} 63 | @{A = '1.0.0-beta2' ; B = '1.0.0-rc1' ; ExpectedResult = -1} 64 | @{A = '1.0.0-rc1' ; B = '1.0.0' ; ExpectedResult = -1} 65 | # here is the SemVer v2 equivalent: 66 | #@{A = '1.0.0-alpha.1' ; B = '1.0.0-alpha.1' ; ExpectedResult = 0} 67 | #@{A = '1.0.0-alpha.1' ; B = '1.0.0-alpha.01' ; ExpectedResult = 0} 68 | #@{A = '1.0.0-alpha' ; B = '1.0.0-alpha.1' ; ExpectedResult = -1} 69 | #@{A = '1.0.0-alpha.1' ; B = '1.0.0-alpha.beta'; ExpectedResult = -1} 70 | #@{A = '1.0.0-alpha.beta'; B = '1.0.0-beta' ; ExpectedResult = -1} 71 | #@{A = '1.0.0-beta' ; B = '1.0.0-beta.2' ; ExpectedResult = -1} 72 | #@{A = '1.0.0-beta.2' ; B = '1.0.0-beta.11' ; ExpectedResult = -1} 73 | #@{A = '1.0.0-beta.11' ; B = '1.0.0-rc.1' ; ExpectedResult = -1} 74 | #@{A = '1.0.0-rc.1' ; B = '1.0.0' ; ExpectedResult = -1} 75 | @{A = '1.0.0' ; B = '1.0.0+1' ; ExpectedResult = 0} 76 | @{A = '1.0.0+1' ; B = '1.0.0+2' ; ExpectedResult = 0} 77 | @{A = '1.0.0-alpha' ; B = '1.0.0-alpha+1' ; ExpectedResult = 0} 78 | @{A = '1.0.0-alpha+1' ; B = '1.0.0-alpha+2' ; ExpectedResult = 0} 79 | ) 80 | 81 | It 'should compare 2 versions successfully' -TestCases $testCases { param([string] $A, [string] $B, [int] $ExpectedResult) 82 | $VersionA = ConvertTo-AUVersion $A 83 | $VersionB = ConvertTo-AUVersion $B 84 | if ($ExpectedResult -gt 0 ) { 85 | $VersionA | Should BeGreaterThan $VersionB 86 | } elseif ($ExpectedResult -lt 0 ) { 87 | $VersionA | Should BeLessThan $VersionB 88 | } else { 89 | $VersionA | Should Be $VersionB 90 | } 91 | } 92 | 93 | $testCases = @( 94 | @{Value = '1.2'} 95 | @{Value = '1.2-beta+003'} 96 | @{Value = [AUVersion] '1.2'} 97 | @{Value = [AUVersion] '1.2-beta+003'} 98 | @{Value = [version] '1.2'} 99 | @{Value = [regex]::Match('1.2', '^(.+)$').Groups[1]} 100 | @{Value = [regex]::Match('1.2-beta+003', '^(.+)$').Groups[1]} 101 | ) 102 | 103 | It 'converts from any type of values' -TestCases $testCases { param($Value) 104 | $version = [AUVersion] $Value 105 | $version | Should Not BeNullOrEmpty 106 | } 107 | 108 | $testCases = @( 109 | @{Value = '1.2-beta.3'} 110 | @{Value = '1.2+xyz.4'} 111 | @{Value = '1.2-beta.3+xyz.4'} 112 | ) 113 | 114 | It 'does not convert semver v2' -TestCases $testCases { param($Value, $ExpectedResult) 115 | { [AUVersion] $Value } | Should Throw 'Invalid version' 116 | } 117 | 118 | $testCases = @( 119 | @{ExpectedResult = '5.4.9' ; Delimiter = '-' ; Value = 'http://dl.airserver.com/pc32/AirServer-5.4.9-x86.msi'} 120 | @{ExpectedResult = '1.24.0-beta2' ; Value = 'https://github.com/atom/atom/releases/download/v1.24.0-beta2/AtomSetup.exe'} 121 | @{ExpectedResult = '2.4.0.24-beta' ; Value = 'https://github.com/gurnec/HashCheck/releases/download/v2.4.0.24-beta/HashCheckSetup-v2.4.0.24-beta.exe'} 122 | @{ExpectedResult = '2.0.9' ; Value = 'http://www.ltr-data.se/files/imdiskinst_2.0.9.exe'} 123 | @{ExpectedResult = '17.6' ; Delimiter = '-' ; Value = 'http://mirrors.kodi.tv/releases/windows/win32/kodi-17.6-Krypton-x86.exe'} 124 | @{ExpectedResult = '0.70.2' ; Value = 'https://github.com/Nevcairiel/LAVFilters/releases/download/0.70.2/LAVFilters-0.70.2-Installer.exe'} 125 | @{ExpectedResult = '2.2.0-1' ; Value = 'https://files.kde.org/marble/downloads/windows/Marble-setup_2.2.0-1_x64.exe'} 126 | @{ExpectedResult = '2.3.2' ; Value = 'https://github.com/sabnzbd/sabnzbd/releases/download/2.3.2/SABnzbd-2.3.2-win-setup.exe'} 127 | @{ExpectedResult = '1.9' ; Delimiter = '-' ; Value = 'http://download.serviio.org/releases/serviio-1.9-win-setup.exe'} 128 | @{ExpectedResult = '0.17.0' ; Value = 'https://github.com/Stellarium/stellarium/releases/download/v0.17.0/stellarium-0.17.0-win32.exe'} 129 | @{ExpectedResult = '5.24.3.1' ; Value = 'http://strawberryperl.com/download/5.24.3.1/strawberry-perl-5.24.3.1-32bit.msi'} 130 | @{ExpectedResult = '3.5.4' ; Value = 'https://github.com/SubtitleEdit/subtitleedit/releases/download/3.5.4/SubtitleEdit-3.5.4-Setup.zip'} 131 | # for now, chocolatey does only support SemVer v1 (no dot separated identifiers in pre-release): 132 | @{ExpectedResult = '1.2.3-beta4' ; Value = 'v 1.2.3 beta 4'} 133 | @{ExpectedResult = '1.2.3-beta3' ; Value = 'Last version: 1.2.3 beta 3.'} 134 | # here is the SemVer v2 equivalent: 135 | #@{ExpectedResult = '1.2.3-beta.4' ; Value = 'v 1.2.3 beta 4'} 136 | #@{ExpectedResult = '1.2.3-beta.3' ; Value = 'Last version: 1.2.3 beta 3.'} 137 | ) 138 | 139 | It 'should parse any non strict version' -TestCases $testCases { param($Value, $Delimiter, $ExpectedResult) 140 | $version = Get-Version $Value -Delimiter $Delimiter 141 | $version | Should Be ([AUVersion] $ExpectedResult) 142 | } 143 | } 144 | } 145 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/zNewRelease.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Create new Release Template 3 | about: Use this template when starting to prepare a new release 4 | title: "Release: Chocolatey AU v1.0.0" 5 | labels: TaskItem, "2 - Working" 6 | --- 7 | 8 | # Release Procedure 9 | 10 | This documents the procedure that should be followed when releasing a new version of the Chocolatey AU project. 11 | Most of the steps outlined in this document can be done by anyone with write access to the repository, with the exception of the built artifacts that need to come from a Chocolatey Team Member. 12 | 13 | For the steps requiring a Chocolatey Team Member, reach out to one of the team members associated with the repository and ask them for the package artifact once a tag has been created. 14 | 15 | - [ ] Update the issue title with the new version number of the release. 16 | - [ ] All tagged releases of Chocolatey AU should come from: 17 | - [ ] The **master** branch for a normal release, or 18 | - [ ] A **support/*** branch if doing a backport/bugfix release for an earlier supported version, or 19 | - [ ] The **hotfix/*** or **release/*** branch, if a beta package is being released, or 20 | - [ ] The **develop** branch, if an alpha package is being released. 21 | - [ ] Before moving forward, run `build.ps1 -Task CI` locally, to verify that everything builds as expected. 22 | - [ ] Make sure all issues in the upcoming milestone have only one type label associated (A type label would be labels such as `Feature`, `Improvement`, `Enhancement`, `Bug Fix`, etc). 23 | - [ ] If the GitHub milestone issues are still open, confirm that they are done before moving on. If they are in fact done, apply the `Done` label and close the issue. 24 | - [ ] Update the GitHub milestones description if there is a need for any custom words that should be part of the release notes. 25 | - [ ] Run the following command to generate release notes `gitreleasemanager.exe -m --token $env:GITRELEASEMANAGER_PAT -o chocolatey-community -r chocolatey-au` 26 | - [ ] **NOTE:** This expects that you have GitReleaseManager installed. If you do not, it can be installed with `choco install gitreleasemanager.portable --confirm` 27 | - [ ] **NOTE:** If doing an alpha/beta release, don't run this step, instead generate the release notes manually. GitReleaseManager uses labels and milestones to generate the release notes, and therefore won't understand what needs to be done, especially when there are multiple alpha/beta releases. 28 | - [ ] Before running the above command, make sure you have set the environment variable `GITRELEASEMANAGER_PAT` to your own access token. This can be set through PowerShell with `$env:GITRELEASEMANAGER_PAT = ""`. This token requires access to the labels, milestones, issues, pull requests and releases API. 29 | - [ ] This will generate a new draft release on GitHub - the URL to the release should be output from the above command. 30 | - [ ] If doing a release from a **develop**, **support**, **release** or **hotfix** branch, verify that the target branch for creating the new tag is correctly set, and we are **not** tagging against **master** for this release. 31 | - [ ] Review the generated release notes to make sure that they are ok, with appropriate names, etc, make any changes if needed. 32 | - [ ] **This step should only be done if this is NOT an alpha or beta release**. Merge the **hotfix** or **release** branch into the **master** or **support/*** base branches. 33 | - [ ] `git checkout master` OR `git checkout support/*` (**NOTE:** If you do not have access to push to the master branch, ask a Chocolatey Team Member to be granted bypass access). 34 | - [ ] `git merge --no-ff ` i.e. **hotfix/4.1.1** or **release/4.2.0**, whatever branch you are working on just now. 35 | - [ ] Push the changes to the [upstream repository][], and to your fork of the repository. 36 | - [ ] `git push upstream` - here upstream is assumed to be the above repository. 37 | - [ ] `git push origin` - here origin is assumed to be your fork on the above repository 38 | - [ ] Assuming everyone is happy, Publish the GitHub release. 39 | - [ ] This will trigger a tagged build on a private CI system. **NOTE:** Contact a Chocolatey Team Member about sending you the package artifact once it has been built if you have no access to internal systems. 40 | - [ ] Save the package acquired from the internal systems, or a Team Member to a local directory on your local system. 41 | - [ ] Verify that the package can be installed and that it can be uninstalled. 42 | - [ ] Run `choco install chocolatey-au --source="'C:\testing'"` (_replace `C:\testing` with the location you sawed the package to_) and ensure that it successfully installs (_use upgrade if it was already installed_). 43 | - [ ] Run `choco uninstall chocolatey-au` and verify the package was successfully uninstalled. 44 | - [ ] Go back to the releases page, and upload the package artifact `chocolatey-au` to the release. 45 | - [ ] Push or ask a Chocolatey Team Member to push the previously uploaded artifact to the Chocolatey Community Repository (_Wait on confirmation that this has been pushed, and is pending moderation before moving further_). 46 | - [ ] Move closed issues to `5 - Released` with the [Done Label][]. 47 | - [ ] **NOTE:** This step should only be performed if this is a stable release. If an alpha/beta release, these issues won't be moved to released until the stable release is completed. 48 | - [ ] Use GitReleaseManager to close the milestone so that all issues are updated with a message saying this has been released 49 | - [ ] **NOTE:** This step should only be performed if this is a stable release. While on alpha/beta release we don't want to update the issues, since this will happen in the final stable release. 50 | - [ ] Before running the below command, make sure you have set the environment variable `GITRELEASEMANAGER_PAT` to your own access token. This can be set through PowerShell with `$env:GITRELEASEMANAGER_PAT = ""`. This token requires access to the labels, milestones, issues, pull requests and releases API. 51 | - [ ] Use a command similar to the following `gitreleasemanager.exe close -m --token $env:GITRELEASEMANAGER_PAT -o chocolatey-community -r chocolatey-au`. This should become an automated step at some point in the build process. 52 | - [ ] Once the package is available and approved on Chocolatey Community Repository, announce this release on the public [Discord Server][] under the channel `#community-maintainers` (_There is currently no format for this, but ensure a link to the release notes are included_). 53 | - [ ] Next up, we need to finalise the merging of changes back to the **develop** branch. Depending on what type of release you were performing, the steps are going to be different. 54 | - [ ] If this release comes from the **master** branch: 55 | - [ ] `git switch develop` 56 | - [ ] `git merge --no-ff master` 57 | - [ ] There may be conflicts at this point, depending on if any changes have been made on the **develop** branch whilst the release was being done, these will need to be handled on a case by case basis. 58 | - [ ] If this release comes from a **support/*** branch, the following steps should be completed if changes made in this release need to be pulled into **develop**. This may not be necessary but check with folks before doing these steps: 59 | - [ ] Create a new branch, for example `merge-release-VERSION-change` from **develop**. 60 | - [ ] `git switch develop` 61 | - [ ] `git switch -c merge-release-1.2.3-changes` 62 | - [ ] Cherry-pick relevant commits from the release into this new branch. 63 | - [ ] `git cherry-pick COMMIT_HASH` (_multiple commit hashes may be added_). 64 | - [ ] Repeat until all relevant commits are incorporated. 65 | - [ ] If all commits since the last release on the **support/*** branch should be included, you can select these all at once with `git cherry-pick PREVIOUS_VERSION_TAG..support/*` (selecting the previous version tag and correct **support/*** base branch that the tag comes from). 66 | - [ ] Push this branch to you own fork of the repository, and PR the changes into the `develop` branch on GitHub. 67 | - [ ] Delete the **hotfix** or **release** branch that was used during this process 68 | - [ ] **NOTE:** This steps should only be completed if there are no plans to do subsequent alpha/beta releases for this package version. 69 | - [ ] `git branch -d ` 70 | - [ ] If the hotfix or release branch was pushed to the upstream repository, delete it from there as well. 71 | - [ ] Push the changes to [upstream repository][] 72 | - [ ] `git push upstream` - here upstream is assumed to be the above repository. 73 | - [ ] `git push origin` - here origin is assumed to be your fork off the above repository 74 | - [ ] Update the information in the [Chocolatey Community Packages repository][] 75 | - [ ] In the `.appveyor.yml` script, find the mention of `chocolatey-au` and update its version to the released version number. 76 | - [ ] Submit a PR with the changes made. 77 | 78 | [Discord Server]: https://ch0.co/community 79 | [Done Label]: https://github.com/chocolatey-community/chocolatey-au/issues/?q=is%3Aissue+is%3Aclosed+label%3A%224+-+Done%22 80 | [Releases]: https://github.com/chocolatey-community/chocolatey-au/releases 81 | [upstream repository]: https://github.com/chocolatey-community/chocolatey-au 82 | [Chocolatey Community Packages repository]: https://github.com/chocolatey-community/chocolatey-packages 83 | -------------------------------------------------------------------------------- /tests/Update-AUPackages.Streams.Tests.ps1: -------------------------------------------------------------------------------- 1 | remove-module Chocolatey-AU -ea ignore 2 | import-module $PSScriptRoot\..\Chocolatey-AU\Chocolatey-AU.psm1 # Tests require the private functions exported 3 | 4 | Describe 'Update-AUPackages using streams' -Tag updateallstreams { 5 | $saved_pwd = $pwd 6 | 7 | function global:nuspec_file() { [xml](Get-Content $PSScriptRoot/test_package_with_streams/test_package_with_streams.nuspec) } 8 | $pkg_no = 2 9 | $streams_no = $pkg_no * 3 10 | 11 | BeforeEach { 12 | $global:au_Root = "TestDrive:\packages" 13 | $global:au_NoPlugins = $true 14 | 15 | Remove-Item -Recurse $global:au_root -ea ignore 16 | foreach ( $i in 1..$pkg_no ) { 17 | $name = "test_package_with_streams_$i" 18 | $path = "$au_root\$name" 19 | 20 | Copy-Item -Recurse -Force $PSScriptRoot\test_package_with_streams $path 21 | $nu = nuspec_file 22 | $nu.package.metadata.id = $name 23 | Remove-Item "$path\*.nuspec" 24 | $nu.OuterXml | Set-Content "$path\$name.nuspec" 25 | Move-Item "$path\test_package_with_streams.json" "$path\$name.json" 26 | 27 | $module_path = Resolve-Path $PSScriptRoot\..\Chocolatey-AU 28 | "import-module '$module_path' -Force", (Get-Content $path\update.ps1 -ea ignore) | Set-Content $path\update.ps1 29 | } 30 | 31 | $Options = [ordered]@{} 32 | } 33 | 34 | Context 'Plugins' { 35 | It 'should ignore the package that returns "ignore"' { 36 | Get-Content $global:au_Root\test_package_with_streams_1\update.ps1 | Set-Variable content 37 | $content -replace 'update', "Write-Host 'test ignore'; 'ignore'" | Set-Variable content 38 | $content | Set-Content $global:au_Root\test_package_with_streams_1\update.ps1 39 | 40 | $res = updateall -Options $Options -NoPlugins:$false 6>$null 41 | 42 | $res[0].Ignored | Should Be $true 43 | $res[0].IgnoreMessage | Should Be 'test ignore' 44 | } 45 | 46 | It 'should execute text Report plugin' { 47 | Get-Content $global:au_Root\test_package_with_streams_1\update.ps1 | Set-Variable content 48 | $content -replace '@\{.+1\.3.+\}', "@{ Version = '1.3.2' }" | Set-Variable content 49 | $content -replace '@\{.+1\.2.+\}', "@{ Version = '1.2.4' }" | Set-Variable content 50 | $content | Set-Content $global:au_Root\test_package_with_streams_1\update.ps1 51 | 52 | $Options.Report = @{ 53 | Type = 'text' 54 | Path = "$global:au_Root\report.txt" 55 | } 56 | 57 | $res = updateall -NoPlugins:$false -Options $Options 6> $null 58 | 59 | $pattern = "\bFinished $pkg_no packages\b[\S\s]*" 60 | $pattern += '\b1 updated\b[\S\s]*' 61 | $pattern += '\b0 errors\b[\S\s]*' 62 | $pattern += '\btest_package_with_streams_1 +True +1\.3\.2 +1\.3\.1\b[\S\s]*' 63 | $pattern += "\btest_package_with_streams_2 +False +1\.4-beta1 +1\.4-beta1\b[\S\s]*" 64 | $pattern += '\btest_package_with_streams_1\b[\S\s]*' 65 | $pattern += '\bStream: 1\.2\b[\S\s]*' 66 | $pattern += '\bnuspec version: 1\.2\.3\b[\S\s]*' 67 | $pattern += '\bremote version: 1\.2\.4\b[\S\s]*' 68 | $pattern += '\bNew version is available\b[\S\s]*' 69 | $pattern += '\bStream: 1\.3\b[\S\s]*' 70 | $pattern += '\bnuspec version: 1\.3\.1\b[\S\s]*' 71 | $pattern += '\bremote version: 1\.3\.2\b[\S\s]*' 72 | $pattern += '\bNew version is available\b[\S\s]*' 73 | $pattern += '\bStream: 1\.4\b[\S\s]*' 74 | $pattern += '\bnuspec version: 1\.4-beta1\b[\S\s]*' 75 | $pattern += '\bremote version: 1\.4-beta1\b[\S\s]*' 76 | $pattern += '\bNo new version found\b[\S\s]*' 77 | $pattern += '\bPackage updated\b[\S\s]*' 78 | $pattern += '\btest_package_with_streams_2\b[\S\s]*' 79 | $pattern += '\bStream: 1\.2\b[\S\s]*' 80 | $pattern += '\bnuspec version: 1\.2\.3\b[\S\s]*' 81 | $pattern += '\bremote version: 1\.2\.3\b[\S\s]*' 82 | $pattern += '\bNo new version found\b[\S\s]*' 83 | $pattern += '\bStream: 1\.3\b[\S\s]*' 84 | $pattern += '\bnuspec version: 1\.3\.1\b[\S\s]*' 85 | $pattern += '\bremote version: 1\.3\.1\b[\S\s]*' 86 | $pattern += '\bNo new version found\b[\S\s]*' 87 | $pattern += '\bStream: 1\.4\b[\S\s]*' 88 | $pattern += '\bnuspec version: 1\.4-beta1\b[\S\s]*' 89 | $pattern += '\bremote version: 1\.4-beta1\b[\S\s]*' 90 | $pattern += '\bNo new version found\b[\S\s]*' 91 | $Options.Report.Path | Should Exist 92 | $Options.Report.Path | Should FileContentMatchMultiline $pattern 93 | } 94 | 95 | It 'should execute markdown Report plugin' { 96 | Get-Content $global:au_Root\test_package_with_streams_1\update.ps1 | Set-Variable content 97 | $content -replace '@\{.+1\.3.+\}', "@{ Version = '1.3.2' }" | Set-Variable content 98 | $content -replace '@\{.+1\.2.+\}', "@{ Version = '1.2.4' }" | Set-Variable content 99 | $content | Set-Content $global:au_Root\test_package_with_streams_1\update.ps1 100 | 101 | $Options.Report = @{ 102 | Type = 'markdown' 103 | Path = "$global:au_Root\report.md" 104 | Params = @{ Github_UserRepo = 'majkinetor/chocolatey' } 105 | } 106 | 107 | $res = updateall -NoPlugins:$false -Options $Options 6> $null 108 | 109 | $pattern = "\bFinished $pkg_no packages\b[\S\s]*" 110 | $pattern += '\b1 updated\b[\S\s]*' 111 | $pattern += '\b0 errors\b[\S\s]*' 112 | $pattern += '\btest_package_with_streams_1\b.*\bTrue\b.*\bFalse\b.*\b1\.3\.2\b.*\b1\.3\.1\b[\S\s]*' 113 | $pattern += "\btest_package_with_streams_2\b.*\bFalse\b.*\bFalse\b.*\b1\.4-beta1\b.*\b1\.4-beta1\b[\S\s]*" 114 | $pattern += '\btest_package_with_streams_1\b[\S\s]*' 115 | $pattern += '\bStream: 1\.2\b[\S\s]*' 116 | $pattern += '\bnuspec version: 1\.2\.3\b[\S\s]*' 117 | $pattern += '\bremote version: 1\.2\.4\b[\S\s]*' 118 | $pattern += '\bNew version is available\b[\S\s]*' 119 | $pattern += '\bStream: 1\.3\b[\S\s]*' 120 | $pattern += '\bnuspec version: 1\.3\.1\b[\S\s]*' 121 | $pattern += '\bremote version: 1\.3\.2\b[\S\s]*' 122 | $pattern += '\bNew version is available\b[\S\s]*' 123 | $pattern += '\bStream: 1\.4\b[\S\s]*' 124 | $pattern += '\bnuspec version: 1\.4-beta1\b[\S\s]*' 125 | $pattern += '\bremote version: 1\.4-beta1\b[\S\s]*' 126 | $pattern += '\bNo new version found\b[\S\s]*' 127 | $pattern += '\bPackage updated\b[\S\s]*' 128 | $pattern += '\btest_package_with_streams_2\b[\S\s]*' 129 | $pattern += '\bStream: 1\.2\b[\S\s]*' 130 | $pattern += '\bnuspec version: 1\.2\.3\b[\S\s]*' 131 | $pattern += '\bremote version: 1\.2\.3\b[\S\s]*' 132 | $pattern += '\bNo new version found\b[\S\s]*' 133 | $pattern += '\bStream: 1\.3\b[\S\s]*' 134 | $pattern += '\bnuspec version: 1\.3\.1\b[\S\s]*' 135 | $pattern += '\bremote version: 1\.3\.1\b[\S\s]*' 136 | $pattern += '\bNo new version found\b[\S\s]*' 137 | $pattern += '\bStream: 1\.4\b[\S\s]*' 138 | $pattern += '\bnuspec version: 1\.4-beta1\b[\S\s]*' 139 | $pattern += '\bremote version: 1\.4-beta1\b[\S\s]*' 140 | $pattern += '\bNo new version found\b[\S\s]*' 141 | $Options.Report.Path | Should Exist 142 | $Options.Report.Path | Should FileContentMatchMultiline $pattern 143 | } 144 | 145 | # Skip this test. For whatever reason, it started failing on Team City. 146 | It 'should execute GitReleases plugin when there are updates' -Skip { 147 | Get-Content $global:au_Root\test_package_with_streams_1\update.ps1 | Set-Variable content 148 | $content -replace '@\{.+1\.3.+\}', "@{ Version = '1.3.2' }" | Set-Variable content 149 | $content -replace '@\{.+1\.2.+\}', "@{ Version = '1.2.4' }" | Set-Variable content 150 | $content | Set-Content $global:au_Root\test_package_with_streams_1\update.ps1 151 | 152 | $Options.GitReleases = @{ 153 | ApiToken = 'apiToken' 154 | ReleaseType = 'package' 155 | Force = $true 156 | } 157 | 158 | Mock Invoke-RestMethod { 159 | return @{ 160 | tag_name = 'test_package_with_streams_1-1.2.4' 161 | assets = @( 162 | @{ 163 | url = 'https://api.github.com/test_package_with_streams_1.1.2.4.nupkg' 164 | name = 'test_package_with_streams_1.1.2.4.nupkg' 165 | } 166 | ) 167 | } 168 | } -ModuleName Chocolatey-AU 169 | 170 | updateall -NoPlugins:$false -Options $Options 6> $null 171 | 172 | Assert-MockCalled Invoke-RestMethod -Exactly 6 -ModuleName Chocolatey-AU 173 | } 174 | } 175 | 176 | It 'should update package with checksum verification mode' { 177 | 178 | $choco_path = Get-Command choco.exe | ForEach-Object Source 179 | $choco_hash = Get-FileHash $choco_path -Algorithm SHA256 | ForEach-Object Hash 180 | Get-Content $global:au_Root\test_package_with_streams_1\update.ps1 | Set-Variable content 181 | $content -replace '@\{.+1\.3.+\}', "@{ Version = '1.3.2'; ChecksumType32 = 'sha256'; Checksum32 = '$choco_hash'}" | Set-Variable content 182 | $content -replace 'update', "update -ChecksumFor 32" | Set-Variable content 183 | $content | Set-Content $global:au_Root\test_package_with_streams_1\update.ps1 184 | 185 | $res = updateall -Options $Options 6> $null 186 | $res.Count | Should Be $pkg_no 187 | $res[0].Updated | Should Be $true 188 | } 189 | 190 | It 'should limit update time' { 191 | Get-Content $global:au_Root\test_package_with_streams_1\update.ps1 | Set-Variable content 192 | $content -replace 'update', "sleep 10; update" | Set-Variable content 193 | $content | Set-Content $global:au_Root\test_package_with_streams_1\update.ps1 194 | $Options.UpdateTimeout = 5 195 | 196 | $res = updateall -Options $Options 3>$null 6> $null 197 | $res[0].Error -eq "Job terminated due to the 5s UpdateTimeout" | Should Be $true 198 | } 199 | 200 | It 'should update all packages when forced' { 201 | $Options.Force = $true 202 | 203 | $res = updateall -Options $Options 6> $null 204 | 205 | lsau | Measure-Object | ForEach-Object Count | Should Be $pkg_no 206 | $res.Count | Should Be $pkg_no 207 | ($res.Result -match 'update is forced').Count | Should Be $pkg_no 208 | ($res | Where-Object Updated).Count | Should Be $pkg_no 209 | } 210 | 211 | It 'should update no packages when none is newer' { 212 | $res = updateall 6> $null 213 | 214 | lsau | Measure-Object | ForEach-Object Count | Should Be $pkg_no 215 | $res.Count | Should Be $pkg_no 216 | ($res.Result -match 'No new version found').Count | Should Be $streams_no 217 | ($res | Where-Object Updated).Count | Should Be 0 218 | } 219 | 220 | $saved_pwd = $pwd 221 | } 222 | 223 | -------------------------------------------------------------------------------- /tests/Update-AUPackages.Tests.ps1: -------------------------------------------------------------------------------- 1 | remove-module Chocolatey-AU -ea ignore 2 | import-module $PSScriptRoot\..\Chocolatey-AU\Chocolatey-AU.psm1 # Tests require the private functions exported 3 | 4 | Describe 'Update-AUPackages' -Tag updateall { 5 | $saved_pwd = $pwd 6 | 7 | function global:nuspec_file() { [xml](Get-Content $PSScriptRoot/test_package/test_package.nuspec) } 8 | $pkg_no = 3 9 | 10 | BeforeEach { 11 | $global:au_Root = "TestDrive:\packages" 12 | $global:au_NoPlugins = $true 13 | 14 | Remove-Item -Recurse $global:au_root -ea ignore 15 | foreach ( $i in 1..$pkg_no ) { 16 | $name = "test_package_$i" 17 | $path = "$au_root\$name" 18 | 19 | Copy-Item -Recurse -Force $PSScriptRoot\test_package $path 20 | $nu = nuspec_file 21 | $nu.package.metadata.id = $name 22 | Remove-Item "$au_root\$name\*.nuspec" 23 | $nu.OuterXml | Set-Content "$path\$name.nuspec" 24 | 25 | $module_path = Resolve-Path $PSScriptRoot\..\Chocolatey-AU 26 | "import-module '$module_path' -Force", (Get-Content $path\update.ps1 -ea ignore) | Set-Content $path\update.ps1 27 | } 28 | 29 | $Options = [ordered]@{} 30 | } 31 | 32 | Context 'Plugins' { 33 | # Commented tests are invoked manually 34 | 35 | #It 'should execute Gist plugin' { 36 | #$Options.Report = @{ 37 | #Type = 'text' 38 | #Path = "$au_root\report.txt" 39 | #} 40 | #$Options.RunInfo = @{ 41 | #Path = "$au_root\runinfo.xml" 42 | #} 43 | #$Options.Gist = @{ 44 | #Path = "$au_root\*.*" 45 | #} 46 | 47 | #$res = updateall -NoPlugins:$false -Options $Options 48 | #} 49 | 50 | #It 'should execute Mail plugin' { 51 | #$Options.Report = @{ 52 | #Type = 'text' 53 | #Path = "$global:au_Root\report.txt" 54 | #} 55 | 56 | #$Options.Mail = @{ 57 | #To = 'test@localhost' 58 | #Server = 'localhost' 59 | #UserName = 'test_user' 60 | #Password = 'test_pass' 61 | #Port = 25 62 | #EnableSsl = $true 63 | #Attachment = ("$global:au_Root\report.txt" -replace 'TestDrive:', $TestDrive) 64 | #SendAlways = $true 65 | #} 66 | 67 | #if (!(ps papercut -ea ignore)) { 68 | #if (gcm papercut.exe -ea ignore) { start papercut.exe; sleep 5 } 69 | #else { Write-Warning 'Papercut is not installed - skipping test'; return } 70 | #} 71 | #rm $Env:APPDATA\Papercut\* -ea ignore 72 | #$res = updateall -NoPlugins:$false -Options $Options 6> $null 73 | 74 | #sleep 5 75 | #(ls $Env:APPDATA\Papercut\*).Count | Should Be 1 76 | #} 77 | 78 | 79 | It 'should ignore the package that returns "ignore"' { 80 | Get-Content $global:au_Root\test_package_1\update.ps1 | Set-Variable content 81 | $content -replace 'update', "Write-Host 'test ignore'; 'ignore'" | Set-Variable content 82 | $content | Set-Content $global:au_Root\test_package_1\update.ps1 83 | 84 | $res = updateall -Options $Options -NoPlugins:$false 6>$null 85 | 86 | $res[0].Ignored | Should Be $true 87 | $res[0].IgnoreMessage | Should Be 'test ignore' 88 | } 89 | 90 | It 'should repeat and ignore on specific error' { 91 | Get-Content $global:au_Root\test_package_1\update.ps1 | Set-Variable content 92 | $content -replace 'update', "1|Out-File -Append $TestDrive\tmp_test; throw 'test ignore'; update" | Set-Variable content 93 | $content | Set-Content $global:au_Root\test_package_1\update.ps1 94 | 95 | $Options.RepeatOn = @('test ignore') 96 | $Options.RepeatCount = 2 97 | $Options.IgnoreOn = @('test ignore') 98 | 99 | $res = updateall -Options $Options -NoPlugins:$false 6>$null 100 | 101 | $res[0].Ignored | Should Be $true 102 | $res[0].IgnoreMessage | Should BeLike 'AU ignored on*test ignore' 103 | 104 | (Get-Content $TestDrive\tmp_test).Count | Should be 3 105 | } 106 | 107 | It 'should execute text Report plugin' { 108 | Get-Content $global:au_Root\test_package_1\update.ps1 | Set-Variable content 109 | $content -replace '@\{.+\}', "@{ Version = '1.3' }" | Set-Variable content 110 | $content | Set-Content $global:au_Root\test_package_1\update.ps1 111 | 112 | $Options.Report = @{ 113 | Type = 'text' 114 | Path = "$global:au_Root\report.txt" 115 | } 116 | 117 | $res = updateall -NoPlugins:$false -Options $Options 6> $null 118 | 119 | $pattern = "\bFinished $pkg_no packages\b[\S\s]*" 120 | $pattern += '\b1 updated\b[\S\s]*' 121 | $pattern += '\b0 errors\b[\S\s]*' 122 | $pattern += '\btest_package_1 +True +1\.3 +1\.2\.3\b[\S\s]*' 123 | foreach ( $i in 2..$pkg_no ) { 124 | $pattern += "\btest_package_$i +False +1\.2\.3 +1\.2\.3\b[\S\s]*" 125 | } 126 | $pattern += '\btest_package_1\b[\S\s]*' 127 | $pattern += '\bnuspec version: 1\.2\.3\b[\S\s]*' 128 | $pattern += '\bremote version: 1\.3\b[\S\s]*' 129 | $pattern += '\bNew version is available\b[\S\s]*' 130 | $pattern += '\bPackage updated\b[\S\s]*' 131 | foreach ( $i in 2..$pkg_no ) { 132 | $pattern += "\btest_package_$i\b[\S\s]*" 133 | $pattern += '\bnuspec version: 1\.2\.3\b[\S\s]*' 134 | $pattern += '\bremote version: 1\.2\.3\b[\S\s]*' 135 | $pattern += '\bNo new version found\b[\S\s]*' 136 | } 137 | $Options.Report.Path | Should Exist 138 | $Options.Report.Path | Should FileContentMatchMultiline $pattern 139 | } 140 | 141 | It 'should execute markdown Report plugin' { 142 | Get-Content $global:au_Root\test_package_1\update.ps1 | Set-Variable content 143 | $content -replace '@\{.+\}', "@{ Version = '1.3' }" | Set-Variable content 144 | $content | Set-Content $global:au_Root\test_package_1\update.ps1 145 | 146 | $Options.Report = @{ 147 | Type = 'markdown' 148 | Path = "$global:au_Root\report.md" 149 | Params = @{ Github_UserRepo = 'majkinetor/chocolatey' } 150 | } 151 | 152 | $res = updateall -NoPlugins:$false -Options $Options 6> $null 153 | 154 | $pattern = "\bFinished $pkg_no packages\b[\S\s]*" 155 | $pattern += '\b1 updated\b[\S\s]*' 156 | $pattern += '\b0 errors\b[\S\s]*' 157 | $pattern += '\btest_package_1\b.*\bTrue\b.*\bFalse\b.*\b1\.3\b.*\b1\.2\.3\b[\S\s]*' 158 | foreach ( $i in 2..$pkg_no ) { 159 | $pattern += "\btest_package_$i\b.*\bFalse\b.*\bFalse\b.*\b1\.2\.3\b.*\b1\.2\.3\b[\S\s]*" 160 | } 161 | $pattern += '\btest_package_1\b[\S\s]*' 162 | $pattern += '\bnuspec version: 1\.2\.3\b[\S\s]*' 163 | $pattern += '\bremote version: 1\.3\b[\S\s]*' 164 | $pattern += '\bNew version is available\b[\S\s]*' 165 | $pattern += '\bPackage updated\b[\S\s]*' 166 | foreach ( $i in 2..$pkg_no ) { 167 | $pattern += "\btest_package_$i\b[\S\s]*" 168 | $pattern += '\bnuspec version: 1\.2\.3\b[\S\s]*' 169 | $pattern += '\bremote version: 1\.2\.3\b[\S\s]*' 170 | $pattern += '\bNo new version found\b[\S\s]*' 171 | } 172 | $Options.Report.Path | Should Exist 173 | $Options.Report.Path | Should FileContentMatchMultiline $pattern 174 | } 175 | 176 | It 'should execute RunInfo plugin' { 177 | $Options.RunInfo = @{ 178 | Path = "$global:au_Root\update_info.xml" 179 | Exclude = 'password' 180 | } 181 | $Options.Test = @{ 182 | MyPassword = 'password' 183 | Parameter2 = 'p2'` 184 | } 185 | 186 | $res = updateall -NoPlugins:$false -Options $Options 6> $null 187 | 188 | Test-Path $Options.RunInfo.Path | Should Be $true 189 | $info = Import-Clixml $Options.RunInfo.Path 190 | $info.plugin_results.RunInfo -match 'Test.MyPassword' | Should Be $true 191 | $info.Options.Test.MyPassword | Should Be '*****' 192 | } 193 | 194 | It 'should not execute GitReleases plugin when there are no updates' { 195 | $Options.GitReleases = @{ 196 | ApiToken = 'apiToken' 197 | ReleaseType = 'package' 198 | Force = $true 199 | } 200 | 201 | Mock -ModuleName Chocolatey-AU Invoke-RestMethod {} 202 | 203 | updateall -NoPlugins:$false -Options $Options 6> $null 204 | 205 | Assert-MockCalled -ModuleName Chocolatey-AU Invoke-RestMethod -Exactly 0 -Scope It 206 | } 207 | 208 | # Skipping this test as it currently fails for unknown reasons 209 | It 'should execute GitReleases plugin per package when there are updates' -Skip { 210 | Get-Content $global:au_Root\test_package_1\update.ps1 | Set-Variable content 211 | $content -replace '@\{.+\}', "@{ Version = '1.3' }" | Set-Variable content 212 | $content | Set-Content $global:au_Root\test_package_1\update.ps1 213 | 214 | $Options.GitReleases = @{ 215 | ApiToken = 'apiToken' 216 | ReleaseType = 'package' 217 | Force = $true 218 | } 219 | 220 | Mock -ModuleName Chocolatey-AU Invoke-RestMethod { 221 | return @{ 222 | tag_name = 'test_package_1-1.3' 223 | assets = @( 224 | @{ 225 | url = 'https://api.github.com/test_package_1.1.3.nupkg' 226 | name = 'test_package_1.1.3.nupkg' 227 | } 228 | ) 229 | } 230 | } 231 | 232 | updateall -NoPlugins:$false -Options $Options 6> $null 233 | 234 | Assert-MockCalled -ModuleName Chocolatey-AU Invoke-RestMethod -Exactly 3 -Scope It 235 | } 236 | 237 | # Skipping this test as it currently fails for unknown reasons 238 | It 'should execute GitReleases plugin per date when there are updates' -Skip { 239 | Get-Content $global:au_Root\test_package_1\update.ps1 | Set-Variable content 240 | $content -replace '@\{.+\}', "@{ Version = '1.3' }" | Set-Variable content 241 | $content | Set-Content $global:au_Root\test_package_1\update.ps1 242 | 243 | $Options.GitReleases = @{ 244 | ApiToken = 'apiToken' 245 | ReleaseType = 'date' 246 | Force = $true 247 | } 248 | 249 | Mock -ModuleName Chocolatey-AU Get-Date { return '2017-11-05' } -ParameterFilter { $UFormat -eq '{0:yyyy-MM-dd}' } 250 | Mock -ModuleName Chocolatey-AU Invoke-RestMethod { return @{ tag_name = '2017-11-05' } } 251 | 252 | updateall -NoPlugins:$false -Options $Options 6> $null 253 | 254 | Assert-MockCalled -ModuleName Chocolatey-AU Get-Date -Exactly 1 -Scope It 255 | Assert-MockCalled -ModuleName Chocolatey-AU Invoke-RestMethod -Exactly 2 -Scope It 256 | } 257 | } 258 | 259 | It 'should update package with checksum verification mode' { 260 | 261 | $choco_path = Get-Command choco.exe | ForEach-Object Source 262 | $choco_hash = Get-FileHash $choco_path -Algorithm SHA256 | ForEach-Object Hash 263 | Get-Content $global:au_Root\test_package_1\update.ps1 | Set-Variable content 264 | $content -replace '@\{.+\}', "@{ Version = '1.3'; ChecksumType32 = 'sha256'; Checksum32 = '$choco_hash'}" | Set-Variable content 265 | $content -replace 'update', "update -ChecksumFor 32" | Set-Variable content 266 | $content | Set-Content $global:au_Root\test_package_1\update.ps1 267 | 268 | $res = updateall -Options $Options 6> $null 269 | $res.Count | Should Be $pkg_no 270 | $res[0].Updated | Should Be $true 271 | } 272 | 273 | It 'should limit update time' { 274 | Get-Content $global:au_Root\test_package_1\update.ps1 | Set-Variable content 275 | $content -replace 'update', "sleep 10; update" | Set-Variable content 276 | $content | Set-Content $global:au_Root\test_package_1\update.ps1 277 | $Options.UpdateTimeout = 5 278 | 279 | $res = updateall -Options $Options 3>$null 6> $null 280 | $res[0].Error -eq "Job terminated due to the 5s UpdateTimeout" | Should Be $true 281 | } 282 | 283 | It 'should update all packages when forced' { 284 | $Options.Force = $true 285 | 286 | $res = updateall -Options $Options 6> $null 287 | 288 | lsau | Measure-Object | ForEach-Object Count | Should Be $pkg_no 289 | $res.Count | Should Be $pkg_no 290 | ($res.Result -match 'update is forced').Count | Should Be $pkg_no 291 | ($res | Where-Object Updated).Count | Should Be $pkg_no 292 | } 293 | 294 | It 'should update no packages when none is newer' { 295 | $res = updateall 6> $null 296 | 297 | lsau | Measure-Object | ForEach-Object Count | Should Be $pkg_no 298 | $res.Count | Should Be $pkg_no 299 | ($res.Result -match 'No new version found').Count | Should Be $pkg_no 300 | ($res | Where-Object Updated).Count | Should Be 0 301 | } 302 | 303 | $saved_pwd = $pwd 304 | } 305 | 306 | -------------------------------------------------------------------------------- /tests/Update-Package.Tests.ps1: -------------------------------------------------------------------------------- 1 | remove-module Chocolatey-AU -ea ignore 2 | import-module $PSScriptRoot\..\Chocolatey-AU\Chocolatey-AU.psm1 # Tests require the private functions exported -force 3 | 4 | Describe 'Update-Package' -Tag update { 5 | $saved_pwd = $pwd 6 | 7 | function global:get_latest($Version='1.3', $URL='test') { 8 | "function global:au_GetLatest { @{Version = '$Version'; URL = '$URL'} }" | Invoke-Expression 9 | } 10 | 11 | function global:seach_replace() { 12 | "function global:au_SearchReplace { @{} }" | Invoke-Expression 13 | } 14 | 15 | function global:nuspec_file() { [xml](Get-Content TestDrive:\test_package\test_package.nuspec) } 16 | 17 | BeforeEach { 18 | Set-Location $TestDrive 19 | Remove-Item -Recurse -Force TestDrive:\test_package -ea ignore 20 | Copy-Item -Recurse -Force $PSScriptRoot\test_package TestDrive:\test_package 21 | Set-Location $TestDrive\test_package 22 | 23 | $global:au_Timeout = 100 24 | $global:au_Force = $false 25 | $global:au_NoHostOutput = $true 26 | $global:au_NoCheckUrl = $true 27 | $global:au_NoCheckChocoVersion = $true 28 | $global:au_ChecksumFor = 'none' 29 | $global:au_WhatIf = $false 30 | $global:au_NoReadme = $false 31 | 32 | Remove-Variable -Scope global Latest -ea ignore 33 | 'BeforeUpdate', 'AfterUpdate' | ForEach-Object { Remove-Item "Function:/au_$_" -ea ignore } 34 | get_latest 35 | seach_replace 36 | } 37 | 38 | InModuleScope Chocolatey-AU { 39 | 40 | Context 'Updating' { 41 | 42 | It 'can set description from README.md' { 43 | $readme = 'dummy readme & test' 44 | '','', $readme | Out-File $TestDrive\test_package\README.md 45 | $res = update 46 | 47 | $res.Result -match 'Setting package description from README.md' | Should Be $true 48 | (nuspec_file).package.metadata.description.InnerText.Trim() | Should Be $readme 49 | } 50 | 51 | It 'does not set description from README.md with NoReadme parameter' { 52 | $readme = 'dummy readme & test' 53 | '','', $readme | Out-File $TestDrive\test_package\README.md 54 | $res = update -NoReadme 55 | 56 | $res.Result -match 'Setting package description from README.md' | Should BeNullOrEmpty 57 | (nuspec_file).package.metadata.description | Should Be 'This is a test package for Pester' 58 | } 59 | 60 | It 'can backup and restore using WhatIf' { 61 | get_latest -Version 1.2.3 62 | $global:au_Force = $true; $global:au_Version = '1.0' 63 | $global:au_WhatIf = $true 64 | $res = update -ChecksumFor 32 6> $null 65 | 66 | $res.Updated | Should Be $true 67 | $res.RemoteVersion | Should Be '1.0' 68 | (nuspec_file).package.metadata.version | Should Be 1.2.3 69 | } 70 | 71 | It 'can let user override the version' { 72 | get_latest -Version 1.2.3 73 | $global:au_Force = $true; $global:au_Version = '1.0' 74 | 75 | $res = update -ChecksumFor 32 6> $null 76 | 77 | $res.Updated | Should Be $true 78 | $res.RemoteVersion | Should Be '1.0' 79 | } 80 | 81 | It 'automatically verifies the checksum' { 82 | $choco_path = Get-Command choco.exe | ForEach-Object Source 83 | $choco_hash = Get-FileHash $choco_path -Algorithm SHA256 | ForEach-Object Hash 84 | 85 | function global:au_GetLatest { 86 | @{ PackageName = 'test'; Version = '1.3'; URL32=$choco_path; Checksum32 = $choco_hash } 87 | } 88 | 89 | $res = update -ChecksumFor 32 6> $null 90 | $res.Result -match 'hash checked for 32 bit version' | Should Be $true 91 | } 92 | 93 | It 'automatically calculates the checksum' { 94 | update -ChecksumFor 32 6> $null 95 | 96 | $global:Latest.Checksum32 | Should Not BeNullOrEmpty 97 | $global:Latest.ChecksumType32 | Should Be 'sha256' 98 | $global:Latest.Checksum64 | Should BeNullOrEmpty 99 | $global:Latest.ChecksumType64 | Should BeNullOrEmpty 100 | } 101 | 102 | It 'updates package when remote version is higher' { 103 | $res = update 104 | 105 | $res.Updated | Should Be $true 106 | $res.RemoteVersion | Should Be 1.3 107 | $res.Result[-1] | Should Be 'Package updated' 108 | (nuspec_file).package.metadata.version | Should Be 1.3 109 | } 110 | 111 | It "does not update the package when remote version is not higher" { 112 | get_latest -Version 1.2.3 113 | 114 | $res = update 115 | 116 | $res.Updated | Should Be $false 117 | $res.RemoteVersion | Should Be 1.2.3 118 | $res.Result[-1] | Should Be 'No new version found' 119 | (nuspec_file).package.metadata.version | Should Be 1.2.3 120 | } 121 | 122 | It "updates the package when forced using choco fix notation" { 123 | get_latest -Version 1.2.3 124 | 125 | $res = update -Force:$true 126 | 127 | $d = (get-date).ToString('yyyyMMdd') 128 | $res.Updated | Should Be $true 129 | $res.Result[-1] | Should Be 'Package updated' 130 | $res.Result -match 'No new version found, but update is forced' | Should Not BeNullOrEmpty 131 | (nuspec_file).package.metadata.version | Should Be "1.2.3.$d" 132 | } 133 | 134 | It "does not use choco fix notation if the package remote version is higher" { 135 | $res = update -Force:$true 136 | 137 | $res.Updated | Should Be $true 138 | $res.RemoteVersion | Should Be 1.3 139 | (nuspec_file).package.metadata.version | Should Be 1.3 140 | } 141 | 142 | It "searches and replaces given file lines when updating" { 143 | 144 | function global:au_SearchReplace { 145 | @{ 146 | 'test_package.nuspec' = @{ '()(.*)()' = '$1test$3' } 147 | } 148 | } 149 | 150 | function global:au_GetLatest { 151 | @{ PackageName = 'test'; Version = '1.3' } 152 | } 153 | 154 | update 155 | 156 | $nu = (nuspec_file).package.metadata 157 | $nu.releaseNotes | Should Be 'test' 158 | $nu.id | Should Be 'test' 159 | $nu.version | Should Be 1.3 160 | } 161 | } 162 | 163 | Context 'Checks' { 164 | It 'verifies semantic version' { 165 | get_latest -Version 1.0.1-alpha 166 | $res = update 167 | $res.Updated | Should Be $false 168 | 169 | get_latest 1.2.3-alpha 170 | $res = update 171 | $res.Updated | Should Be $false 172 | 173 | get_latest -Version 1.3-alpha 174 | $res = update 175 | $res.Updated | Should Be $true 176 | 177 | get_latest -Version 1.3-alpha.1 178 | { update } | Should Throw "Invalid version" 179 | 180 | get_latest -Version 1.3a 181 | { update } | Should Throw "Invalid version" 182 | } 183 | 184 | It 'throws if latest URL is non existent' { 185 | { update -NoCheckUrl:$false } | Should Throw "URL syntax is invalid" 186 | } 187 | 188 | It 'throws if latest URL ContentType is text/html' { 189 | Mock request { @{ ContentType = 'text/html' } } 190 | Mock is_url { $true } 191 | { update -NoCheckUrl:$false } | Should Throw "Bad content type" 192 | } 193 | 194 | It 'quits if updated package version already exist in Chocolatey community feed' { 195 | $res = update -NoCheckChocoVersion:$false 196 | $res.Result[-1] | Should Match "New version is available but it already exists in the Chocolatey community feed" 197 | } 198 | 199 | It 'throws if search string is not found in given file' { 200 | function global:au_SearchReplace { 201 | @{ 202 | 'test_package.nuspec' = @{ 'not existing' = '' } 203 | } 204 | } 205 | 206 | { update } | Should Throw "Search pattern not found: 'not existing'" 207 | } 208 | } 209 | 210 | Context 'Global variables' { 211 | Mock Write-Verbose 212 | 213 | 214 | It 'sets Force parameter from global variable au_Force if it is not bound' { 215 | $global:au_Force = $true 216 | $filter_msg = "Parameter Force set from global variable au_Force: $au_Force" 217 | update -Verbose 218 | Assert-MockCalled Write-Verbose -ParameterFilter { $Message -eq $filter_msg } 219 | 220 | } 221 | 222 | It "doesn't set Force parameter from global variable au_Force if it is bound" { 223 | $global:au_Force = $true 224 | $filter_msg = "Parameter Force set from global variable au_Force: $au_Force" 225 | update -Verbose -Force:$false 226 | Assert-MockCalled Write-Verbose -ParameterFilter { $Message -ne $filter_msg } 227 | } 228 | 229 | It 'sets Timeout parameter from global variable au_Timeout if it is not bound' { 230 | $global:au_Timeout = 50 231 | $filter_msg = "Parameter Timeout set from global variable au_Timeout: $au_Timeout" 232 | update -Verbose 233 | Assert-MockCalled Write-Verbose -ParameterFilter { $Message -eq $filter_msg } 234 | } 235 | 236 | } 237 | 238 | Context 'Nuspec file' { 239 | 240 | It 'loads a nuspec file from the package directory' { 241 | { update } | Should Not Throw 'No nuspec file' 242 | $global:Latest.NuspecVersion | Should Be 1.2.3 243 | } 244 | 245 | It "throws if it can't find the nuspec file in the current directory" { 246 | Set-Location $TestDrive 247 | { update } | Should Throw 'No nuspec file' 248 | } 249 | 250 | It "uses version 0.0 on invalid nuspec version" { 251 | $nu = nuspec_file 252 | $nu.package.metadata.version = '{{PackageVersion}}' 253 | $nu.Save("$TestDrive\test_package\test_package.nuspec") 254 | 255 | update *> $null 256 | 257 | $global:Latest.NuspecVersion | Should Be '0.0' 258 | } 259 | } 260 | 261 | Context 'au_GetLatest' { 262 | 263 | It 'throws if au_GetLatest is not defined' { 264 | Remove-Item Function:/au_GetLatest 265 | { update } | Should Throw "'au_GetLatest' is not recognized" 266 | } 267 | 268 | It "throws if au_GetLatest doesn't return HashTable" { 269 | $return_value = @(1) 270 | function global:au_GetLatest { $return_value } 271 | { update } | Should Throw "doesn't return a HashTable" 272 | $return_value = @() 273 | { update } | Should Throw "returned nothing" 274 | } 275 | 276 | It "rethrows if au_GetLatest throws" { 277 | function global:au_GetLatest { throw 'test' } 278 | { update } | Should Throw "test" 279 | } 280 | 281 | It 'checks values in $Latest when entering au_GetLatest' { 282 | function global:au_GetLatest { 283 | $Latest.Count | Should Be 1 284 | $Latest.PackageName | Should Be 'test_package' 285 | @{ Version = '1.2' } 286 | } 287 | update 288 | } 289 | 290 | It 'supports returning "ignore"' { 291 | function global:au_GetLatest { 'ignore' } 292 | $res = update 293 | $res | Should BeExactly 'ignore' 294 | } 295 | 296 | It 'supports returning custom values' { 297 | function global:au_GetLatest { @{ Version = '1.2'; NewValue = 1 } } 298 | update 299 | $global:Latest.NewValue | Should Be 1 300 | } 301 | 302 | It 'supports adding values to $global:Latest' { 303 | function global:au_GetLatest { $global:Latest += @{ NewValue = 1 }; @{ Version = '1.2' } } 304 | update 305 | $global:Latest.NewValue | Should Be 1 306 | } 307 | 308 | It 'supports adding values to $Latest' { 309 | function global:au_GetLatest { $Latest.NewValue = 1; @{ Version = '1.2' } } 310 | update 311 | $global:Latest.NewValue | Should Be 1 312 | } 313 | 314 | $testCases = @( 315 | @{ Version = '1.2'; Type = [string] } 316 | @{ Version = [AUVersion] '1.2'; Type = [AUVersion] } 317 | @{ Version = [version] '1.2'; Type = [version] } 318 | @{ Version = [regex]::Match('1.2', '^(.+)$').Groups[1]; Type = [string] } 319 | ) 320 | 321 | It 'supports various Version types' -TestCases $testCases { param($Version) 322 | function global:au_GetLatest { @{ Version = $Version } } 323 | { update } | Should Not Throw 324 | } 325 | 326 | It 'supports various Version types when forcing update' -TestCases $testCases { param($Version, $Type) 327 | function global:au_GetLatest { @{ Version = $Version } } 328 | function global:au_BeforeUpdate { $Latest.Version | Should BeOfType $Type } 329 | { update -Force } | Should Not Throw 330 | } 331 | } 332 | 333 | Context 'Before and after update' { 334 | It 'calls au_BeforeUpdate if package is updated' { 335 | function au_BeforeUpdate { $global:Latest.test = 1 } 336 | update 337 | $global:Latest.test | Should Be 1 338 | } 339 | 340 | It 'calls au_AfterUpdate if package is updated' { 341 | function au_AfterUpdate { $global:Latest.test = 1 } 342 | update 343 | $global:Latest.test | Should Be 1 344 | } 345 | 346 | It 'doesnt call au_BeforeUpdate if package is not updated' { 347 | get_latest -Version 1.2.3 348 | function au_BeforeUpdate { $global:Latest.test = 1 } 349 | update 350 | $global:Latest.test | Should BeNullOrEmpty 351 | } 352 | } 353 | } 354 | Set-Location $saved_pwd 355 | } 356 | 357 | -------------------------------------------------------------------------------- /Chocolatey-AU.build.ps1: -------------------------------------------------------------------------------- 1 | param( 2 | [string] 3 | $OutputDirectory = "$PSScriptRoot/code_drop", 4 | 5 | 6 | [string] 7 | $TimeStampServer = $( 8 | if ($env:CERT_TIMESTAMP_URL) { 9 | $env:CERT_TIMESTAMP_URL 10 | } 11 | else { 12 | 'http://timestamp.digicert.com' 13 | } 14 | ), 15 | 16 | [string] 17 | $CertificatePath = $env:CHOCOLATEY_OFFICIAL_CERT, 18 | 19 | [string] 20 | $CertificatePassword = $env:CHOCOLATEY_OFFICIAL_CERT_PASSWORD, 21 | 22 | 23 | [string] 24 | $CertificateAlgorithm = $( 25 | if ($env:CERT_ALGORITHM) { 26 | $env:CERT_ALGORITHM 27 | } 28 | else { 29 | 'Sha256' 30 | } 31 | ), 32 | 33 | [string] 34 | $CertificateSubjectName = $( 35 | if ($CHOCOLATEY_OFFICIAL_CERT_SUBJECT_NAME) { 36 | $CHOCOLATEY_OFFICIAL_CERT_SUBJECT_NAME 37 | } 38 | else { 39 | 'Chocolatey Software, Inc' 40 | } 41 | ), 42 | 43 | 44 | [string] 45 | $NugetApiKey = $env:POWERSHELLPUSH_API_KEY, 46 | 47 | 48 | [string] 49 | $PublishUrl = $env:POWERSHELLPUSH_SOURCE, 50 | 51 | 52 | [string] 53 | $ChocolateyNugetApiKey = $env:CHOCOOPSPUSH_API_KEY, 54 | 55 | 56 | [string] 57 | $ChocolateyPublishUrl = $env:CHOCOOPSPUSH_SOURCE, 58 | 59 | 60 | [string] 61 | $ModuleName = 'Chocolatey-AU', 62 | 63 | 64 | [switch] 65 | $ThrowOnPSSAViolation 66 | ) 67 | 68 | $ErrorActionPreference = 'Stop' 69 | 70 | $script:SourceFolder = "$PSScriptRoot/src" 71 | $script:ReleaseBuild = -not [string]::IsNullOrEmpty((git tag --points-at HEAD 2> $null) -replace '^v') 72 | $script:BuildVersion = $null 73 | $script:IsPrerelease = $false 74 | $script:ModuleOutputDir = "$OutputDirectory/$ModuleName" 75 | 76 | 77 | # Fix for Register-PSRepository not working with https from StackOverflow: 78 | # https://stackoverflow.com/questions/35296482/invalid-web-uri-error-on-register-psrepository/35296483#35296483 79 | function Register-PSRepositoryFix { 80 | [CmdletBinding()] 81 | param ( 82 | [Parameter(Mandatory = $true)] 83 | [String] 84 | $Name, 85 | 86 | [Parameter(Mandatory = $true)] 87 | [Uri] 88 | $SourceLocation, 89 | 90 | [ValidateSet('Trusted', 'Untrusted')] 91 | $InstallationPolicy = 'Trusted' 92 | ) 93 | 94 | $ErrorActionPreference = 'Stop' 95 | 96 | try { 97 | Write-Verbose 'Trying to register via Register-PSRepository' 98 | Register-PSRepository -Name $Name -SourceLocation $SourceLocation -InstallationPolicy $InstallationPolicy -ErrorAction Stop 99 | Write-Verbose 'Registered via Register-PSRepository' 100 | } 101 | catch { 102 | Write-Verbose 'Register-PSRepository failed, registering via workaround' 103 | 104 | # Adding PSRepository directly to file 105 | Register-PSRepository -Name $Name -SourceLocation $env:TEMP -InstallationPolicy $InstallationPolicy -ErrorAction Stop 106 | $PSRepositoriesXmlPath = "$env:LOCALAPPDATA\Microsoft\Windows\PowerShell\PowerShellGet\PSRepositories.xml" 107 | $repos = Import-Clixml -Path $PSRepositoriesXmlPath 108 | $repos[$Name].SourceLocation = $SourceLocation.AbsoluteUri 109 | $repos[$Name].PublishLocation = [uri]::new($SourceLocation, 'package').AbsoluteUri 110 | $repos[$Name].ScriptSourceLocation = '' 111 | $repos[$Name].ScriptPublishLocation = '' 112 | $repos | Export-Clixml -Path $PSRepositoriesXmlPath 113 | 114 | # Reloading PSRepository list 115 | Set-PSRepository -Name PSGallery -InstallationPolicy Trusted 116 | Write-Verbose 'Registered via workaround' 117 | } 118 | } 119 | 120 | # Synopsis: ensure GitVersion is installed 121 | task InstallGitVersion { 122 | if ((-not (Get-Command gitversion -ErrorAction Ignore)) -and (-not (Get-Command dotnet-gitversion -ErrorAction Ignore))) { 123 | Write-Host "Gitversion not installed. Attempting to install" 124 | 125 | if (-not ([Security.Principal.WindowsPrincipal]([Security.Principal.WindowsIdentity]::GetCurrent())).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)){ 126 | throw "You are not an administrator. We cannot use Chocolatey to install gitversion.portable." 127 | } 128 | 129 | choco install gitversion.portable -y --no-progress 130 | } 131 | } 132 | 133 | # Synopsis: ensure PowerShellGet has the NuGet provider installed 134 | task BootstrapPSGet { 135 | if (-not (Get-PackageProvider NuGet -ErrorAction Ignore)) { 136 | Write-Host "Installing NuGet package provider" 137 | Install-PackageProvider NuGet -MinimumVersion 2.8.5.201 -ForceBootstrap -Force 138 | } 139 | 140 | Set-PSRepository -Name PSGallery -InstallationPolicy Trusted 141 | 142 | if (-not (Get-InstalledModule PowerShellGet -MinimumVersion 2.0 -MaximumVersion 2.99 -ErrorAction Ignore)) { 143 | Install-Module PowerShellGet -MaximumVersion 2.99 -Force -AllowClobber -Scope CurrentUser 144 | Remove-Module PowerShellGet -Force 145 | Import-Module PowerShellGet -MinimumVersion 2.0 -Force 146 | Import-PackageProvider -Name PowerShellGet -MinimumVersion 2.0 -Force 147 | } 148 | } 149 | 150 | # Synopsis: ensure Pester is installed 151 | task InstallPester BootstrapPSGet, { 152 | if (-not (Get-InstalledModule Pester -MaximumVersion 4.99 -ErrorAction SilentlyContinue)) { 153 | Write-Host "Installing Pester" 154 | Install-Module Pester -MaximumVersion 4.99 -SkipPublisherCheck -Force -Scope CurrentUser -ErrorAction Stop -Verbose:$false 155 | } 156 | } 157 | 158 | # Synopsis: ensure PSScriptAnalyzer is installed 159 | task InstallScriptAnalyzer BootstrapPSGet, { 160 | if (-not (Get-InstalledModule PSScriptAnalyzer -MinimumVersion 1.20 -ErrorAction SilentlyContinue)) { 161 | Write-Host "Installing PSSA" 162 | Install-Module PSScriptAnalyzer -Scope CurrentUser -Force -MinimumVersion 1.20 -ErrorAction Stop -Verbose:$false 163 | } 164 | } 165 | 166 | # Synopsis: cleanup build artifacts 167 | task Clean { 168 | remove $OutputDirectory 169 | New-Item -Path $OutputDirectory -ItemType Directory | Out-Null 170 | } 171 | 172 | # Synopsis: run PSScriptAnalyzer on project files 173 | task ScriptAnalyzer InstallScriptAnalyzer, { 174 | $results = Invoke-ScriptAnalyzer -Path $script:SourceFolder -Recurse -Settings "$PSScriptRoot/PSScriptAnalyzerSettings.psd1" 175 | if ($results) { 176 | Write-Warning "$($results.Count) PSSA rule violations found." 177 | $results 178 | # Chocolatey-AU currently has lots of PSSA violations. None of them are errors in PSSA. 179 | # For now, the build will not fail on PSSA unless asked. 180 | if ($ThrowOnPSSAViolation) { 181 | throw "PSSA rule violations detected, see above errors for more information" 182 | } 183 | } 184 | } 185 | 186 | # Synopsis: build the project 187 | task Build Clean, InstallGitVersion, ScriptAnalyzer, { 188 | New-Item $script:ModuleOutputDir -ItemType Directory | Out-Null 189 | 190 | Copy-Item "$script:SourceFolder/*" -Destination $script:ModuleOutputDir -Recurse 191 | $manifest = Get-ChildItem "$OutputDirectory/$ModuleName/$ModuleName.psd1" 192 | 193 | $gitversion = if (Get-Command gitversion -ErrorAction Ignore) 194 | { 195 | gitversion.exe 196 | } 197 | else { 198 | dotnet-gitversion.exe 199 | } 200 | 201 | $gitversion | Out-String -Width 120 | Write-Host 202 | $versionInfo = $gitversion 2>$null | ConvertFrom-Json 203 | $manifestUpdates = @{ 204 | Path = $manifest.FullName 205 | ModuleVersion = $versionInfo.MajorMinorPatch 206 | } 207 | 208 | $prerelease = $versionInfo.NuGetPreReleaseTagV2 -replace '[^a-z0-9]' 209 | 210 | if ($prerelease) { 211 | if ($prerelease -notmatch '^(alpha|beta)') { 212 | $prerelease = "alpha$prerelease" 213 | } 214 | 215 | if ($prerelease.Length -gt 20) { 216 | $prerelease = $prerelease.Substring(0, 20) 217 | } 218 | 219 | $manifestUpdates.Prerelease = $prerelease 220 | $script:IsPrerelease = $true 221 | } 222 | 223 | $script:BuildVersion = if ($prerelease) { 224 | "$($versionInfo.MajorMinorPatch)-$prerelease" 225 | } 226 | else { 227 | $versionInfo.MajorMinorPatch 228 | } 229 | 230 | $help_dir = "${script:ModuleOutputDir}/en-US" 231 | New-Item -Type Directory -Force $help_dir | Out-Null 232 | Get-Content $PSScriptRoot/README.md | Select-Object -Skip 4 | Set-Content "$help_dir/about_$ModuleName.help.txt" -Encoding ascii 233 | 234 | Update-ModuleManifest @manifestUpdates 235 | } 236 | 237 | # Synopsis: Create the Chocolatey Package 238 | task CreateChocolateyPackage -After Sign { 239 | $ReadmePath = "$PSScriptRoot/README.md" 240 | $Readme = Get-Content $ReadmePath -Raw 241 | 242 | if (-not ($Readme -match '## Features(.|\n)+?(?=\n##)')) 243 | { 244 | throw "No 'Features' found in '$ReadmePath'" 245 | } 246 | 247 | $features = $Matches[0] 248 | $ChocolateyPackageDir = "$OutputDirectory/temp/chocolateyPackage" 249 | New-Item $ChocolateyPackageDir -ItemType Directory -ErrorAction SilentlyContinue | Out-Null 250 | Copy-Item $PSScriptRoot/chocolatey/* $ChocolateyPackageDir -Recurse 251 | $nuspecPath = "$ChocolateyPackageDir/chocolatey-au.nuspec" 252 | [xml]$chocolateyPackage = Get-Content $nuspecPath 253 | $description = $chocolateyPackage.package.metadata.summary + ".`n`n" + $features 254 | $chocolateyPackage.package.metadata.description = $description 255 | $chocolateyPackage.Save($nuspecPath) 256 | Copy-Item $script:ModuleOutputDir $ChocolateyPackageDir/tools -Recurse -Force 257 | choco pack $nuspecPath --outputdirectory $OutputDirectory --version $script:BuildVersion 258 | $script:ChocolateyPackagePath = Get-ChildItem $OutputDirectory -Filter *.nupkg | Select-Object -ExpandProperty FullName 259 | 260 | if (-not (Test-Path $script:ChocolateyPackagePath)) { 261 | throw 'Chocolatey Package failed to pack.' 262 | } 263 | } 264 | 265 | # Synopsis: zip up the built project 266 | task Create7zipArchive -After Sign { 267 | $zip_path = "$OutputDirectory\${ModuleName}_${script:BuildVersion}.7z" 268 | $cmd = "$Env:ChocolateyInstall/tools/7z.exe a '$zip_path' '$OutputDirectory/$ModuleName' '$PSScriptRoot/chocolatey/tools/install.ps1'" 269 | $cmd | Invoke-Expression | Out-Null 270 | if (!(Test-Path $zip_path)) { throw "Failed to build 7z package" } 271 | } 272 | 273 | task ImportChecks -After Build { 274 | $publicFunctions = Get-Item "$script:SourceFolder/Public/*.ps1" 275 | 276 | Remove-Module $ModuleName -ErrorAction Ignore 277 | Import-Module $script:ModuleOutputDir -Force 278 | $actualFunctions = (Get-Module $ModuleName).ExportedFunctions 279 | if ($actualFunctions.Count -lt $publicFunctions.Count) { 280 | $missingFunctions = $publicFunctions.BaseName | Where-Object { $_ -notin $actualFunctions.Keys } 281 | $message = @( 282 | "src/Public: $($publicFunctions.Count) files" 283 | "${ModuleName}: $($actualFunctions.Count) exported functions" 284 | "some functions in the Public folder may not be exported" 285 | "missing functions may include: $($missingFunctions -join ', ')" 286 | ) -join "`n" 287 | Write-Warning $message 288 | } 289 | elseif ($publicFunctions.Count -lt $actualFunctions.Count) { 290 | $message = @( 291 | "src/Public: $($publicFunctions.Count) files" 292 | "${ModuleName}: $($actualFunctions.Count) exported functions" 293 | "there seems to be fewer files in the Public folder than public functions exported" 294 | ) -join "`n" 295 | Write-Warning $message 296 | } 297 | } 298 | 299 | # Synopsis: CI-specific build operations to run after the normal build 300 | task CIBuild Build, { 301 | Write-Host $env:GitVersionTool 302 | 303 | Write-Host "##teamcity[buildNumber '$script:BuildVersion']" 304 | } 305 | 306 | # Synopsis: run Pester tests 307 | task Test InstallPester, Build, { 308 | Import-Module Pester -MaximumVersion 4.99 309 | 310 | Copy-Item -Path "$script:SourceFolder/../Tests" -Destination "$OutputDirectory/Tests" -Recurse 311 | $results = Invoke-Pester (Resolve-Path "$OutputDirectory/Tests") -OutputFile "$OutputDirectory/test.results.xml" -OutputFormat NUnitXml -PassThru 312 | 313 | assert ($results.FailedCount -eq 0) "Pester test failures found, see above or the '$OutputDirectory/test.results.xml' result file for details" 314 | } 315 | 316 | # Synopsis: sign PowerShell scripts 317 | task Sign -After Build { 318 | $ScriptsToSign = Get-ChildItem -Path $script:ModuleOutputDir -Recurse -Include '*.ps1', '*.psm1' 319 | 320 | if ($CertificatePath) { 321 | $CertificatePath = $CertificatePath 322 | $CertificatePassword = $CertificatePassword 323 | } 324 | else { 325 | $CertificateSubjectName = $CertificateSubjectName 326 | } 327 | 328 | 329 | $cert = if ($CertificatePath) { 330 | New-Object System.Security.Cryptography.X509Certificates.X509Certificate2($CertificatePath, $CertificatePassword) 331 | } 332 | else { 333 | Get-ChildItem Cert:\LocalMachine\My | Where-Object Subject -Like "*$CertificateSubjectName*" 334 | } 335 | 336 | if ($null -eq $cert) { 337 | Write-Warning "No certificate found for signing. Module not being signed." 338 | return 339 | } 340 | 341 | Set-AuthenticodeSignature -FilePath $ScriptsToSign -Certificate $cert -TimestampServer $TimeStampServer -IncludeChain NotRoot -HashAlgorithm $CertificateAlgorithm 342 | } 343 | 344 | # Synopsis: publish $ModuleName either internally or to the PSGallery 345 | task Publish -If ($script:ReleaseBuild -or $PublishUrl) Build, { 346 | if (-not (Test-Path $OutputDirectory)) { 347 | throw 'Build the module with `Invoke-Build` or `build.ps1` before attempting to publish the module' 348 | } 349 | 350 | if (-not $NugetApiKey -or -not $ChocolateyNugetApiKey) { 351 | throw 'Please pass the API key for publishing to both the `-NugetApiKey` and `-ChocolateyNugetApiKey` parameter or set $env:POWERSHELLPUSH_API_KEY and $env:CHOCOOPSPUSH_API_KEY before publishing' 352 | } 353 | 354 | $psdFile = Resolve-Path $script:ModuleOutputDir 355 | $publishParams = @{ 356 | Path = $psdFile 357 | NugetApiKey = $NugetApiKey 358 | } 359 | 360 | if ($PublishUrl) { 361 | Write-Verbose "Publishing to '$PublishUrl'" 362 | $repo = Get-PSRepository | Where-Object PublishLocation -EQ $PublishUrl 363 | if ($repo) { 364 | $publishParams.Repository = $repo.Name 365 | } 366 | else { 367 | $testRepo = @{ 368 | Name = "$ModuleName" 369 | SourceLocation = $PublishUrl 370 | InstallationPolicy = 'Trusted' 371 | } 372 | 373 | Register-PSRepositoryFix @testRepo 374 | $publishParams.Repository = "$ModuleName" 375 | } 376 | 377 | Publish-Module @publishParams 378 | } 379 | 380 | if ($ChocolateyPublishUrl) { 381 | Write-Verbose "Publishing to '$ChocolateyPublishUrl'" 382 | choco push $script:ChocolateyPackagePath --source $ChocolateyPublishUrl --key $ChocolateyNugetApiKey 383 | 384 | if ($LASTEXITCODE -ne 0) { 385 | throw "Chocolatey push to $ChocolateyPublishUrl failed." 386 | } 387 | } 388 | 389 | if ($script:ReleaseBuild) { 390 | Write-Verbose "Publishing to PSGallery" 391 | $publishParams.NugetApiKey = $env:POWERSHELLGALLERY_API_KEY 392 | $publishParams.Repository = 'PSGallery' 393 | 394 | Publish-Module @publishParams 395 | } 396 | } 397 | 398 | # Synopsis: CI configuration; test, build, sign the module, and publish 399 | task CI CIBuild, Sign, Test, Publish 400 | 401 | # Synopsis: default task; build and test 402 | task . Build, Test 403 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # AU Project Changelog 2 | 3 | The AU project is now archived and there will be no new versions. 4 | 5 | ## 2022.10.24 6 | 7 | - Added `$au_GalleryPackageRootUrl` as a slightly more flexible alternative to `$au_GalleryUrl` ([#250](https://github.com/majkinetor/au/issues/250)) 8 | - `$au_GalleryUrl` global variable is still maintained for compatibility 9 | - Can specify as an environment variable `$env:au_GalleryPackageRootUrl` when working with Update-AUPackages (update_all.ps1) ([#254](https://github.com/majkinetor/au/issues/254)) 10 | - Can specify as a global variable in update.ps1 to override on per package basis. 11 | - Plugins: 12 | - `History`: 13 | - History plugin now ignores merges ([#258](https://github.com/majkinetor/au/issues/258)) 14 | - `Package_Source_Root_Url` param added to History plugin so links can be configured for non-Github users. (related to [#257](https://github.com/majkinetor/au/issues/257)) 15 | - `Report`: 16 | - `Package_Source_Root_Url` param added to Markdown report type so links can be configured for non-Github users. ([#257](https://github.com/majkinetor/au/issues/257)) 17 | - `Package_Source_Branch` parameter added to Markdown report type to configure the branch name for the package source if not using master. ([#244](https://github.com/majkinetor/au/issues/244)) 18 | - `PullRequest`: New plugin that creates a GitHub pull request for the updated packages. ([#269](https://github.com/majkinetor/au/pull/269)) 19 | 20 | ## 2021.7.18 21 | 22 | - Fixed bad packaging of previous version 23 | 24 | ## 2021.6.27 25 | 26 | - Linux support ([#234](https://github.com/majkinetor/au/pull/234)) 27 | - TLS settings updated ([#216](https://github.com/majkinetor/au/pull/233)) 28 | - Plugins: 29 | - `Git`: Added `AddNew` parameter to allow adding new packages, created by the AU script ([#239](https://github.com/majkinetor/au/issues/239)) 30 | - `Git`: Changed `Branch` parameter to create branch if it doesnt exist 31 | - `History`: Changed so it looks into all branches for AU commit messages 32 | 33 | ## 2020.11.21 34 | 35 | - `Get-RemoteFiles` now considers `$Latest.Options.Headers` 36 | - TLS settings updated ([#216](https://github.com/majkinetor/au/pull/216)) 37 | - Support ChocolateyPackageFolder environment variable ([#255](https://github.com/majkinetor/au/pull/255)) 38 | - Improved Powershell 7 compatibility ([#208](https://github.com/majkinetor/au/issues/208)) 39 | - Set the AU version to the last commit date ([#217](https://github.com/majkinetor/au/pull/217)) 40 | 41 | ### Plugins: 42 | 43 | - **GitLab**: new plugin ([#195](https://github.com/majkinetor/au/pull/195)) 44 | - **Gist**: option for secret gist and Enterprise API 45 | - **GitReleases**: Added a `Branch` parameter ([#227](https://github.com/majkinetor/au/issues/227)) 46 | 47 | ## 2019.5.22 48 | 49 | - `Get-RemoteChecksum`: New parameter `Headers` 50 | - Plugins: 51 | - New plugin: Gitter 52 | - New plugin: Snippet 53 | 54 | ### Bugfixes 55 | 56 | - Fixed header handling during request ([#164](https://github.com/majkinetor/au/issues/164)) 57 | - Push errors are not repeated or ignored on ([#175](https://github.com/majkinetor/au/issues/175)) 58 | - Few small changes and fixes 59 | 60 | ## 2018.5.18 61 | 62 | - `Update-Package`: 63 | - Now you can pass HTTP/HTTPS headers to `$Latest.Options.Headers` to avoid `Unauthorized` errors while checking URLs. 64 | - Package Gallery URL is no longer hard-coded but taken from the `$au_GalleryUrl` if it exists ([#95](https://github.com/majkinetor/au/issues/95)) 65 | - `Update-AUPackages`: Added `NoCheckChocoVersion` option. 66 | - Plugins: 67 | - `Git`: Added `Branch` parameter to specify a branch name 68 | - `Mail`: Added `From` parameter to be used with mail servers that do not allow non-existent email addresses. 69 | 70 | ### Bugfixes 71 | 72 | - `Gist` plugin: Security protocol is set according to updated [Github requirements](https://githubengineering.com/crypto-removal-notice). 73 | - `Get-RemoteFiles`: Fixed wrong checksum type being set on 64bit url 74 | 75 | ## 2018.1.11 76 | - `Update-AuPackage` 77 | - New feature [streams](https://github.com/majkinetor/au#streams) that extends `au_GetLatest` with option to return multiple HashTables (one for each stream). 78 | - New parameter `IncludeStream` to force update of specific stream. 79 | - `au_BeforeUpdate` and `au_AfterUpdate` now have parameter `Package` of type `[AUPackage]` which you can use among other things to modify the Nuspec data. 80 | - Added new function `Set-DescriptionFromReadme` that is called automatically when README.md is present in the package folder ([#85](https://github.com/majkinetor/au/issues/85)). See [documentation](README.md#automatic-package-description-from-readmemd). 81 | - Plugins: 82 | - New plugin: [GitReleases](https://github.com/majkinetor/au/blob/master/AU/Plugins/GitReleases.ps1) creates Github release on successifully pushed packages. 83 | - Git: new parameter `Strategy` with options on how to commit repository changes 84 | - Report: symbols in markdown report to mark embedded and stream packages 85 | 86 | ## 2017.8.30 87 | 88 | - `Update-AUPackages` 89 | - New options to handle update.ps1 errors: `IgnoreOn`, `RepeatOn`,`RepeatCount`,`RepeatSleep`. See [documentation](https://github.com/majkinetor/au#handling-update-errors). ([#76](https://github.com/majkinetor/au/issues/76)). 90 | - New option `WhatIf` option that will trigger WhatIf on all packages. 91 | - New AUPackage properties: `Ignored` (boolean) and `IgnoreMessage`. 92 | - Report plugin: `IgnoreMessage` is added in the ignore section. 93 | - `Update-AuPackage` 94 | - Added parameter `WhatIf` that will save and restore the package. See [documentation](https://github.com/majkinetor/au#whatif). ([#30](https://github.com/majkinetor/au/issues/30)) 95 | - `au_GetLatest` can now return `ignore` to make package ignored in the `updateall` context. 96 | 97 | ### Bugfixes 98 | 99 | - Git plugin: package that changed `$Latest.PackageName` was not pushed when updated ([#66](https://github.com/majkinetor/au/issues/66)). 100 | 101 | ## 2017.3.29 102 | 103 | - `Get-RemoteFiles` 104 | - `NoSuffix` switch to not add `_x32` and/or `_x64` suffix at the end of the file names. 105 | - Now also sets `ChecksumTypeXX` and `FileNameXX` and accepts `Algorithm` parameter. 106 | 107 | ### Bugfixes 108 | 109 | - Fix ps1 files encoded in UTF8 without BOM being treated as ANSI. 110 | - Fix chocolatey.org package check using wrong package name when overridden in update.ps1. 111 | 112 | ## 2017.1.14 113 | 114 | **NOTE**: License changed from MIT to GPL2. 115 | 116 | - New function `Get-RemoteFiles`. See [documentation](https://github.com/majkinetor/au#embedding-binaries). 117 | - `Update-Package` 118 | - Support newer TLS version support by setting the `SecurityProtocol` property of `ServicePointManager`. 119 | - Posh 5 dependency removed for chocolatey package because it is not practical. 120 | 121 | ### Bugfixes 122 | 123 | - Fix encoding of nuspec (UTF-8 NO BOM) and ps1 (UTF-8 BOM) files. 124 | 125 | ## 2016.12.17 126 | 127 | **NOTE**: Minimal PowerShell version required to run AU is now 5.0 instead of 4.0. This wont affect AppVeyor builds, but might affect local runs. Please update your local PowerShell version (`cinst powershell`) if you run it locally. 128 | 129 | - New function `Get-RemoteChecksum` that can be used instead of automatic checksum. 130 | - `Get-AuPackages` now accepts array of globs, for example `lsau 'cpu-z*','p*','copyq'`. 131 | - `Update-AUPackages` 132 | - New plugin `History` that creates markdown report of package updates grouped by dates. 133 | - Report plugin 134 | - Added link to `packageSourceUrl` and `projectUrl`. 135 | - New parameter `Title` to change report title. 136 | - New parameters for markdown report - `IconSize` and `NoIcons`. Icons are now shown by default. 137 | - Plugins documentation updated. 138 | - `Test-Package`: new parameter `VagrantNoClear` that will not delete existing packages from the vagrant package directory. 139 | - `update.ps1` script can now return keyword [ignore](https://github.com/majkinetor/au#ignoring-specific-errors) to cause `udpateall` to not report it as an error in output. 140 | - `Update-Package` 141 | - `au_GetLatest` can now force update by setting `$global:au_Force = $true`. 142 | - Refactoring code to use PowerShell 5 classes, functions now return `[AUPackage]` object. 143 | 144 | ### Bugfixes 145 | 146 | - `Git` plugin bugfixes. 147 | - Small fixes and tweaks all around. 148 | - Packages shouldn't drop from the results now no matter what happens with the `updateall` thread. 149 | - `$Latest.FileType` is not overwritten when its set in the `au_GetLatest`. 150 | 151 | ### CD 152 | 153 | Changes in [au-packages-template](https://github.com/majkinetor/au-packages-template): 154 | - Added new script `test_all.ps1` to force test all desired packages and randomly test package groups. See wiki page [setting up the force test](https://github.com/majkinetor/au/wiki/AppVeyor#setting-up-the-force-test-project-optional) for how to set this up on AppVeyor. 155 | 156 | ## 2016.11.5 157 | 158 | - `Update-Package` 159 | - It now automatically adds `$Latest.Filetype` based on the extension of the first URL it finds. 160 | 161 | ### CD 162 | 163 | - Added script `scripts\Install-AU.ps1` to install any AU version or branch using git tags. 164 | 165 | Changes in [au-packages-template](https://github.com/majkinetor/au-packages-template): 166 | - Added new AppVeyor commit command `[PUSH pkg1 ... pkgN]` to push any package to the community repository. 167 | 168 | ### Bugfixes 169 | 170 | - Fixed missing temporary directory for package download [ref](https://github.com/chocolatey/chocolatey-coreteampackages/pull/350). 171 | 172 | ## 2016.10.30 173 | 174 | - `Update-Package` 175 | - Show 'URL check' in output. 176 | - `$global:au_Version` can now be used when update is forced to explicitly provide version. 177 | - Invalid version in the nuspec file doesn't throw error any more but uses version 0.0 with warning. 178 | - `Update-AUPackages` 179 | - Added `BeforeEach` and `AfterEach` scripts to Options. 180 | - New Option `UpdateTimeout` to limit update total execution time ([#38](https://github.com/majkinetor/au/issues/38)). 181 | - `Git` plugin: only push files that are changed, not entire package content. 182 | - `Test-Package` 183 | - New string parameter `Vagrant` and global variable `$au_Vagrant` that contain path to the [chocolatey test environment](https://github.com/majkinetor/chocolatey-test-environment) so you can test the package using the Vagrant system. 184 | - PowerShell documentation improved. 185 | 186 | ### Bugfixes 187 | 188 | - Fixed frequent URL check timeout [#35](https://github.com/majkinetor/au/issues/35). 189 | - AU updated nuspec file to UTF-8 with BOM [#39](https://github.com/majkinetor/au/issues/39). 190 | - Checksum verification mode didn't work with updateall [#36](https://github.com/majkinetor/au/issues/36). 191 | - Small fixes. 192 | 193 | ### CD 194 | 195 | Changes in [au-packages-template](https://github.com/majkinetor/au-packages-template): 196 | - `update_all.ps1` now accepts `ForcedPackages` and `Root` parameters. 197 | - AppVeyor commit message parsing for AU options. 198 | 199 | 200 | ## 2016.10.9 201 | 202 | - `Update-Package` uses last returned value of `au_GetLatest` instead of everything ([#28](https://github.com/majkinetor/au/issues/28)). 203 | - `Test-Package` new option `Parameters` to support testing packages with custom parameters. 204 | 205 | ### Bugfixes 206 | 207 | - `Test-Package` - Uninstall test fixed. 208 | - `Git` plugin error - _A positional parameter cannot be found_ error fixed ([#31](https://github.com/majkinetor/au/issues/31)). 209 | - Small fixes. 210 | 211 | ## 2016.9.25 212 | 213 | **NOTE**: This update breaks compatibility with existing `update_all.ps1` scripts - parameter `Options` 214 | is now of the type ordered HashTable ( `[ordered]@{...}` ). This is the only required change for the script 215 | to continue working and behave the same as before, however, other things are required in order to fully use AU features: 216 | 217 | - Remove the user scripts `Save-XXX.ps1` as improved versions now come with AU (plugins). 218 | - Take a look at the [update_all.ps1](https://github.com/majkinetor/au-packages-template/blob/master/update_all.ps1) 219 | to see how plugins are used and setup. Migrate current custom options to the new style. 220 | See [plugins section](https://github.com/majkinetor/au#plugins) for details. 221 | 222 | Take a look at the [working example](https://github.com/majkinetor/au-packages/blob/master/update_all.ps1) and [plugin wiki page](https://github.com/majkinetor/au/wiki/Plugins). 223 | 224 | ### Changes 225 | 226 | - `Update-Package` 227 | - Support for Semantic Versioning [#21](https://github.com/majkinetor/au/issues/21). 228 | - `Test-Package` 229 | - Optional parameter Nu to test package from the .nupkg, .nuspec or directory. 230 | - Test chocolatey uninstaller. 231 | - Refactoring. 232 | - Installer improvements. 233 | - `Update-AUPackages` 234 | - Plugin system with the following default plugins included: 235 | - `RunInfo` - Save run info to the CliXml file and exclude sensitive information. 236 | - `Report` - Saves run info as a report file via included templates (currently markdown and text). 237 | - `Gist` - Save files as anonymous or user gists. 238 | - `Git` - Commits package changes to the git repository. 239 | - `Mail` - Send mail with attachments. 240 | - New parameter `NoPlugins` (by default `$Env:au_NoPlugins` to disable all plugins. 241 | - New option parameter `PluginPath` to specify additional path where plugins are located. 242 | - Output now shows if Push and Force options are used. 243 | - Created [au-packages-template](https://github.com/majkinetor/au-packages-template) to quick start AU. 244 | - Documentation is rewritten and [wiki](https://github.com/majkinetor/au/wiki) created. 245 | 246 | ### Bugfixes 247 | 248 | - Fixed bug due to the typo when pushing and sorting packages when executing `Update-AUPackages`. 249 | 250 | ### CD 251 | 252 | - New `./test.ps1` script that run some or all of the tests. 253 | - AU version environment variable added to `appveyor.yml`. 254 | 255 | 256 | ## 2016.9.21 257 | 258 | ### Bugfixes 259 | 260 | - Push was not working when package was updated. 261 | 262 | ## 2016.9.14.233253 263 | 264 | - `Update-Package` 265 | - New alias `lsau`. 266 | - Return an object of type `AUPackage` instead of text. 267 | - New parameters 268 | - `NoHostOutput` to not show any `Write-Host` output. 269 | - `Result` to hold the name of the global output variable. 270 | - Verbose parameter. 271 | - `NuspecVersion` added to the `$Latest` HashTable. 272 | - Pester tests. 273 | - run standalone, `update` in the package directory calls `./update.ps1`. 274 | - `README.md` made available via `man about_au`. 275 | - Consider global variable `$au_root` when looking for AU packages. 276 | - Optimization and refactoring. 277 | - Bugfixes 278 | - `Update-Packages` exception when `au_GetLatests` returned nothing. 279 | - `$Latest.Version` remains set to remote version when forcing update [#24](https://github.com/majkinetor/au/issues/24). 280 | - Chocolatey installation fixed [#15](https://github.com/majkinetor/au/issues/15) 281 | 282 | ### CD 283 | 284 | - Build module script. 285 | - Build chocolatey package script. 286 | - Publish to Github, Chocolatey and PSGallery. 287 | - `install.ps1` script to install/remove Powershell module in the current system. 288 | - AppVeyor automatic build. 289 | 290 | 291 | ## 2016.8.15 292 | 293 | - Use Chocoloatey fix notation with `Force` parameter. 294 | - Checksum verification using `ChecksumType32` and `ChecksumType64` when `Checksum32` or `Checksum64` are present in the `$Latest` HashTable. 295 | - `PackageName` added to the $Latest HashTable by the framework. 296 | - Use chocolatey cached nuget API key when all other methods fail. 297 | 298 | ### Bugfixes 299 | 300 | - Multiple updates happening at the same time lead to issues with the fix-choco method. 301 | - Copy fails if 'extensions' directory doesn't exist. 302 | 303 | 304 | ## 2016.8.13 305 | 306 | ### Bugfixes 307 | 308 | - Fixed `cpack` name collision with that of CMake. 309 | 310 | ## 2016.8.12 311 | 312 | - Support for Chocoloatey version 0.10.0. 313 | 314 | 315 | ## 2016.8.7 316 | 317 | - Automatic checksum. 318 | - Raise errors on search pattern not found. 319 | - Bugfixes and small improvements. 320 | 321 | ## 2016.6.6 322 | 323 | - First PowerShell Gallery version. 324 | 325 | ## 2016.2.19 326 | 327 | - First PoC version. 328 | --------------------------------------------------------------------------------