diff --git a/AU/Private/AUPackage.ps1 b/AU/Private/AUPackage.ps1 index bc029a83..7ea0a042 100644 --- a/AU/Private/AUPackage.ps1 +++ b/AU/Private/AUPackage.ps1 @@ -48,16 +48,14 @@ class AUPackage { return Get-Content $StreamsPath | ConvertFrom-Json } - UpdateStreams( [hashtable] $streams ){ - if (!$this.Streams) { Write-Host ''; $this.Streams = [pscustomobject] @{} } - $streams.Keys | sort { ConvertTo-AUVersion $_ } -Descending | % { - $stream = $_.ToString() - $version = $streams[$_].Version.ToString() - if ($this.Streams | Get-Member $stream) { - if ($this.Streams.$stream -ne 'ignore') { $this.Streams.$stream = $version } - } else { - $this.Streams | Add-Member $stream $version - } + UpdateStream( $stream, $version ){ + if (!$this.Streams) { $this.Streams = [pscustomobject] @{} } + $s = $stream.ToString() + $v = $version.ToString() + if ($this.Streams | Get-Member $s) { + if ($this.Streams.$s -ne 'ignore') { $this.Streams.$s = $v } + } else { + $this.Streams | Add-Member $s $v } $this.Streams | ConvertTo-Json | Set-Content $this.StreamsPath -Encoding UTF8 } diff --git a/AU/Public/Update-Package.ps1 b/AU/Public/Update-Package.ps1 index 9b109d42..2f8bac7a 100644 --- a/AU/Public/Update-Package.ps1 +++ b/AU/Public/Update-Package.ps1 @@ -284,9 +284,10 @@ function Update-Package { $Latest.Version = $package.RemoteVersion } - function set_latest( [HashTable]$latest, [string] $version ) { + function set_latest( [HashTable]$latest, [string] $version, $stream ) { if (!$latest.PackageName) { $latest.PackageName = $package.Name } if (!$latest.NuspecVersion) { $latest.NuspecVersion = $version } + if ($stream -and !$latest.Stream) { $latest.Stream = $stream } $package.NuspecVersion = $latest.NuspecVersion $global:Latest = $latest } @@ -314,6 +315,9 @@ function Update-Package { $package.NuspecXml.package.metadata.version = $package.RemoteVersion.ToString() $package.SaveNuspec() + if ($global:Latest.Stream) { + $package.UpdateStream($global:Latest.Stream, $package.RemoteVersion) + } } $sr = au_SearchReplace @@ -386,11 +390,15 @@ function Update-Package { throw "au_GetLatest failed`n$_" } - if ($res.Streams) { + if ($res.ContainsKey('Streams')) { + if (!$res.Streams) { throw "au_GetLatest's streams returned nothing" } if ($res.Streams -isnot [HashTable]) { throw "au_GetLatest's streams don't return a HashTable result but $($res.Streams.GetType())" } if ($Include) { - if ($Include -isnot [string] -and $Include -isnot [Array]) { throw "`$Include must be either a String or an Array but is $($Include.GetType())" } + if ($Include -isnot [string] -and $Include -isnot [double] -and $Include -isnot [Array]) { + throw "`$Include must be either a String, a Double or an Array but is $($Include.GetType())" + } + if ($Include -is [double]) { $Include = $Include -as [string] } if ($Include -is [string]) { [Array] $Include = $Include -split ',' | foreach { ,$_.Trim() } } } elseif ($Force) { $Include = @($res.Streams.Keys | sort { [AUVersion]$_ } -Descending | select -First 1) @@ -421,11 +429,9 @@ function Update-Package { return } - set_latest $stream $package.Streams.$_ + set_latest $stream $package.Streams.$_ $_ process_stream } - - $package.UpdateStreams($streams) } else { '' | result set_latest $res $package.NuspecVersion diff --git a/tests/Update-Package.Streams.Tests.ps1 b/tests/Update-Package.Streams.Tests.ps1 new file mode 100644 index 00000000..f35deb66 --- /dev/null +++ b/tests/Update-Package.Streams.Tests.ps1 @@ -0,0 +1,303 @@ +remove-module AU -ea ignore +import-module $PSScriptRoot\..\AU -force + +Describe 'Update-Package using streams' -Tag updatestreams { + $saved_pwd = $pwd + + function global:get_latest([string] $Version, [string] $URL32, [string] $Checksum32) { + $streams = @{ + '1.4' = @{ Version = '1.4-beta1'; URL32 = 'test.1.4-beta1' } + '1.2' = @{ Version = '1.2.4'; URL32 = 'test.1.2.4' } + '1.3' = @{ Version = '1.3.1'; URL32 = 'test.1.3.1' } + } + if ($Version) { + $stream = (ConvertTo-AUVersion $Version).ToString(2) + if (!$URL32) { + $URL32 = if ($streams.$stream) { $streams.$stream.URL32 } else { "test.$Version" } + } + $streams.Remove($stream) + $s = @{ Version = $Version; URL32 = $URL32 } + if ($Checksum32) { $s += @{ Checksum32 = $Checksum32 } } + $streams.Add($stream, $s) + } + $command = "function global:au_GetLatest { @{ Streams = @{`n" + foreach ($item in $streams.Keys) { + $command += "'$item' = @{Version = '$($streams.$item.Version)'; URL32 = '$($streams.$item.URL32)'" + if ($streams.$item.Checksum32) { $command += "; Checksum32 = '$($streams.$item.Checksum32)'" } + $command += "}`n" + } + $command += "} } }" + $command | iex + } + + function global:seach_replace() { + "function global:au_SearchReplace { @{} }" | iex + } + + function global:nuspec_file() { [xml](gc TestDrive:\test_package_with_streams\test_package_with_streams.nuspec) } + + function global:json_file() { (gc TestDrive:\test_package_with_streams\test_package_with_streams.json) | ConvertFrom-Json } + + BeforeEach { + cd $TestDrive + rm -Recurse -Force TestDrive:\test_package_with_streams -ea ignore + cp -Recurse -Force $PSScriptRoot\test_package_with_streams TestDrive:\test_package_with_streams + cd $TestDrive\test_package_with_streams + + $global:au_Timeout = 100 + $global:au_Force = $false + $global:au_Include = '' + $global:au_NoHostOutput = $true + $global:au_NoCheckUrl = $true + $global:au_NoCheckChocoVersion = $true + $global:au_ChecksumFor = 'none' + $global:au_WhatIf = $false + $global:au_NoReadme = $false + + rv -Scope global Latest -ea ignore + 'BeforeUpdate', 'AfterUpdate' | % { rm "Function:/au_$_" -ea ignore } + get_latest + seach_replace + } + + InModuleScope AU { + + Context 'Updating' { + + It 'can set description from README.md' { + $readme = 'dummy readme & test' + '','', $readme | Out-File $TestDrive\test_package_with_streams\README.md + $res = update + + $res.Result -match 'Setting package description from README.md' | Should Be $true + (nuspec_file).package.metadata.description.InnerText.Trim() | Should Be $readme + } + + It 'does not set description from README.md with NoReadme parameter' { + $readme = 'dummy readme & test' + '','', $readme | Out-File $TestDrive\test_package_with_streams\README.md + $res = update -NoReadme + + $res.Result -match 'Setting package description from README.md' | Should BeNullOrEmpty + (nuspec_file).package.metadata.description | Should Be 'This is a test package with streams for Pester' + } + + It 'can backup and restore using WhatIf' { + get_latest -Version 1.2.3 + $global:au_Force = $true + $global:au_Version = '1.0' + $global:au_WhatIf = $true + $res = update -ChecksumFor 32 6> $null + + $res.Updated | Should Be $true + $res.RemoteVersion | Should Be '1.0' + (nuspec_file).package.metadata.version | Should Be 1.2.3 + (json_file).'1.2' | Should Be 1.2.3 + (json_file).'1.3' | Should Be 1.3.1 + (json_file).'1.4' | Should Be 1.4-beta1 + } + + It 'can let user override the version of the latest stream' { + get_latest -Version 1.2.3 + $global:au_Force = $true + $global:au_Version = '1.0' + + $res = update -ChecksumFor 32 6> $null + + $res.Updated | Should Be $true + $res.RemoteVersion | Should Be '1.0' + (json_file).'1.2' | Should Be 1.2.3 + (json_file).'1.3' | Should Be 1.3.1 + (json_file).'1.4' | Should Be 1.0 + } + + It 'can let user override the version of a specific stream' { + get_latest -Version 1.2.3 + $global:au_Force = $true + $global:au_Include = '1.2' + $global:au_Version = '1.0' + + $res = update -ChecksumFor 32 6> $null + + $res.Updated | Should Be $true + $res.RemoteVersion | Should Be '1.0' + (json_file).'1.2' | Should Be 1.0 + (json_file).'1.3' | Should Be 1.3.1 + (json_file).'1.4' | Should Be 1.4-beta1 + } + + It 'automatically verifies the checksum' { + $choco_path = gcm choco.exe | % Source + $choco_hash = Get-FileHash $choco_path -Algorithm SHA256 | % Hash + + get_latest -Version 1.2.4 -URL32 $choco_path -Checksum32 $choco_hash + + $res = update -ChecksumFor 32 6> $null + $res.Result -match 'hash checked for 32 bit version' | Should Be $true + } + + It 'automatically calculates the checksum' { + update -ChecksumFor 32 -Include 1.2 6> $null + + $global:Latest.Checksum32 | Should Not BeNullOrEmpty + $global:Latest.ChecksumType32 | Should Be 'sha256' + $global:Latest.Checksum64 | Should BeNullOrEmpty + $global:Latest.ChecksumType64 | Should BeNullOrEmpty + } + + It 'updates package when remote version is higher' { + $res = update + + $res.Updated | Should Be $true + $res.Result[-1] | Should Be 'Package updated' + (nuspec_file).package.metadata.version | Should Be 1.2.4 + (json_file).'1.2' | Should Be 1.2.4 + (json_file).'1.3' | Should Be 1.3.1 + (json_file).'1.4' | Should Be 1.4-beta1 + } + + It 'updates package when multiple remote versions are higher' { + get_latest -Version 1.4.0 + + $res = update + + $res.Updated | Should Be $true + $res.Result[-1] | Should Be 'Package updated' + (json_file).'1.2' | Should Be 1.2.4 + (json_file).'1.3' | Should Be 1.3.1 + (json_file).'1.4' | Should Be 1.4.0 + } + + It "does not update the package when remote version is not higher" { + get_latest -Version 1.2.3 + + $res = update + + $res.Updated | Should Be $false + (nuspec_file).package.metadata.version | Should Be 1.2.3 + (json_file).'1.2' | Should Be 1.2.3 + (json_file).'1.3' | Should Be 1.3.1 + (json_file).'1.4' | Should Be 1.4-beta1 + } + + It "throws an error when forcing update whithout specifying a stream" { + get_latest -Version 1.2.3 + { update -Force -Include 1.2,1.4 } | Should Throw 'A single stream must be included when forcing package update' + } + + It "updates the package when forced using choco fix notation" { + get_latest -Version 1.2.3 + + $res = update -Force -Include 1.2 + + $d = (get-date).ToString('yyyyMMdd') + $res.Updated | Should Be $true + $res.Result[-1] | Should Be 'Package updated' + $res.Result -match 'No new version found, but update is forced' | Should Not BeNullOrEmpty + (nuspec_file).package.metadata.version | Should Be "1.2.3.$d" + (json_file).'1.2' | Should Be "1.2.3.$d" + (json_file).'1.3' | Should Be 1.3.1 + (json_file).'1.4' | Should Be 1.4-beta1 + } + + It "does not use choco fix notation if the package remote version is higher" { + $res = update -Force -Include 1.2 + + $res.Updated | Should Be $true + (nuspec_file).package.metadata.version | Should Be 1.2.4 + (json_file).'1.2' | Should Be 1.2.4 + (json_file).'1.3' | Should Be 1.3.1 + (json_file).'1.4' | Should Be 1.4-beta1 + } + + It "searches and replaces given file lines when updating" { + function global:au_SearchReplace { + @{ + 'test_package_with_streams.nuspec' = @{ + '()(.*)()' = "`$1test.$($Latest.Version)`$3" + } + } + } + + update + + $nu = (nuspec_file).package.metadata + $nu.releaseNotes | Should Be 'test.1.2.4' + $nu.version | Should Be 1.2.4 + } + } + + Context 'Json file' { + + It 'loads a json file from the package directory' { + { update } | Should Not Throw + } + + It "uses version 0.0 if it can't find the json file in the current directory" { + rm *.json + update *> $null + $global:Latest.NuspecVersion | Should Be '0.0' + } + + It "uses version 0.0 on invalid json version" { + $streams = json_file + $streams.'1.2' = '{{PackageVersion}}' + $streams | ConvertTo-Json | Set-Content "$TestDrive\test_package_with_streams\test_package_with_streams.json" -Encoding UTF8 + + update -Include 1.2 *> $null + + $global:Latest.NuspecVersion | Should Be '0.0' + } + + It "uses version 0.0 when a new stream is available" { + get_latest -Version 1.5.0 + update *> $null + $global:Latest.NuspecVersion | Should Be '0.0' + } + + It "does not update the package when stream is ignored in json file" { + $streams = json_file + $streams.'1.2' = 'ignore' + $streams | ConvertTo-Json | Set-Content "$TestDrive\test_package_with_streams\test_package_with_streams.json" -Encoding UTF8 + + $res = update + + $res.Updated | Should Be $false + } + } + + Context 'au_GetLatest' { + + It "throws if au_GetLatest doesn't return HashTable" { + $return_value = @(1) + function global:au_GetLatest { @{ Streams = $return_value } } + { update } | Should Throw "don't return a HashTable" + $return_value = @() + { update } | Should Throw "returned nothing" + } + } + + Context 'Before and after update' { + It 'calls au_BeforeUpdate if package is updated' { + function au_BeforeUpdate { $global:Latest.test = 1 } + update -Include 1.2 + $global:Latest.test | Should Be 1 + } + + It 'calls au_AfterUpdate if package is updated' { + function au_AfterUpdate { $global:Latest.test = 1 } + update -Include 1.2 + $global:Latest.test | Should Be 1 + } + + It 'doesnt call au_BeforeUpdate if package is not updated' { + get_latest -Version 1.2.3 + function au_BeforeUpdate { $global:Latest.test = 1 } + update -Include 1.2 + $global:Latest.test | Should BeNullOrEmpty + } + } + } + + cd $saved_pwd +}