1
0
Fork 0
mirror of https://github.com/ansible-collections/community.general.git synced 2026-06-16 04:47:30 +00:00

xbps: include stdout and stderr in module output (#12234)

* fix(xbps): add stdout/stderr to module output and fix error message typo

Include stdout and stderr from the last executed command in all
exit_json and fail_json calls so users can see the actual xbps output
when debugging failures (addresses issue #2478).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* test(xbps): add basic unit tests using uthelper

Cover install (new, already present, failure) and remove (installed,
absent) scenarios. Verifies stdout/stderr are propagated in output.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* changelog: add fragment for PR 12234

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Add version_added.

Co-authored-by: Felix Fontein <felix@fontein.de>

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-authored-by: Felix Fontein <felix@fontein.de>
This commit is contained in:
Alexei Znamensky 2026-06-15 07:05:09 +12:00 committed by GitHub
parent 4775dfbcb2
commit 7dc2441fc8
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 186 additions and 16 deletions

View file

@ -155,6 +155,18 @@ packages:
type: list
sample: ["ansible"]
returned: success
stdout:
description: Standard output of the last executed command.
returned: when a package manager command was executed
type: str
sample: ''
version_added: 13.1.0
stderr:
description: Standard error of the last executed command.
returned: when a package manager command was executed
type: str
sample: ''
version_added: 13.1.0
"""
@ -202,7 +214,7 @@ def query_package(module, xbps_path, name, state="present"):
def update_package_db(module, xbps_path):
"""Returns True if update_package_db changed"""
"""Returns (changed, stdout, stderr) for the sync command"""
cmd = [xbps_path["install"], "-S"]
cmd = append_flags(module, xbps_path, cmd)
if module.params["accept_pubkey"]:
@ -212,10 +224,10 @@ def update_package_db(module, xbps_path):
rc, stdout, stderr = module.run_command(cmd, check_rc=False, data=stdin)
if "Failed to import pubkey" in stderr:
module.fail_json(msg="Failed to import pubkey for repository")
module.fail_json(msg="Failed to import pubkey for repository", stdout=stdout, stderr=stderr)
if rc != 0:
module.fail_json(msg="Could not update package db")
return "avg rate" in stdout
module.fail_json(msg="Could not update package db", stdout=stdout, stderr=stderr)
return "avg rate" in stdout, stdout, stderr
def upgrade_xbps(module, xbps_path, exit_on_success=False):
@ -223,7 +235,7 @@ def upgrade_xbps(module, xbps_path, exit_on_success=False):
cmdupgradexbps = append_flags(module, xbps_path, cmdupgradexbps)
rc, stdout, stderr = module.run_command(cmdupgradexbps, check_rc=False)
if rc != 0:
module.fail_json(msg="Could not upgrade xbps itself")
module.fail_json(msg="Could not upgrade xbps itself", stdout=stdout, stderr=stderr)
def upgrade(module, xbps_path):
@ -236,27 +248,29 @@ def upgrade(module, xbps_path):
rc, stdout, stderr = module.run_command(cmdneedupgrade, check_rc=False)
if rc == 0:
if len(stdout.splitlines()) == 0:
module.exit_json(changed=False, msg="Nothing to upgrade")
module.exit_json(changed=False, msg="Nothing to upgrade", stdout=stdout, stderr=stderr)
elif module.check_mode:
module.exit_json(changed=True, msg="Would have performed upgrade")
module.exit_json(changed=True, msg="Would have performed upgrade", stdout=stdout, stderr=stderr)
else:
rc, stdout, stderr = module.run_command(cmdupgrade, check_rc=False)
if rc == 0:
module.exit_json(changed=True, msg="System upgraded")
module.exit_json(changed=True, msg="System upgraded", stdout=stdout, stderr=stderr)
elif rc == 16 and module.params["upgrade_xbps"]:
upgrade_xbps(module, xbps_path)
# avoid loops by not trying self-upgrade again
module.params["upgrade_xbps"] = False
upgrade(module, xbps_path)
else:
module.fail_json(msg="Could not upgrade")
module.fail_json(msg="Could not upgrade", stdout=stdout, stderr=stderr)
else:
module.fail_json(msg="Could not upgrade")
module.fail_json(msg="Could not upgrade", stdout=stdout, stderr=stderr)
def remove_packages(module, xbps_path, packages):
"""Returns true if package removal succeeds"""
changed_packages = []
last_stdout = ""
last_stderr = ""
# Using a for loop in case of error, we can report the package that failed
for package in packages:
# Query the package first, to see if we even need to remove
@ -269,12 +283,20 @@ def remove_packages(module, xbps_path, packages):
rc, stdout, stderr = module.run_command(cmd, check_rc=False)
if rc != 0:
module.fail_json(msg=f"failed to remove {package}")
module.fail_json(msg=f"failed to remove {package}", stdout=stdout, stderr=stderr)
last_stdout = stdout
last_stderr = stderr
changed_packages.append(package)
if len(changed_packages) > 0:
module.exit_json(changed=True, msg=f"removed {len(changed_packages)} package(s)", packages=changed_packages)
module.exit_json(
changed=True,
msg=f"removed {len(changed_packages)} package(s)",
packages=changed_packages,
stdout=last_stdout,
stderr=last_stderr,
)
module.exit_json(changed=False, msg="package(s) already absent")
@ -304,9 +326,13 @@ def install_packages(module, xbps_path, state, packages):
module.params["upgrade_xbps"] = False
install_packages(module, xbps_path, state, packages)
elif rc != 0 and not (state == "latest" and rc == 17):
module.fail_json(msg=f"failed to install {len(toInstall)} packages(s)", packages=toInstall)
module.fail_json(
msg=f"failed to install {len(toInstall)} package(s)", packages=toInstall, stdout=stdout, stderr=stderr
)
module.exit_json(changed=True, msg=f"installed {len(toInstall)} package(s)", packages=toInstall)
module.exit_json(
changed=True, msg=f"installed {len(toInstall)} package(s)", packages=toInstall, stdout=stdout, stderr=stderr
)
def check_packages(module, xbps_path, packages, state):
@ -336,10 +362,13 @@ def update_cache(module, xbps_path, upgrade_planned):
if upgrade_planned:
return
module.exit_json(changed=True, msg="Would have updated the package cache")
changed = update_package_db(module, xbps_path)
changed, stdout, stderr = update_package_db(module, xbps_path)
if not upgrade_planned:
module.exit_json(
changed=changed, msg=("Updated the package master lists" if changed else "Package list already up to date")
changed=changed,
msg=("Updated the package master lists" if changed else "Package list already up to date"),
stdout=stdout,
stderr=stderr,
)