From 3eeafecd1fcdb8096ac0b106101beb87ac8c1c4d Mon Sep 17 00:00:00 2001 From: Kit Ham Date: Sat, 4 May 2024 23:25:21 +1000 Subject: [PATCH] homebrew: Add force_formula parameter to pass --formula to brew command (#8275) * homebrew: Add force_formula parameter to pass --formula to brew command Some formulas have names that are also cask formulas (e.g. docker). When trying to install such a formula, brew prints a warning and returns a non-zero exit code. This causes Ansible to halt and report the failure. By allowing the task to set force_formula, we can sidestep this problem. * Add changelog fragment * Apply suggestions from code review Co-authored-by: Felix Fontein * Update plugins/modules/homebrew.py Co-authored-by: Felix Fontein --------- Co-authored-by: Felix Fontein --- .../fragments/8274-homebrew-force-formula.yml | 2 + plugins/modules/homebrew.py | 37 +++++++++++++++--- .../targets/docker/handlers/main.yml | 11 ++++++ .../integration/targets/docker/tasks/main.yml | 39 +++++++++++++++++++ 4 files changed, 84 insertions(+), 5 deletions(-) create mode 100644 changelogs/fragments/8274-homebrew-force-formula.yml create mode 100644 tests/integration/targets/docker/handlers/main.yml create mode 100644 tests/integration/targets/docker/tasks/main.yml diff --git a/changelogs/fragments/8274-homebrew-force-formula.yml b/changelogs/fragments/8274-homebrew-force-formula.yml new file mode 100644 index 0000000000..4a9e471f4c --- /dev/null +++ b/changelogs/fragments/8274-homebrew-force-formula.yml @@ -0,0 +1,2 @@ +minor_changes: + - "homebrew - adds ``force_formula`` parameter to disambiguate a formula from a cask of the same name (https://github.com/ansible-collections/community.general/issues/8274)." \ No newline at end of file diff --git a/plugins/modules/homebrew.py b/plugins/modules/homebrew.py index 5d471797a7..144d73a5a6 100644 --- a/plugins/modules/homebrew.py +++ b/plugins/modules/homebrew.py @@ -76,6 +76,13 @@ options: type: list elements: str version_added: '0.2.0' + force_formula: + description: + - Force the package(s) to be treated as a formula (equivalent to C(brew --formula)). + - To install a cask, use the M(community.general.homebrew_cask) module. + type: bool + default: false + version_added: 9.0.0 notes: - When used with a C(loop:) each package will be processed individually, it is much more efficient to pass the list directly to the O(name) option. @@ -141,6 +148,12 @@ EXAMPLES = ''' community.general.homebrew: upgrade_all: true upgrade_options: ignore-pinned + +- name: Force installing a formula whose name is also a cask name + community.general.homebrew: + name: ambiguous_formula + state: present + force_formula: true ''' RETURN = ''' @@ -404,7 +417,8 @@ class Homebrew(object): def __init__(self, module, path, packages=None, state=None, update_homebrew=False, upgrade_all=False, - install_options=None, upgrade_options=None): + install_options=None, upgrade_options=None, + force_formula=False): if not install_options: install_options = list() if not upgrade_options: @@ -414,7 +428,8 @@ class Homebrew(object): state=state, update_homebrew=update_homebrew, upgrade_all=upgrade_all, install_options=install_options, - upgrade_options=upgrade_options,) + upgrade_options=upgrade_options, + force_formula=force_formula) self._prep() @@ -487,6 +502,8 @@ class Homebrew(object): "--json=v2", self.current_package, ] + if self.force_formula: + cmd.append("--formula") rc, out, err = self.module.run_command(cmd) if err: self.failed = True @@ -632,10 +649,15 @@ class Homebrew(object): else: head = None + if self.force_formula: + formula = '--formula' + else: + formula = None + opts = ( [self.brew_path, 'install'] + self.install_options - + [self.current_package, head] + + [self.current_package, head, formula] ) cmd = [opt for opt in opts if opt] rc, out, err = self.module.run_command(cmd) @@ -919,7 +941,11 @@ def main(): default=None, type='list', elements='str', - ) + ), + force_formula=dict( + default=False, + type='bool', + ), ), supports_check_mode=True, ) @@ -951,6 +977,7 @@ def main(): if state in ('absent', 'removed', 'uninstalled'): state = 'absent' + force_formula = p['force_formula'] update_homebrew = p['update_homebrew'] if not update_homebrew: module.run_command_environ_update.update( @@ -967,7 +994,7 @@ def main(): brew = Homebrew(module=module, path=path, packages=packages, state=state, update_homebrew=update_homebrew, upgrade_all=upgrade_all, install_options=install_options, - upgrade_options=upgrade_options) + upgrade_options=upgrade_options, force_formula=force_formula) (failed, changed, message) = brew.run() changed_pkgs = brew.changed_pkgs unchanged_pkgs = brew.unchanged_pkgs diff --git a/tests/integration/targets/docker/handlers/main.yml b/tests/integration/targets/docker/handlers/main.yml new file mode 100644 index 0000000000..90a2e8017d --- /dev/null +++ b/tests/integration/targets/docker/handlers/main.yml @@ -0,0 +1,11 @@ +--- +# Copyright (c) Ansible Project +# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt) +# SPDX-License-Identifier: GPL-3.0-or-later + +- name: uninstall docker + community.general.homebrew: + name: docker + state: absent + become: true + become_user: "{{ brew_stat.stat.pw_name }}" diff --git a/tests/integration/targets/docker/tasks/main.yml b/tests/integration/targets/docker/tasks/main.yml new file mode 100644 index 0000000000..fd636247f4 --- /dev/null +++ b/tests/integration/targets/docker/tasks/main.yml @@ -0,0 +1,39 @@ +--- +# Copyright (c) Ansible Project +# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt) +# SPDX-License-Identifier: GPL-3.0-or-later + +- when: ansible_facts.distribution == 'MacOSX' + block: + - name: MACOS | Find brew binary + command: which brew + register: brew_which + + - name: MACOS | Get owner of brew binary + stat: + path: "{{ brew_which.stdout }}" + register: brew_stat + + - name: MACOS | Install docker without --formula + community.general.homebrew: + name: docker + state: present + become: true + become_user: "{{ brew_stat.stat.pw_name }}" + ignore_errors: true + register: result + + - name: Check that installing docker without --formula raises warning + assert: + that: + - result is failed + + - name: MACOS | Install docker + community.general.homebrew: + name: docker + state: present + force_formula: true + become: true + become_user: "{{ brew_stat.stat.pw_name }}" + notify: + - uninstall docker