[PR #5829/4c4ef80c backport][stable-6] yarn: Fix state=latest not working with global=true (#5992)

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>
(cherry picked from commit 4c4ef80ca9)

Co-authored-by: Sargun Vohra <sargun.vohra@gmail.com>
This commit is contained in:
patchback[bot] 2023-02-13 22:07:12 +01:00 committed by GitHub
parent 53e5f51e57
commit 4f71c9384e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 112 additions and 25 deletions

View file

@ -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,