Add state option to git_config module (#50578)

* Add state option to git_config module

State present/absent option works like --set/--unset option for 'git config'.

* Change git_config to avoid useless parameter passed to git command

When unsetting value, command was : git config --unset foo ''.
Now command is : git config --unset foo.

* Add some integration tests to git_config module

* Add missing aliases file

* Change set up method

Using git command seems to cause troubles on some OS : changing config
by changing '.gitconfig' file.

* Remove some distros from tests pool

Git is not installed or is out of date on these distros.

* Fix aliases to skip tests on centos6

* Refactor tests of the git_config module

* Add use case when state=absent and value is defined
This commit is contained in:
Ari Stark 2019-02-12 03:49:53 +01:00 committed by ansibot
parent 984777b3d0
commit 2f85d62989
15 changed files with 257 additions and 5 deletions

View file

@ -51,6 +51,14 @@ options:
also specify the repo parameter. It defaults to system only when also specify the repo parameter. It defaults to system only when
not using I(list_all)=yes. not using I(list_all)=yes.
choices: [ "local", "global", "system" ] choices: [ "local", "global", "system" ]
state:
description:
- "Indicates the setting should be set/unset.
This parameter has higher precedence than I(value) parameter:
when I(state)=absent and I(value) is defined, I(value) is discarded."
choices: [ 'present', 'absent' ]
default: 'present'
version_added: '2.8'
value: value:
description: description:
- When specifying the name of a single setting, supply a value to - When specifying the name of a single setting, supply a value to
@ -69,6 +77,12 @@ EXAMPLES = '''
scope: global scope: global
value: status value: status
# Unset some settings in ~/.gitconfig
- git_config:
name: alias.ci
scope: global
state: absent
# Or system-wide: # Or system-wide:
- git_config: - git_config:
name: alias.remotev name: alias.remotev
@ -149,9 +163,10 @@ def main():
name=dict(type='str'), name=dict(type='str'),
repo=dict(type='path'), repo=dict(type='path'),
scope=dict(required=False, type='str', choices=['local', 'global', 'system']), scope=dict(required=False, type='str', choices=['local', 'global', 'system']),
state=dict(required=False, type='str', default='present', choices=['present', 'absent']),
value=dict(required=False) value=dict(required=False)
), ),
mutually_exclusive=[['list_all', 'name'], ['list_all', 'value']], mutually_exclusive=[['list_all', 'name'], ['list_all', 'value'], ['list_all', 'state']],
required_if=[('scope', 'local', ['repo'])], required_if=[('scope', 'local', ['repo'])],
required_one_of=[['list_all', 'name']], required_one_of=[['list_all', 'name']],
supports_check_mode=True, supports_check_mode=True,
@ -175,6 +190,12 @@ def main():
else: else:
scope = 'system' scope = 'system'
if params['state'] == 'absent':
unset = 'unset'
params['value'] = None
else:
unset = None
if params['value']: if params['value']:
new_value = params['value'] new_value = params['value']
else: else:
@ -212,16 +233,22 @@ def main():
k, v = value.split('=', 1) k, v = value.split('=', 1)
config_values[k] = v config_values[k] = v
module.exit_json(changed=False, msg='', config_values=config_values) module.exit_json(changed=False, msg='', config_values=config_values)
elif not new_value: elif not new_value and not unset:
module.exit_json(changed=False, msg='', config_value=out.rstrip()) module.exit_json(changed=False, msg='', config_value=out.rstrip())
elif unset and not out:
module.exit_json(changed=False, msg='no setting to unset')
else: else:
old_value = out.rstrip() old_value = out.rstrip()
if old_value == new_value: if old_value == new_value:
module.exit_json(changed=False, msg="") module.exit_json(changed=False, msg="")
if not module.check_mode: if not module.check_mode:
new_value_quoted = shlex_quote(new_value) if unset:
cmd = ' '.join(args + [new_value_quoted]) args.insert(len(args) - 1, "--" + unset)
cmd = ' '.join(args)
else:
new_value_quoted = shlex_quote(new_value)
cmd = ' '.join(args + [new_value_quoted])
(rc, out, err) = module.run_command(cmd, cwd=dir) (rc, out, err) = module.run_command(cmd, cwd=dir)
if err: if err:
module.fail_json(rc=rc, msg=err, cmd=cmd) module.fail_json(rc=rc, msg=err, cmd=cmd)
@ -232,7 +259,7 @@ def main():
before_header=' '.join(args), before_header=' '.join(args),
before=old_value + "\n", before=old_value + "\n",
after_header=' '.join(args), after_header=' '.join(args),
after=new_value + "\n" after=(new_value or '') + "\n"
), ),
changed=True changed=True
) )

View file

@ -0,0 +1,2 @@
shippable/posix/group3

View file

@ -0,0 +1,2 @@
[http]
proxy = foo

View file

@ -0,0 +1,16 @@
---
- import_tasks: setup_no_value.yml
- name: testing exclusion between state and list_all parameters
git_config:
list_all: true
state: absent
register: result
ignore_errors: yes
- name: assert git_config failed
assert:
that:
- result is failed
- "result.msg == 'parameters are mutually exclusive: list_all, state'"
...

View file

@ -0,0 +1,25 @@
---
- import_tasks: setup_no_value.yml
- name: setting value without state
git_config:
name: "{{ option_name }}"
value: "{{ option_value }}"
scope: "{{ option_scope }}"
register: set_result
- name: getting value without state
git_config:
name: "{{ option_name }}"
scope: "{{ option_scope }}"
register: get_result
- name: assert set changed and value is correct
assert:
that:
- set_result.changed == true
- set_result.diff.before == "\n"
- set_result.diff.after == option_value + "\n"
- get_result.changed == false
- get_result.config_value == option_value
...

View file

@ -0,0 +1,27 @@
---
- import_tasks: setup_no_value.yml
- name: setting value with state=present
git_config:
name: "{{ option_name }}"
value: "{{ option_value }}"
scope: "{{ option_scope }}"
state: present
register: result
- name: getting value with state=present
git_config:
name: "{{ option_name }}"
scope: "{{ option_scope }}"
state: present
register: get_result
- name: assert set changed and value is correct with state=present
assert:
that:
- set_result.changed == true
- set_result.diff.before == "\n"
- set_result.diff.after == option_value + "\n"
- get_result.changed == false
- get_result.config_value == option_value
...

View file

@ -0,0 +1,23 @@
---
# test code for the git_config module
- name: setup
import_tasks: setup.yml
- block:
# testing parameters exclusion: state and list_all
- import_tasks: exclusion_state_list-all.yml
# testing get/set option without state
- import_tasks: get_set_no_state.yml
# testing get/set option with state=present
- import_tasks: get_set_state_present.yml
# testing state=absent without value to delete
- import_tasks: unset_no_value.yml
# testing state=absent with value to delete
- import_tasks: unset_value.yml
# testing state=absent with value to delete and a defined value parameter
- import_tasks: precedence_between_unset_and_value.yml
# testing state=absent with check mode
- import_tasks: unset_check_mode.yml
when: git_installed is succeeded and git_version.stdout is version(git_version_supporting_includes, ">=")
...

View file

@ -0,0 +1,25 @@
---
- import_tasks: setup_value.yml
- name: unsetting value
git_config:
name: "{{ option_name }}"
scope: "{{ option_scope }}"
state: absent
value: bar
register: unset_result
- name: getting value
git_config:
name: "{{ option_name }}"
scope: "{{ option_scope }}"
register: get_result
- name: assert unset changed and deleted value
assert:
that:
- unset_result.changed == true
- unset_result.diff.before == option_value + "\n"
- unset_result.diff.after == "\n"
- get_result.config_value == ''
...

View file

@ -0,0 +1,11 @@
---
- name: verify that git is installed so this test can continue
command: which git
register: git_installed
ignore_errors: yes
- name: get git version, only newer than {{git_version_supporting_includes}} has includes option
shell: "git --version | grep 'git version' | sed 's/git version //'"
register: git_version
ignore_errors: yes
...

View file

@ -0,0 +1,8 @@
---
# ------
# set up : deleting gitconfig file
- name: set up without value
file:
path: ~/.gitconfig
state: absent
...

View file

@ -0,0 +1,8 @@
---
# ------
# set up : set gitconfig with value
- name: set up with value
copy:
src: gitconfig
dest: ~/.gitconfig
...

View file

@ -0,0 +1,25 @@
---
- import_tasks: setup_value.yml
- name: unsetting value with check mode
git_config:
name: "{{ option_name }}"
scope: "{{ option_scope }}"
state: absent
check_mode: yes
register: unset_result
- name: getting value
git_config:
name: "{{ option_name }}"
scope: "{{ option_scope }}"
register: get_result
- name: assert unset changed but dit not delete value
assert:
that:
- unset_result.changed == true
- unset_result.diff.before == option_value + "\n"
- unset_result.diff.after == "\n"
- get_result.config_value == option_value
...

View file

@ -0,0 +1,23 @@
---
- import_tasks: setup_no_value.yml
- name: unsetting value
git_config:
name: "{{ option_name }}"
scope: "{{ option_scope }}"
state: absent
register: unset_result
- name: getting value
git_config:
name: "{{ option_name }}"
scope: "{{ option_scope }}"
register: get_result
- name: assert unsetting didn't change
assert:
that:
- unset_result.changed == false
- unset_result.msg == 'no setting to unset'
- get_result.config_value == ''
...

View file

@ -0,0 +1,24 @@
---
- import_tasks: setup_value.yml
- name: unsetting value
git_config:
name: "{{ option_name }}"
scope: "{{ option_scope }}"
state: absent
register: unset_result
- name: getting value
git_config:
name: "{{ option_name }}"
scope: "{{ option_scope }}"
register: get_result
- name: assert unset changed and deleted value
assert:
that:
- unset_result.changed == true
- unset_result.diff.before == option_value + "\n"
- unset_result.diff.after == "\n"
- get_result.config_value == ''
...

View file

@ -0,0 +1,6 @@
---
git_version_supporting_includes: 1.7.10
option_name: http.proxy
option_value: 'foo'
option_scope: global
...