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/project/$Github_UserRepo/build/$Env:APPVEYOR_BUILD_NUMBER)" }
30 |
31 | @"
32 | [-red.svg)](#ok)
33 | [-blue.svg)](https://www.powershellgallery.com/packages/AU)
34 | [](#)[](#)
35 | **UTC**: $now [](#) [$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 |
--------------------------------------------------------------------------------