mirror of
https://github.com/ansible-collections/community.general.git
synced 2024-09-14 20:13:21 +02:00
yarn: Fix state=latest not working with global=true (#5829)
* Yarn module: fix state=latest not working with global=true * fix whitespace * add changelog fragment * add integration test cases * add only tests for this PR (install+upgrade) * fix assuming default global dir * fix list() not working when global=true and name a package with no binary * remove ignores * whitespace * Update changelogs/fragments/5829-fix-yarn-global.yml Co-authored-by: Felix Fontein <felix@fontein.de> * Update changelogs/fragments/5829-fix-yarn-global.yml Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com> --------- Co-authored-by: Felix Fontein <felix@fontein.de> Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
This commit is contained in:
parent
cd0a414e9f
commit
4c4ef80ca9
8 changed files with 112 additions and 25 deletions
4
changelogs/fragments/5829-fix-yarn-global.yml
Normal file
4
changelogs/fragments/5829-fix-yarn-global.yml
Normal file
|
@ -0,0 +1,4 @@
|
|||
bugfixes:
|
||||
- yarn - fix ``state=latest`` not working with ``global=true`` (https://github.com/ansible-collections/community.general/issues/5712).
|
||||
- yarn - fix ``global=true`` to check for the configured global folder instead of assuming the default (https://github.com/ansible-collections/community.general/pull/5829)
|
||||
- yarn - fix ``state=absent`` not working with ``global=true`` when the package does not include a binary (https://github.com/ansible-collections/community.general/pull/5829)
|
|
@ -163,8 +163,6 @@ from ansible.module_utils.basic import AnsibleModule
|
|||
|
||||
class Yarn(object):
|
||||
|
||||
DEFAULT_GLOBAL_INSTALLATION_PATH = os.path.expanduser('~/.config/yarn/global')
|
||||
|
||||
def __init__(self, module, **kwargs):
|
||||
self.module = module
|
||||
self.globally = kwargs['globally']
|
||||
|
@ -188,10 +186,12 @@ class Yarn(object):
|
|||
elif self.name is not None:
|
||||
self.name_version = self.name
|
||||
|
||||
def _exec(self, args, run_in_check_mode=False, check_rc=True):
|
||||
def _exec(self, args, run_in_check_mode=False, check_rc=True, unsupported_with_global=False):
|
||||
if not self.module.check_mode or (self.module.check_mode and run_in_check_mode):
|
||||
|
||||
if self.globally:
|
||||
with_global_arg = self.globally and not unsupported_with_global
|
||||
|
||||
if with_global_arg:
|
||||
# Yarn global arg is inserted before the command (e.g. `yarn global {some-command}`)
|
||||
args.insert(0, 'global')
|
||||
|
||||
|
@ -207,7 +207,7 @@ class Yarn(object):
|
|||
|
||||
# If path is specified, cd into that path and run the command.
|
||||
cwd = None
|
||||
if self.path and not self.globally:
|
||||
if self.path and not with_global_arg:
|
||||
if not os.path.exists(self.path):
|
||||
# Module will make directory if not exists.
|
||||
os.makedirs(self.path)
|
||||
|
@ -233,24 +233,21 @@ class Yarn(object):
|
|||
missing.append(self.name)
|
||||
return installed, missing
|
||||
|
||||
result, error = self._exec(cmd, True, False)
|
||||
# `yarn global list` should be treated as "unsupported with global" even though it exists,
|
||||
# because it only only lists binaries, but `yarn global add` can install libraries too.
|
||||
result, error = self._exec(cmd, run_in_check_mode=True, check_rc=False, unsupported_with_global=True)
|
||||
|
||||
if error:
|
||||
self.module.fail_json(msg=error)
|
||||
|
||||
for json_line in result.strip().split('\n'):
|
||||
data = json.loads(json_line)
|
||||
if self.globally:
|
||||
if data['type'] == 'list' and data['data']['type'].startswith('bins-'):
|
||||
# This is a string in format: 'bins-<PACKAGE_NAME>'
|
||||
installed.append(data['data']['type'][5:])
|
||||
else:
|
||||
if data['type'] == 'tree':
|
||||
dependencies = data['data']['trees']
|
||||
if data['type'] == 'tree':
|
||||
dependencies = data['data']['trees']
|
||||
|
||||
for dep in dependencies:
|
||||
name, version = dep['name'].rsplit('@', 1)
|
||||
installed.append(name)
|
||||
for dep in dependencies:
|
||||
name, version = dep['name'].rsplit('@', 1)
|
||||
installed.append(name)
|
||||
|
||||
if self.name not in installed:
|
||||
missing.append(self.name)
|
||||
|
@ -276,9 +273,12 @@ class Yarn(object):
|
|||
if not os.path.isfile(os.path.join(self.path, 'yarn.lock')):
|
||||
return outdated
|
||||
|
||||
cmd_result, err = self._exec(['outdated', '--json'], True, False)
|
||||
if err:
|
||||
self.module.fail_json(msg=err)
|
||||
cmd_result, err = self._exec(['outdated', '--json'], True, False, unsupported_with_global=True)
|
||||
|
||||
# the package.json in the global dir is missing a license field, so warnings are expected on stderr
|
||||
for line in err.splitlines():
|
||||
if json.loads(line)['type'] == 'error':
|
||||
self.module.fail_json(msg=err)
|
||||
|
||||
if not cmd_result:
|
||||
return outdated
|
||||
|
@ -340,7 +340,8 @@ def main():
|
|||
|
||||
# When installing globally, use the defined path for global node_modules
|
||||
if globally:
|
||||
path = Yarn.DEFAULT_GLOBAL_INSTALLATION_PATH
|
||||
_rc, out, _err = module.run_command([executable, 'global', 'dir'], check_rc=True)
|
||||
path = out.strip()
|
||||
|
||||
yarn = Yarn(module,
|
||||
name=name,
|
||||
|
|
|
@ -39,6 +39,7 @@
|
|||
package: 'iconv-lite'
|
||||
environment:
|
||||
PATH: "{{ node_bin_path }}:{{ansible_env.PATH}}"
|
||||
YARN_IGNORE_ENGINES: true
|
||||
block:
|
||||
|
||||
# Get the version of Yarn and register to a variable
|
||||
|
@ -135,3 +136,89 @@
|
|||
assert:
|
||||
that:
|
||||
- yarn_uninstall_package is changed
|
||||
|
||||
- name: 'Global install binary with explicit version (older version of package)'
|
||||
yarn:
|
||||
global: true
|
||||
executable: '{{ yarn_bin_path }}/yarn'
|
||||
name: prettier
|
||||
version: 2.0.0
|
||||
state: present
|
||||
environment:
|
||||
PATH: '{{ node_bin_path }}:{{ ansible_env.PATH }}'
|
||||
register: yarn_global_install_old_binary
|
||||
|
||||
- assert:
|
||||
that:
|
||||
- yarn_global_install_old_binary is changed
|
||||
|
||||
- name: 'Global upgrade old binary'
|
||||
yarn:
|
||||
global: true
|
||||
executable: '{{ yarn_bin_path }}/yarn'
|
||||
name: prettier
|
||||
state: latest
|
||||
environment:
|
||||
PATH: '{{ node_bin_path }}:{{ ansible_env.PATH }}'
|
||||
register: yarn_global_update_old_binary
|
||||
|
||||
- assert:
|
||||
that:
|
||||
- yarn_global_update_old_binary is changed
|
||||
|
||||
- name: 'Global remove a binary'
|
||||
yarn:
|
||||
global: true
|
||||
executable: '{{ yarn_bin_path }}/yarn'
|
||||
name: prettier
|
||||
state: absent
|
||||
environment:
|
||||
PATH: '{{ node_bin_path }}:{{ ansible_env.PATH }}'
|
||||
register: yarn_global_uninstall_binary
|
||||
|
||||
- assert:
|
||||
that:
|
||||
- yarn_global_uninstall_binary is changed
|
||||
|
||||
- name: 'Global install package with no binary with explicit version (older version of package)'
|
||||
yarn:
|
||||
global: true
|
||||
executable: '{{ yarn_bin_path }}/yarn'
|
||||
name: left-pad
|
||||
version: 1.1.0
|
||||
state: present
|
||||
environment:
|
||||
PATH: '{{ node_bin_path }}:{{ ansible_env.PATH }}'
|
||||
register: yarn_global_install_old_package
|
||||
|
||||
- assert:
|
||||
that:
|
||||
- yarn_global_install_old_package is changed
|
||||
|
||||
- name: 'Global upgrade old package with no binary'
|
||||
yarn:
|
||||
global: true
|
||||
executable: '{{ yarn_bin_path }}/yarn'
|
||||
name: left-pad
|
||||
state: latest
|
||||
environment:
|
||||
PATH: '{{ node_bin_path }}:{{ ansible_env.PATH }}'
|
||||
register: yarn_global_update_old_package
|
||||
|
||||
- assert:
|
||||
that:
|
||||
- yarn_global_update_old_package is changed
|
||||
|
||||
- name: 'Global remove a package with no binary'
|
||||
yarn:
|
||||
global: true
|
||||
executable: '{{ yarn_bin_path }}/yarn'
|
||||
name: left-pad
|
||||
state: absent
|
||||
environment:
|
||||
PATH: '{{ node_bin_path }}:{{ ansible_env.PATH }}'
|
||||
register: yarn_global_uninstall_package
|
||||
|
||||
- assert:
|
||||
that:
|
||||
- yarn_global_uninstall_package is changed
|
||||
|
|
|
@ -24,6 +24,5 @@ plugins/modules/rax_files.py validate-modules:parameter-state-invalid-choice
|
|||
plugins/modules/rax.py use-argspec-type-path # module deprecated - removed in 9.0.0
|
||||
plugins/modules/rhevm.py validate-modules:parameter-state-invalid-choice
|
||||
plugins/modules/xfconf.py validate-modules:return-syntax-error
|
||||
plugins/modules/yarn.py use-argspec-type-path
|
||||
tests/integration/targets/django_manage/files/base_test/simple_project/p1/manage.py compile-2.6 # django generated code
|
||||
tests/integration/targets/django_manage/files/base_test/simple_project/p1/manage.py compile-2.7 # django generated code
|
||||
|
|
|
@ -19,4 +19,3 @@ plugins/modules/rax_files.py validate-modules:parameter-state-invalid-choice
|
|||
plugins/modules/rax.py use-argspec-type-path # module deprecated - removed in 9.0.0
|
||||
plugins/modules/rhevm.py validate-modules:parameter-state-invalid-choice
|
||||
plugins/modules/xfconf.py validate-modules:return-syntax-error
|
||||
plugins/modules/yarn.py use-argspec-type-path
|
||||
|
|
|
@ -19,4 +19,3 @@ plugins/modules/rax_files.py validate-modules:parameter-state-invalid-choice
|
|||
plugins/modules/rax.py use-argspec-type-path # module deprecated - removed in 9.0.0
|
||||
plugins/modules/rhevm.py validate-modules:parameter-state-invalid-choice
|
||||
plugins/modules/xfconf.py validate-modules:return-syntax-error
|
||||
plugins/modules/yarn.py use-argspec-type-path
|
||||
|
|
|
@ -21,4 +21,3 @@ plugins/modules/rax.py use-argspec-type-path
|
|||
plugins/modules/rhevm.py validate-modules:parameter-state-invalid-choice
|
||||
plugins/modules/udm_user.py import-3.11 # Uses deprecated stdlib library 'crypt'
|
||||
plugins/modules/xfconf.py validate-modules:return-syntax-error
|
||||
plugins/modules/yarn.py use-argspec-type-path
|
||||
|
|
|
@ -21,4 +21,3 @@ plugins/modules/rax.py use-argspec-type-path
|
|||
plugins/modules/rhevm.py validate-modules:parameter-state-invalid-choice
|
||||
plugins/modules/udm_user.py import-3.11 # Uses deprecated stdlib library 'crypt'
|
||||
plugins/modules/xfconf.py validate-modules:return-syntax-error
|
||||
plugins/modules/yarn.py use-argspec-type-path
|
||||
|
|
Loading…
Reference in a new issue