aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/plugins/module_utils/git.py
diff options
context:
space:
mode:
authorEgor Tensin <egor@tensin.name>2025-11-24 00:47:29 +0100
committerEgor Tensin <egor@tensin.name>2025-11-27 01:31:43 +0100
commitc4b418a791acf23742195709b3be777128c55ce1 (patch)
treee04967a81122048592be935647e63eeb89c0fb79 /plugins/module_utils/git.py
parentfix some ansible-lint warnings (diff)
downloadinfra-ansible-c4b418a791acf23742195709b3be777128c55ce1.tar.gz
infra-ansible-c4b418a791acf23742195709b3be777128c55ce1.zip
plugins: add safe_git
Diffstat (limited to 'plugins/module_utils/git.py')
-rw-r--r--plugins/module_utils/git.py96
1 files changed, 96 insertions, 0 deletions
diff --git a/plugins/module_utils/git.py b/plugins/module_utils/git.py
new file mode 100644
index 0000000..dec54c5
--- /dev/null
+++ b/plugins/module_utils/git.py
@@ -0,0 +1,96 @@
+import os
+import shlex
+
+from ansible.errors import AnsibleActionFail
+from ansible.module_utils.common.text.converters import to_text
+
+
+def is_work_tree(action, repo_dir, task_vars):
+ cmd_result = action._execute_module(
+ module_name='ansible.builtin.command',
+ module_args=dict(
+ argv=['git', 'rev-parse', '--is-inside-work-tree'],
+ chdir=repo_dir,
+ ),
+ task_vars=task_vars,
+ )
+ return not cmd_result.get('failed')
+
+
+def get_status(action, repo_dir, task_vars):
+ cmd_result = action._execute_module(
+ module_name='ansible.builtin.command',
+ module_args=dict(
+ argv=['git', 'status', '--porcelain'],
+ chdir=repo_dir,
+ ),
+ task_vars=task_vars,
+ )
+ if cmd_result.get('failed'):
+ raise AnsibleActionFail(f"Couldn't get git status for {repo_dir}", result=cmd_result)
+ return to_text(cmd_result['stdout'])
+
+
+def get_dirty_file_list(action, repo_dir, task_vars):
+ status = get_status(action, repo_dir, task_vars)
+ status = status.splitlines()
+ status = [line[3:] for line in status]
+ return status
+
+
+def get_remote_url(action, repo_dir, task_vars, remote='origin'):
+ cmd_result = action._execute_module(
+ module_name='ansible.builtin.command',
+ module_args=dict(
+ argv=['git', 'config', '--local', f'remote.{remote}.url'],
+ chdir=repo_dir,
+ ),
+ task_vars=task_vars,
+ )
+ if cmd_result.get('failed'):
+ raise AnsibleActionFail(f"Couldn't read the URL of remote '{remote}' in {repo_dir}", result=cmd_result)
+ return cmd_result['stdout']
+
+
+def update_remote(action, repo_dir, remote, task_vars, accept_hostkey=False):
+ ssh = os.environ.get('GIT_SSH', 'ssh')
+ ssh_opts = ''
+ if accept_hostkey:
+ ssh_opts += ' -o StrictHostKeyChecking=no'
+ ssh_command = shlex.quote(ssh) + ssh_opts
+
+ cmd_result = action._execute_module(
+ module_name='ansible.builtin.command',
+ module_args=dict(
+ argv=['env', f'GIT_SSH_COMMAND={ssh_command}', 'git', 'remote', 'update', remote],
+ chdir=repo_dir,
+ ),
+ task_vars=task_vars,
+ )
+ if cmd_result.get('failed'):
+ raise AnsibleActionFail(f"Couldn't update remote '{remote}' for {repo_dir}", result=cmd_result)
+
+
+def is_ancestor(action, repo_dir, remote, version, task_vars):
+ looks_like_hash = all(((c >= '0' and c <= '9') or (c >= 'a' and c <= 'f') for c in version))
+
+ remote_versions = [f'{remote}/{version}']
+ if looks_like_hash:
+ remote_versions += [version]
+
+ for _version in remote_versions:
+ cmd_result = action._execute_module(
+ module_name='ansible.builtin.command',
+ module_args=dict(
+ argv=['git', 'merge-base', '--is-ancestor', 'HEAD', _version],
+ chdir=repo_dir,
+ ),
+ task_vars=task_vars,
+ )
+ if cmd_result.get('failed'):
+ if cmd_result.get('stderr'):
+ continue
+ else:
+ return True
+
+ raise AnsibleActionFail(f"Couldn't deduce how the HEAD of {repo_dir} relates to remote version {remote}/{version}")