win_chocolatey - move over to AnsibleModule and add allow_multiple (#48370)

pull/4420/head
Jordan Borean 2018-11-14 16:18:34 +10:00 committed by GitHub
parent d6bd842c5f
commit 9ac89af355
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 246 additions and 125 deletions

View File

@ -0,0 +1,3 @@
minor_changes:
- win_chocolatey - added the allow_multiple module option to allow side by side installs of the same package
- win_chocolatey - support bootstrapping Chocolatey from other URLs with any PS script that ends with ``.ps1``, originally this script had to be ``install.ps1``

View File

@ -7,44 +7,63 @@
#Requires -Module Ansible.ModuleUtils.ArgvParser #Requires -Module Ansible.ModuleUtils.ArgvParser
#Requires -Module Ansible.ModuleUtils.CommandUtil #Requires -Module Ansible.ModuleUtils.CommandUtil
#Requires -Module Ansible.ModuleUtils.Legacy #AnsibleRequires -CSharpUtil Ansible.Basic
$ErrorActionPreference = 'Stop'
# As of chocolatey 0.9.10, non-zero success exit codes can be returned # As of chocolatey 0.9.10, non-zero success exit codes can be returned
# See https://github.com/chocolatey/choco/issues/512#issuecomment-214284461 # See https://github.com/chocolatey/choco/issues/512#issuecomment-214284461
$successexitcodes = (0, 1605, 1614, 1641, 3010) $successexitcodes = (0, 1605, 1614, 1641, 3010)
$params = Parse-Args $args -supports_check_mode $true $spec = @{
$check_mode = Get-AnsibleParam -obj $params -name "_ansible_check_mode" -type "bool" -default $false options = @{
$verbosity = Get-AnsibleParam -obj $params -name "_ansible_verbosity" -type "int" -default 0 allow_empty_checksums = @{ type = "bool"; default = $false }
allow_multiple = @{ type = "bool"; default = $false }
$name = Get-AnsibleParam -obj $params -name "name" -type "list" -failifempty $true allow_prerelease = @{ type = "bool"; default = $false }
architecture = @{ type = "str"; default = "default"; choices = "default", "x86" }
$allow_empty_checksums = Get-AnsibleParam -obj $params -name "allow_empty_checksums" -type "bool" -default $false install_args = @{ type = "str" }
$allow_prerelease = Get-AnsibleParam -obj $params -name "allow_prerelease" -type "bool" -default $false ignore_checksums = @{ type = "bool"; default = $false }
$architecture = Get-AnsibleParam -obj $params -name "architecture" -type "str" -default "default" -validateset "default", "x86" ignore_dependencies = @{ type = "bool"; default = $false }
$install_args = Get-AnsibleParam -obj $params -name "install_args" -type "str" force = @{ type = "bool"; default = $false }
$ignore_checksums = Get-AnsibleParam -obj $params -name "ignore_checksums" -type "bool" -default $false name = @{ type = "list"; elements = "str"; required = $true }
$ignore_dependencies = Get-AnsibleParam -obj $params -name "ignore_dependencies" -type "bool" -default $false package_params = @{ type = "str"; aliases = "params" }
$force = Get-AnsibleParam -obj $params -name "force" -type "bool" -default $false proxy_url = @{ type = "str" }
$package_params = Get-AnsibleParam -obj $params -name "package_params" -type "str" -aliases "params" proxy_username = @{ type = "str" }
$proxy_url = Get-AnsibleParam -obj $params -name "proxy_url" -type "str" proxy_password = @{ type = "str"; no_log = $true }
$proxy_username = Get-AnsibleParam -obj $params -name "proxy_username" -type "str" skip_scripts = @{ type = "bool"; default = $false }
$proxy_password = Get-AnsibleParam -obj $params -name "proxy_password" -type "str" -failifempty ($null -ne $proxy_username) source = @{ type = "str" }
$skip_scripts = Get-AnsibleParam -obj $params -name "skip_scripts" -type "bool" -default $false source_username = @{ type = "str" }
$source = Get-AnsibleParam -obj $params -name "source" -type "str" source_password = @{ type = "str"; no_log = $true }
$source_username = Get-AnsibleParam -obj $params -name "source_username" -type "str" state = @{ type = "str"; default = "present"; choices = "absent", "downgrade", "latest", "present", "reinstalled" }
$source_password = Get-AnsibleParam -obj $params -name "source_password" -type "str" -failifempty ($null -ne $source_username) timeout = @{ type = "int"; default = 2700; aliases = "execution_timeout" }
$state = Get-AnsibleParam -obj $params -name "state" -type "str" -default "present" -validateset "absent","downgrade","latest","present","reinstalled" validate_certs = @{ type = "bool"; default = $false }
$timeout = Get-AnsibleParam -obj $params -name "timeout" -type "int" -default 2700 -aliases "execution_timeout" version = @{ type = "str" }
$validate_certs = Get-AnsibleParam -obj $params -name "validate_certs" -type "bool" -default $true }
$version = Get-AnsibleParam -obj $params -name "version" -type "str" supports_check_mode = $true
$result = @{
changed = $false
rc = 0
} }
$module = [Ansible.Basic.AnsibleModule]::Create($args, $spec)
$allow_empty_checksums = $module.Params.allow_empty_checksums
$allow_multiple = $module.Params.allow_multiple
$allow_prerelease = $module.Params.allow_prerelease
$architecture = $module.Params.architecture
$install_args = $module.Params.install_args
$ignore_checksums = $module.Params.ignore_checksums
$ignore_dependencies = $module.Params.ignore_dependencies
$force = $module.Params.force
$name = $module.Params.name
$package_params = $module.Params.package_params
$proxy_url = $module.Params.proxy_url
$proxy_username = $module.Params.proxy_username
$proxy_password = $module.Params.proxy_password
$skip_scripts = $module.Params.skip_scripts
$source = $module.Params.source
$source_username = $module.Params.source_username
$source_password = $module.Params.source_password
$state = $module.Params.state
$timeout = $module.Params.timeout
$validate_certs = $module.Params.validate_certs
$version = $module.Params.version
$module.Result.rc = 0
if (-not $validate_certs) { if (-not $validate_certs) {
[System.Net.ServicePointManager]::ServerCertificateValidationCallback = { $true } [System.Net.ServicePointManager]::ServerCertificateValidationCallback = { $true }
@ -55,13 +74,13 @@ Function Get-CommonChocolateyArguments {
# run with Chocolatey # run with Chocolatey
$arguments = [System.Collections.ArrayList]@("--yes", "--no-progress") $arguments = [System.Collections.ArrayList]@("--yes", "--no-progress")
# global vars that control the arguments # global vars that control the arguments
if ($check_mode) { if ($module.CheckMode) {
$arguments.Add("--what-if") > $null $arguments.Add("--what-if") > $null
} }
if ($verbosity -gt 4) { if ($module.Verbosity -gt 4) {
$arguments.Add("--debug") > $null $arguments.Add("--debug") > $null
$arguments.Add("--verbose") > $null $arguments.Add("--verbose") > $null
} elseif ($verbosity -gt 3) { } elseif ($module.Verbosity -gt 3) {
$arguments.Add("--verbose") > $null $arguments.Add("--verbose") > $null
} else { } else {
$arguments.Add("--limit-output") > $null $arguments.Add("--limit-output") > $null
@ -74,6 +93,7 @@ Function Get-InstallChocolateyArguments {
param( param(
[bool]$allow_downgrade, [bool]$allow_downgrade,
[bool]$allow_empty_checksums, [bool]$allow_empty_checksums,
[bool]$allow_multiple,
[bool]$allow_prerelease, [bool]$allow_prerelease,
[String]$architecture, [String]$architecture,
[bool]$force, [bool]$force,
@ -102,6 +122,9 @@ Function Get-InstallChocolateyArguments {
if ($allow_empty_checksums) { if ($allow_empty_checksums) {
$arguments.Add("--allow-empty-checksums") > $null $arguments.Add("--allow-empty-checksums") > $null
} }
if ($allow_multiple) {
$arguments.Add("--allow-multiple") > $null
}
if ($allow_prerelease) { if ($allow_prerelease) {
$arguments.Add("--prerelease") > $null $arguments.Add("--prerelease") > $null
} }
@ -202,8 +225,8 @@ Function Install-Chocolatey {
} }
if ($source) { if ($source) {
# check if the URL already contains the path to install.ps1 # check if the URL already contains the path to PS script
if ($source.EndsWith("install.ps1")) { if ($source.EndsWith(".ps1")) {
$script_url = $source $script_url = $source
} else { } else {
# chocolatey server automatically serves a script at # chocolatey server automatically serves a script at
@ -230,19 +253,19 @@ Function Install-Chocolatey {
try { try {
$install_script = $client.DownloadString($script_url) $install_script = $client.DownloadString($script_url)
} catch { } catch {
Fail-Json -obj $result -message "Failed to download Chocolatey script from '$script_url': $($_.Exception.Message)" $module.FailJson("Failed to download Chocolatey script from '$script_url'; $($_.Exception.Message)", $_)
} }
if (-not $check_mode) { if (-not $module.CheckMode) {
$res = Run-Command -command "powershell.exe -" -stdin $install_script -environment $environment $res = Run-Command -command "powershell.exe -" -stdin $install_script -environment $environment
if ($res.rc -ne 0) { if ($res.rc -ne 0) {
$result.rc = $res.rc $module.Result.rc = $res.rc
$result.stdout = $res.stdout $module.Result.stdout = $res.stdout
$result.stderr = $res.stderr $module.Result.stderr = $res.stderr
Fail-Json -obj $result -message "Chocolatey bootstrap installation failed." $module.FailJson("Chocolatey bootstrap installation failed.")
} }
Add-Warning -obj $result -message "Chocolatey was missing from this system, so it was installed during this task run." $module.Warn("Chocolatey was missing from this system, so it was installed during this task run.")
} }
$result.changed = $true $module.Result.changed = $true
# locate the newly installed choco.exe # locate the newly installed choco.exe
$choco_app = Get-Command -Name choco.exe -CommandType Application -ErrorAction SilentlyContinue $choco_app = Get-Command -Name choco.exe -CommandType Application -ErrorAction SilentlyContinue
@ -257,24 +280,24 @@ Function Install-Chocolatey {
$choco_app = Get-Command -Name $choco_path -CommandType Application -ErrorAction SilentlyContinue $choco_app = Get-Command -Name $choco_path -CommandType Application -ErrorAction SilentlyContinue
} }
} }
if ($check_mode -and $null -eq $choco_app) { if ($module.CheckMode -and $null -eq $choco_app) {
$result.skipped = $true $module.Result.skipped = $true
$result.msg = "Skipped check mode run on win_chocolatey as choco.exe cannot be found on the system" $module.Result.msg = "Skipped check mode run on win_chocolatey as choco.exe cannot be found on the system"
Exit-Json -obj $result $module.ExitJson()
} }
if (-not (Test-Path -Path $choco_app.Path)) { if (-not (Test-Path -Path $choco_app.Path)) {
Fail-Json -obj $result -message "Failed to find choco.exe, make sure it is added to the PATH or the env var 'ChocolateyInstall' is set" $module.FailJson("Failed to find choco.exe, make sure it is added to the PATH or the env var 'ChocolateyInstall' is set")
} }
$actual_version = Get-ChocolateyPackageVersion -choco_path $choco_app.Path -name chocolatey $actual_version = (Get-ChocolateyPackageVersion -choco_path $choco_app.Path -name chocolatey)[0]
if ([Version]$actual_version -lt [Version]"0.10.5") { if ([Version]$actual_version -lt [Version]"0.10.5") {
if ($check_mode) { if ($module.CheckMode) {
$result.skipped = $true $module.Result.skipped = $true
$result.msg = "Skipped check mode run on win_chocolatey as choco.exe is too old, a real run would have upgraded the executable. Actual: '$actual_version', Minimum Version: '0.10.5'" $module.Result.msg = "Skipped check mode run on win_chocolatey as choco.exe is too old, a real run would have upgraded the executable. Actual: '$actual_version', Minimum Version: '0.10.5'"
Exit-Json -obj $result $module.ExitJson()
} }
Add-Warning -obj $result -message "Chocolatey was older than v0.10.5 so it was upgraded during this task run." $module.Warn("Chocolatey was older than v0.10.5 so it was upgraded during this task run.")
Update-ChocolateyPackage -choco_path $choco_app.Path -packages @("chocolatey") ` Update-ChocolateyPackage -choco_path $choco_app.Path -packages @("chocolatey") `
-proxy_url $proxy_url -proxy_username $proxy_username ` -proxy_url $proxy_url -proxy_username $proxy_username `
-proxy_password $proxy_password -source $source ` -proxy_password $proxy_password -source $source `
@ -290,25 +313,24 @@ Function Get-ChocolateyPackageVersion {
[Parameter(Mandatory=$true)][String]$name [Parameter(Mandatory=$true)][String]$name
) )
$command = Argv-ToString -arguments @($choco_path, "list", "--local-only", "--exact", "--limit-output", $name) $command = Argv-ToString -arguments @($choco_path, "list", "--local-only", "--exact", "--limit-output", "--all-versions", $name)
$res = Run-Command -command $command $res = Run-Command -command $command
if ($res.rc -ne 0) { if ($res.rc -ne 0) {
$result.command = $command $module.Result.command = $command
$result.rc = $res.rc $module.Result.rc = $res.rc
$result.stdout = $res.stdout $module.Result.stdout = $res.stdout
$result.stderr = $res.stderr $module.Result.stderr = $res.stderr
Fail-Json -obj $result -message "Error checking installation status for the package '$name'" $module.FailJson("Error checking installation status for the package '$name'")
} }
$stdout = $res.stdout.Trim() $stdout = $res.stdout.Trim()
$version = $null $versions = $null
if ($stdout) { if ($stdout) {
# if a match occurs it is in the format of "package|version" we split # if a match occurs it is in the format of "package|version" we split
# by the last | to get the version in case package contains a pipe char # by the last | to get the version in case package contains a pipe char
$pipe_index = $stdout.LastIndexOf("|") $versions = @($stdout.Split("`r`n", [System.StringSplitOptions]::RemoveEmptyEntries) | ForEach-Object { $_.Substring($_.LastIndexOf("|") + 1) })
$version = $stdout.Substring($pipe_index + 1)
} }
return $version return ,$versions
} }
Function Update-ChocolateyPackage { Function Update-ChocolateyPackage {
@ -317,6 +339,7 @@ Function Update-ChocolateyPackage {
[Parameter(Mandatory=$true)][String[]]$packages, [Parameter(Mandatory=$true)][String[]]$packages,
[bool]$allow_downgrade, [bool]$allow_downgrade,
[bool]$allow_empty_checksums, [bool]$allow_empty_checksums,
[bool]$allow_multiple,
[bool]$allow_prerelease, [bool]$allow_prerelease,
[String]$architecture, [String]$architecture,
[bool]$force, [bool]$force,
@ -337,37 +360,52 @@ Function Update-ChocolateyPackage {
$arguments = [System.Collections.ArrayList]@($choco_path, "upgrade") $arguments = [System.Collections.ArrayList]@($choco_path, "upgrade")
$arguments.AddRange($packages) $arguments.AddRange($packages)
$common_args = Get-InstallChocolateyArguments -allow_downgrade $allow_downgrade `
-allow_empty_checksums $allow_empty_checksums -allow_prerelease $allow_prerelease ` $common_params = @{
-architecture $architecture -force $force -ignore_checksums $ignore_checksums ` allow_downgrade = $allow_downgrade
-ignore_dependencies $ignore_dependencies -install_args $install_args ` allow_empty_checksums = $allow_empty_checksums
-package_params $package_params -proxy_url $proxy_url -proxy_username $proxy_username ` allow_multiple = $allow_multiple
-proxy_password $proxy_password -skip_scripts $skip_scripts -source $source ` allow_prerelease = $allow_prerelease
-source_username $source_username -source_password $source_password -timeout $timeout ` architecture = $architecture
-version $version force = $force
ignore_checksums = $ignore_checksums
ignore_dependencies = $ignore_dependencies
install_args = $install_args
package_params = $package_params
proxy_url = $proxy_url
proxy_username = $proxy_username
proxy_password = $proxy_password
skip_scripts = $skip_scripts
source = $source
source_username = $source_username
source_password = $source_password
timeout = $timeout
version = $version
}
$common_args = Get-InstallChocolateyArguments @common_params
$arguments.AddRange($common_args) $arguments.AddRange($common_args)
$command = Argv-ToString -arguments $arguments $command = Argv-ToString -arguments $arguments
$res = Run-Command -command $command $res = Run-Command -command $command
$result.rc = $res.rc $module.Result.rc = $res.rc
if ($res.rc -notin $successexitcodes) { if ($res.rc -notin $successexitcodes) {
$result.command = $command $module.Result.command = $command
$result.stdout = $res.stdout $module.Result.stdout = $res.stdout
$result.stderr = $res.stderr $module.Result.stderr = $res.stderr
Fail-Json -obj $result -message "Error updating package(s) '$($packages -join ", ")'" $module.FailJson("Error updating package(s) '$($packages -join ", ")'")
} }
if ($verbosity -gt 1) { if ($module.Verbosity -gt 1) {
$result.stdout = $res.stdout $module.Result.stdout = $res.stdout
} }
if ($res.stdout -match ' upgraded (\d+)/\d+ package') { if ($res.stdout -match ' upgraded (\d+)/\d+ package') {
if ($Matches[1] -gt 0) { if ($Matches[1] -gt 0) {
$result.changed = $true $module.Result.changed = $true
} }
} }
# need to set to false in case the rc is not 0 and a failure didn't actually occur # need to set to false in case the rc is not 0 and a failure didn't actually occur
$result.failed = $false $module.Result.failed = $false
} }
Function Install-ChocolateyPackage { Function Install-ChocolateyPackage {
@ -376,6 +414,7 @@ Function Install-ChocolateyPackage {
[Parameter(Mandatory=$true)][String[]]$packages, [Parameter(Mandatory=$true)][String[]]$packages,
[bool]$allow_downgrade, [bool]$allow_downgrade,
[bool]$allow_empty_checksums, [bool]$allow_empty_checksums,
[bool]$allow_multiple,
[bool]$allow_prerelease, [bool]$allow_prerelease,
[String]$architecture, [String]$architecture,
[bool]$force, [bool]$force,
@ -396,33 +435,47 @@ Function Install-ChocolateyPackage {
$arguments = [System.Collections.ArrayList]@($choco_path, "install") $arguments = [System.Collections.ArrayList]@($choco_path, "install")
$arguments.AddRange($packages) $arguments.AddRange($packages)
$common_args = Get-InstallChocolateyArguments -allow_downgrade $allow_downgrade ` $common_params = @{
-allow_empty_checksums $allow_empty_checksums -allow_prerelease $allow_prerelease ` allow_downgrade = $allow_downgrade
-architecture $architecture -force $force -ignore_checksums $ignore_checksums ` allow_empty_checksums = $allow_empty_checksums
-ignore_dependencies $ignore_dependencies -install_args $install_args ` allow_multiple = $allow_multiple
-package_params $package_params -proxy_url $proxy_url -proxy_username $proxy_username ` allow_prerelease = $allow_prerelease
-proxy_password $proxy_password -skip_scripts $skip_scripts -source $source ` architecture = $architecture
-source_username $source_username -source_password $source_password -timeout $timeout ` force = $force
-version $version ignore_checksums = $ignore_checksums
ignore_dependencies = $ignore_dependencies
install_args = $install_args
package_params = $package_params
proxy_url = $proxy_url
proxy_username = $proxy_username
proxy_password = $proxy_password
skip_scripts = $skip_scripts
source = $source
source_username = $source_username
source_password = $source_password
timeout = $timeout
version = $version
}
$common_args = Get-InstallChocolateyArguments @common_params
$arguments.AddRange($common_args) $arguments.AddRange($common_args)
$command = Argv-ToString -arguments $arguments $command = Argv-ToString -arguments $arguments
$res = Run-Command -command $command $res = Run-Command -command $command
$result.rc = $res.rc $module.Result.rc = $res.rc
if ($res.rc -notin $successexitcodes) { if ($res.rc -notin $successexitcodes) {
$result.command = $command $module.Result.command = $command
$result.stdout = $res.stdout $module.Result.stdout = $res.stdout
$result.stderr = $res.stderr $module.Result.stderr = $res.stderr
Fail-Json -obj $result -message "Error installing package(s) '$($packages -join ', ')'" $module.FailJson("Error installing package(s) '$($packages -join ', ')'")
} }
if ($verbosity -gt 1) { if ($module.Verbosity -gt 1) {
$result.stdout = $res.stdout $module.Result.stdout = $res.stdout
} }
$result.changed = $true $module.Result.changed = $true
# need to set to false in case the rc is not 0 and a failure didn't actually occur # need to set to false in case the rc is not 0 and a failure didn't actually occur
$result.failed = $false $module.Result.failed = $false
} }
Function Uninstall-ChocolateyPackage { Function Uninstall-ChocolateyPackage {
@ -456,26 +509,30 @@ Function Uninstall-ChocolateyPackage {
$arguments.Add($timeout) > $null $arguments.Add($timeout) > $null
} }
if ($version) { if ($version) {
# Need to set allow-multiple to make sure choco doesn't uninstall all versions
$arguments.Add("--allow-multiple") > $null
$arguments.Add("--version") > $null $arguments.Add("--version") > $null
$arguments.Add($version) > $null $arguments.Add($version) > $null
} else {
$arguments.Add("--all-versions") > $null
} }
$command = Argv-ToString -arguments $arguments $command = Argv-ToString -arguments $arguments
$res = Run-Command -command $command $res = Run-Command -command $command
$result.rc = $res.rc $module.Result.rc = $res.rc
if ($res.rc -notin $successexitcodes) { if ($res.rc -notin $successexitcodes) {
$result.command = $command $module.Result.command = $command
$result.stdout = $res.stdout $module.Result.stdout = $res.stdout
$result.stderr = $res.stderr $module.Result.stderr = $res.stderr
Fail-Json -obj $result -message "Error uninstalling package(s) '$($packages -join ", ")'" $module.FailJson("Error uninstalling package(s) '$($packages -join ", ")'")
} }
if ($verbosity -gt 1) { if ($module.Verbosity -gt 1) {
$result.stdout = $res.stdout $module.Result.stdout = $res.stdout
} }
$result.changed = $true $module.Result.changed = $true
# need to set to false in case the rc is not 0 and a failure didn't actually occur # need to set to false in case the rc is not 0 and a failure didn't actually occur
$result.failed = $false $module.Result.failed = $false
} }
# get the full path to choco.exe, otherwise install/upgrade to at least 0.10.5 # get the full path to choco.exe, otherwise install/upgrade to at least 0.10.5
@ -490,13 +547,13 @@ foreach ($package in $name) {
# a dummy version so absent, latest, and downgrade will run with all # a dummy version so absent, latest, and downgrade will run with all
if ($package -eq "all") { if ($package -eq "all") {
if ($state -in @("present", "reinstalled")) { if ($state -in @("present", "reinstalled")) {
Fail-Json -obj $result -message "Cannot specify the package name as 'all' when state=$state" $module.FailJson("Cannot specify the package name as 'all' when state=$state")
} }
$package_version = "0.0.0" $package_versions = @("0.0.0")
} else { } else {
$package_version = Get-ChocolateyPackageVersion -choco_path $choco_path -name $package $package_versions = Get-ChocolateyPackageVersion -choco_path $choco_path -name $package
} }
$package_info.$package = $package_version $package_info.$package = $package_versions
} }
if ($state -in "absent", "reinstalled") { if ($state -in "absent", "reinstalled") {
@ -520,16 +577,26 @@ if ($state -in @("downgrade", "latest", "present", "reinstalled")) {
$missing_packages = $name $missing_packages = $name
} else { } else {
# otherwise only install the packages that are not installed # otherwise only install the packages that are not installed
$missing_packages = ($package_info.GetEnumerator() | Where-Object { $null -eq $_.Value }).Key $missing_packages = [System.Collections.ArrayList]@()
foreach ($package in $package_info.GetEnumerator()) {
if ($null -eq $package.Value) {
$missing_packages.Add($package.Key) > $null
}
}
} }
# if version is specified and installed version does not match, throw error # if version is specified and installed version does not match or not
# ignore this if force or is set # allow_multiple, throw error ignore this if force is set
if ($state -eq "present" -and $null -ne $version -and -not $force) { if ($state -eq "present" -and $null -ne $version -and -not $force) {
foreach ($package in $name) { foreach ($package in $name) {
$package_version = ($package_info.GetEnumerator() | Where-Object { $name -eq $_.Key -and $null -ne $_.Value }).Value $package_versions = [System.Collections.ArrayList]$package_info.$package
if ($null -ne $package_version -and $package_version -ne $version) { if ($package_versions.Count -gt 0) {
Fail-Json -obj $result -message "Chocolatey package '$package' is already installed at version '$package_version' but was expecting '$version'. Either change the expected version, set state=latest, or set force=yes to continue" if (-not $package_versions.Contains($version) -and -not $allow_multiple) {
$module.FailJson("Chocolatey package '$package' is already installed with version(s) '$($package_versions -join "', '")' but was expecting '$version'. Either change the expected version, set state=latest, set allow_multiple=yes, or set force=yes to continue")
} elseif ($version -notin $package_versions -and $allow_multiple) {
# add the package back into the list of missing packages if installing multiple
$missing_packages.Add($package) > $null
}
} }
} }
} }
@ -537,6 +604,7 @@ if ($state -in @("downgrade", "latest", "present", "reinstalled")) {
choco_path = $choco_path choco_path = $choco_path
allow_downgrade = ($state -eq "downgrade") allow_downgrade = ($state -eq "downgrade")
allow_empty_checksums = $allow_empty_checksums allow_empty_checksums = $allow_empty_checksums
allow_multiple = $allow_multiple
allow_prerelease = $allow_prerelease allow_prerelease = $allow_prerelease
architecture = $architecture architecture = $architecture
force = $force force = $force
@ -555,7 +623,7 @@ if ($state -in @("downgrade", "latest", "present", "reinstalled")) {
version = $version version = $version
} }
if ($null -ne $missing_packages) { if ($missing_packages) {
Install-ChocolateyPackage -packages $missing_packages @common_args Install-ChocolateyPackage -packages $missing_packages @common_args
} }
@ -571,4 +639,5 @@ if ($state -in @("downgrade", "latest", "present", "reinstalled")) {
} }
} }
Exit-Json -obj $result $module.ExitJson()

View File

@ -33,6 +33,14 @@ options:
type: bool type: bool
default: 'no' default: 'no'
version_added: '2.2' version_added: '2.2'
allow_multiple:
description:
- Allow the installation of multiple packages when I(version) is specified.
- Having multiple packages at different versions can cause issues if the
package doesn't support this. Use at your own risk.
type: bool
default: no
version_added: '2.8'
allow_prerelease: allow_prerelease:
description: description:
- Allow the installation of pre-release packages. - Allow the installation of pre-release packages.
@ -194,7 +202,8 @@ options:
version: version:
description: description:
- Specific version of the package to be installed. - Specific version of the package to be installed.
- Ignored when I(state) is set to C(absent). - When I(state) is set to C(absent), will uninstall the specific version
otherwise all versions of that package will be removed.
type: str type: str
notes: notes:
- Provide the C(version) parameter value as a string (e.g. C('6.1')), otherwise it - Provide the C(version) parameter value as a string (e.g. C('6.1')), otherwise it

View File

@ -87,7 +87,7 @@ Function Get-ChocolateyPackages {
param($choco_app) param($choco_app)
$command = Argv-ToString -arguments $choco_app.Path, "list", "--local-only", "-r" $command = Argv-ToString -arguments $choco_app.Path, "list", "--local-only", "--limit-output", "--all-versions"
$res = Run-Command -command $command $res = Run-Command -command $command
if ($res.rc -ne 0) { if ($res.rc -ne 0) {
$result.stdout = $res.stdout $result.stdout = $res.stdout
@ -97,7 +97,7 @@ Function Get-ChocolateyPackages {
} }
$packages_info = [System.Collections.ArrayList]@() $packages_info = [System.Collections.ArrayList]@()
$res.stdout -split "`r`n" | Where-Object { $_ -ne "" } | ForEach-Object { $res.stdout.Split("`r`n", [System.StringSplitOptions]::RemoveEmptyEntries) | ForEach-Object {
$packages_split = $_ -split "\|" $packages_split = $_ -split "\|"
$package_info = @{ $package_info = @{
package = $packages_split[0] package = $packages_split[0]

View File

@ -270,7 +270,7 @@
state: present state: present
version: 0.1.0 version: 0.1.0
register: fail_multiple_versions register: fail_multiple_versions
failed_when: fail_multiple_versions.msg != "Chocolatey package '" + test_choco_package1 + "' is already installed at version '0.0.1' but was expecting '0.1.0'. Either change the expected version, set state=latest, or set force=yes to continue" failed_when: fail_multiple_versions.msg != "Chocolatey package '" + test_choco_package1 + "' is already installed with version(s) '0.0.1' but was expecting '0.1.0'. Either change the expected version, set state=latest, set allow_multiple=yes, or set force=yes to continue"
- name: force the upgrade of an existing version - name: force the upgrade of an existing version
win_chocolatey: win_chocolatey:
@ -450,3 +450,43 @@
that: that:
- all_latest is changed - all_latest is changed
- all_latest_actual.stdout_lines == [test_choco_package1 + "|0.1.0"] - all_latest_actual.stdout_lines == [test_choco_package1 + "|0.1.0"]
- name: install newer version of package
win_chocolatey:
name: '{{ test_choco_package1 }}'
state: present
- name: install older package with allow_multiple
win_chocolatey:
name: '{{ test_choco_package1 }}'
state: present
allow_multiple: True
version: '0.0.1'
register: allow_multiple
- name: get result of install older package with allow_multiple
win_command: choco.exe list --local-only --limit-output --all-versions --exact {{ test_choco_package1|quote }}
register: allow_multiple_actual
- name: assert install older package with allow_multiple
assert:
that:
- allow_multiple is changed
- allow_multiple_actual.stdout == "ansible|0.1.0\r\nansible|0.0.1\r\n"
- name: uninstall specific version installed with allow_multiple
win_chocolatey:
name: '{{ test_choco_package1 }}'
state: absent
version: '0.0.1'
register: remove_multiple
- name: get result of uninstall specific version installed with allow_multiple
win_command: choco.exe list --local-only --limit-output --all-versions --exact {{ test_choco_package1|quote }}
register: remove_multiple_actual
- name: assert uninstall specific version installed with allow_multiple
assert:
that:
- remove_multiple is changed
- remove_multiple_actual.stdout == "ansible|0.1.0\r\n"