1
0
Fork 0
mirror of https://github.com/ansible-collections/community.general.git synced 2024-09-14 20:13:21 +02:00

New module git config info (#7587)

Add new module git_config_info
This commit is contained in:
Günther Grill 2023-11-29 08:37:50 +01:00 committed by GitHub
parent 512b2c7389
commit 1b9d437be8
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
16 changed files with 406 additions and 1 deletions

2
.github/BOTMETA.yml vendored
View file

@ -526,6 +526,8 @@ files:
maintainers: russoz
$modules/git_config.py:
maintainers: djmattyg007 mgedmin
$modules/git_config_info.py:
maintainers: guenhter
$modules/github_:
maintainers: stpierre
$modules/github_deploy_key.py:

View file

@ -20,7 +20,7 @@ author:
requirements: ['git']
short_description: Read and write git configuration
description:
- The M(community.general.git_config) module changes git configuration by invoking 'git config'.
- The M(community.general.git_config) module changes git configuration by invoking C(git config).
This is needed if you do not want to use M(ansible.builtin.template) for the entire git
config file (for example because you need to change just C(user.email) in
/etc/.git/config). Solutions involving M(ansible.builtin.command) are cumbersome or

View file

@ -0,0 +1,187 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# Copyright (c) 2023, Guenther Grill <grill.guenther@gmail.com>
#
# 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
from __future__ import absolute_import, division, print_function
__metaclass__ = type
DOCUMENTATION = '''
---
module: git_config_info
author:
- Guenther Grill (@guenhter)
version_added: 8.1.0
requirements: ['git']
short_description: Read git configuration
description:
- The M(community.general.git_config_info) module reads the git configuration
by invoking C(git config).
extends_documentation_fragment:
- community.general.attributes
- community.general.attributes.info_module
options:
name:
description:
- The name of the setting to read.
- If not provided, all settings will be returned as RV(config_values).
type: str
path:
description:
- Path to a git repository or file for reading values from a specific repo.
- If O(scope) is V(local), this must point to a repository to read from.
- If O(scope) is V(file), this must point to specific git config file to read from.
- Otherwise O(path) is ignored if set.
type: path
scope:
description:
- Specify which scope to read values from.
- If set to V(global), the global git config is used. O(path) is ignored.
- If set to V(system), the system git config is used. O(path) is ignored.
- If set to V(local), O(path) must be set to the repo to read from.
- If set to V(file), O(path) must be set to the config file to read from.
choices: [ "global", "system", "local", "file" ]
default: "system"
type: str
'''
EXAMPLES = '''
- name: Read a system wide config
community.general.git_config_info:
name: core.editor
register: result
- name: Show value of core.editor
ansible.builtin.debug:
msg: "{{ result.config_value | default('(not set)', true) }}"
- name: Read a global config from ~/.gitconfig
community.general.git_config_info:
name: alias.remotev
scope: global
- name: Read a project specific config
community.general.git_config_info:
name: color.ui
scope: local
path: /etc
- name: Read all global values
community.general.git_config_info:
scope: global
- name: Read all system wide values
community.general.git_config_info:
- name: Read all values of a specific file
community.general.git_config_info:
scope: file
path: /etc/gitconfig
'''
RETURN = '''
---
config_value:
description: >
When O(name) is set, a string containing the value of the setting in name. If O(name) is not set, empty.
If a config key such as V(push.pushoption) has more then one entry, just the first one is returned here.
returned: success if O(name) is set
type: str
sample: "vim"
config_values:
description:
- This is a dictionary mapping a git configuration setting to a list of its values.
- When O(name) is not set, all configuration settings are returned here.
- When O(name) is set, only the setting specified in O(name) is returned here.
If that setting is not set, the key will still be present, and its value will be an empty list.
returned: success
type: dict
sample:
core.editor: ["vim"]
color.ui: ["auto"]
push.pushoption: ["merge_request.create", "merge_request.draft"]
alias.remotev: ["remote -v"]
'''
from ansible.module_utils.basic import AnsibleModule
def main():
module = AnsibleModule(
argument_spec=dict(
name=dict(type="str"),
path=dict(type="path"),
scope=dict(required=False, type="str", default="system", choices=["global", "system", "local", "file"]),
),
required_if=[
("scope", "local", ["path"]),
("scope", "file", ["path"]),
],
required_one_of=[],
supports_check_mode=True,
)
# We check error message for a pattern, so we need to make sure the messages appear in the form we're expecting.
# Set the locale to C to ensure consistent messages.
module.run_command_environ_update = dict(LANG='C', LC_ALL='C', LC_MESSAGES='C', LC_CTYPE='C')
name = module.params["name"]
path = module.params["path"]
scope = module.params["scope"]
run_cwd = path if scope == "local" else "/"
args = build_args(module, name, path, scope)
(rc, out, err) = module.run_command(args, cwd=run_cwd, expand_user_and_vars=False)
if rc == 128 and "unable to read config file" in err:
# This just means nothing has been set at the given scope
pass
elif rc >= 2:
# If the return code is 1, it just means the option hasn't been set yet, which is fine.
module.fail_json(rc=rc, msg=err, cmd=" ".join(args))
output_lines = out.strip("\0").split("\0") if out else []
if name:
first_value = output_lines[0] if output_lines else ""
config_values = {name: output_lines}
module.exit_json(changed=False, msg="", config_value=first_value, config_values=config_values)
else:
config_values = text_to_dict(output_lines)
module.exit_json(changed=False, msg="", config_value="", config_values=config_values)
def build_args(module, name, path, scope):
git_path = module.get_bin_path("git", True)
args = [git_path, "config", "--includes", "--null", "--" + scope]
if scope == "file":
args.append(path)
if name:
args.extend(["--get-all", name])
else:
args.append("--list")
return args
def text_to_dict(text_lines):
config_values = {}
for value in text_lines:
k, v = value.split("\n", 1)
if k in config_values:
config_values[k].append(v)
else:
config_values[k] = [v]
return config_values
if __name__ == "__main__":
main()

1
tests/.gitignore vendored
View file

@ -3,3 +3,4 @@
# SPDX-License-Identifier: GPL-3.0-or-later
output/
integration/inventory

View file

@ -0,0 +1,7 @@
# 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
azp/posix/3
skip/aix
destructive

View file

@ -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
[credential "https://some.com"]
username = yolo
[user]
name = foobar
[push]
pushoption = merge_request.create
pushoption = merge_request.draft

View file

@ -0,0 +1,7 @@
---
# 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
dependencies:
- setup_remote_tmp_dir

View file

@ -0,0 +1,26 @@
---
# 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
- import_tasks: "setup_file.yml"
- name: getting all system configs
git_config_info:
scope: system
register: get_result1
- name: getting all system configs for a key
git_config_info:
name: user.name
scope: system
register: get_result2
- name: assert value is correct
assert:
that:
- get_result1.config_value == ""
- 'get_result1.config_values == {}'
- get_result2.config_value == ""
- 'get_result2.config_values == {"user.name": []}'
...

View file

@ -0,0 +1,19 @@
---
# 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
- include_tasks: "{{ item.import_file }}"
- name: getting all values (as list) for a file config
git_config_info:
scope: "{{ item.git_scope }}"
path: "{{ item.git_file | default(omit) }}"
register: get_result
- name: assert value is correct
assert:
that:
- get_result.config_value == ""
- 'get_result.config_values == {"credential.https://some.com.username": ["yolo"], "user.name": ["foobar"], "push.pushoption": ["merge_request.create", "merge_request.draft"]}'
...

View file

@ -0,0 +1,20 @@
---
# 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
- include_tasks: "{{ item.import_file }}"
- name: getting only a single value (as string) from an option with multiple values in the git config file
git_config_info:
name: push.pushoption
scope: "{{ item.git_scope }}"
path: "{{ item.git_file | default(omit) }}"
register: get_result
- name: assert value is correct
assert:
that:
- get_result.config_value == "merge_request.create"
- 'get_result.config_values == {"push.pushoption": ["merge_request.create", "merge_request.draft"]}'
...

View file

@ -0,0 +1,38 @@
---
# 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
- include_tasks: "{{ item.import_file }}"
- name: getting simple file value1
git_config_info:
name: user.name
scope: "{{ item.git_scope }}"
path: "{{ item.git_file | default(omit) }}"
register: get_result1
- name: getting simple file value2
git_config_info:
name: "credential.https://some.com.username"
scope: "{{ item.git_scope }}"
path: "{{ item.git_file | default(omit) }}"
register: get_result2
- name: getting not existing value
git_config_info:
name: "user.email"
scope: "{{ item.git_scope }}"
path: "{{ item.git_file | default(omit) }}"
register: get_result3
- name: assert value is correct
assert:
that:
- get_result1.config_value == "foobar"
- 'get_result1.config_values == {"user.name": ["foobar"]}'
- get_result2.config_value == "yolo"
- 'get_result2.config_values == {"credential.https://some.com.username": ["yolo"]}'
- get_result3.config_value == ""
- 'get_result3.config_values == {"user.email": []}'
...

View file

@ -0,0 +1,33 @@
---
####################################################################
# WARNING: These are designed specifically for Ansible tests #
# and should not be used as examples of how to write Ansible roles #
####################################################################
# test code for the git_config_info module
# 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: setup
import_tasks: setup.yml
- block:
- include_tasks: get_simple_value.yml
loop:
- { import_file: setup_global.yml, git_scope: 'global' }
- { import_file: setup_file.yml, git_scope: 'file', git_file: "{{ remote_tmp_dir }}/gitconfig_file" }
- include_tasks: get_multi_value.yml
loop:
- { import_file: setup_global.yml, git_scope: 'global' }
- { import_file: setup_file.yml, git_scope: 'file', git_file: "{{ remote_tmp_dir }}/gitconfig_file" }
- include_tasks: get_all_values.yml
loop:
- { import_file: setup_global.yml, git_scope: 'global' }
- { import_file: setup_file.yml, git_scope: 'file', git_file: "{{ remote_tmp_dir }}/gitconfig_file" }
- include_tasks: error_handling.yml
when: git_installed is succeeded and git_version.stdout is version(git_version_supporting_includes, ">=")
...

View file

@ -0,0 +1,15 @@
---
# 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: verify that git is installed so this test can continue
command: which git
register: git_installed
ignore_errors: true
- 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: true
...

View file

@ -0,0 +1,16 @@
---
# 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
# ------
# set up : set gitconfig with value
- name: delete global config
file:
path: ~/.gitconfig
state: absent
- name: set up file config
copy:
src: gitconfig
dest: "{{ remote_tmp_dir }}/gitconfig_file"

View file

@ -0,0 +1,16 @@
---
# 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
# ------
# set up : set gitconfig with value
- name: delete file config
file:
path: "{{ remote_tmp_dir }}/gitconfig_file"
state: absent
- name: setup global config
copy:
src: gitconfig
dest: ~/.gitconfig

View file

@ -0,0 +1,7 @@
---
# 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
git_version_supporting_includes: 1.7.10
...