Repository: ansible/ansible-modules-core

Issue:
git module changes repo URL and returns "changed": false when run with --check
##### ISSUE TYPE
- Bug Report
##### COMPONENT NAME

git module
##### ANSIBLE VERSION

```
$ ansible --version
ansible 2.1.0.0
  config file = 
  configured module search path = Default w/o overrides
```
##### CONFIGURATION

```
[defaults]
nocows = yes
vault_password_file = .vault-password
allow_world_readable_tmpfiles = yes
```
##### OS / ENVIRONMENT
- control host: OS X 10.11.5
- managed host: Debian 7, Debian 8
##### SUMMARY

git module changes repo URL and returns "changed": false when run with --check
##### STEPS TO REPRODUCE

``` yaml
# git-clone.yml

- hosts: localhost
  gather_facts: no
  tasks:
  - local_action: git repo={{url}} dest=ansible version=v1.0
```

```
$ ansible-playbook git-clone.yml -e url=https://github.com/ansible/ansible.git -v

PLAY [localhost] ***************************************************************

TASK [git] *********************************************************************
changed: [localhost -> localhost] => {"after": "6a64e9f0248d402aa60faf33bc720acbcd56e50b", "before": null, "changed": true}

PLAY RECAP *********************************************************************
localhost                  : ok=1    changed=1    unreachable=0    failed=0   

$ git -C ansible remote -v
origin  https://github.com/ansible/ansible.git (fetch)
origin  https://github.com/ansible/ansible.git (push)

$ ansible-playbook git-clone.yml -e url=https://github.com/famousgarkin/ansible.git -v --check

PLAY [localhost] ***************************************************************

TASK [git] *********************************************************************
ok: [localhost -> localhost] => {"after": "6a64e9f0248d402aa60faf33bc720acbcd56e50b", "before": "6a64e9f0248d402aa60faf33bc720acbcd56e50b", "changed": false}

PLAY RECAP *********************************************************************
localhost                  : ok=1    changed=0    unreachable=0    failed=0   

$ git -C ansible remote -v
origin  https://github.com/famousgarkin/ansible.git (fetch)
origin  https://github.com/famousgarkin/ansible.git (push)
```
##### EXPECTED RESULTS
- returns `"changed": true`
- repo URL is not changed
##### ACTUAL RESULTS
- returns `"changed": false`
- repo URL is changed



Discussion:
One needs to put some check for check_mode around https://github.com/ansible/ansible-modules-core/blob/devel/source_control/git.py#L817

@famousgarkin maybe this is something you can try to submit a PR for yourself? Some quick fix should be doable in a couple of lines.

Also it would be nice to have a test-case for this, potentially by using https://github.com/ansible/ansible/pull/16056


Resolving patch:
diff --git a/source_control/git.py b/source_control/git.py
--- a/source_control/git.py
+++ b/source_control/git.py
@@ -206,6 +206,7 @@
 
 import re
 import tempfile
+from ansible.utils.path import unfrackpath
 from distutils.version import LooseVersion
 
 def get_submodule_update_params(module, git_path, cwd):
@@ -521,14 +522,32 @@ def get_head_branch(git_path, module, dest, remote, bare=False):
     f.close()
     return branch
 
+def get_remote_url(git_path, module, dest, remote):
+    '''Return URL of remote source for repo.'''
+    command = [git_path, 'ls-remote', '--get-url', remote]
+    (rc, out, err) = module.run_command(command, cwd=dest)
+    if rc != 0:
+        # There was an issue getting remote URL, most likely
+        # command is not available in this version of Git.
+        return None
+    return out.rstrip('\n')
+
 def set_remote_url(git_path, module, repo, dest, remote):
     ''' updates repo from remote sources '''
-    commands = [("set a new url %s for %s" % (repo, remote), [git_path, 'remote', 'set-url', remote, repo])]
+    # Return if remote URL isn't changing.
+    remote_url = get_remote_url(git_path, module, dest, remote)
+    if remote_url == repo or remote_url == unfrackpath(repo):
+        return False
 
-    for (label,command) in commands:
-        (rc,out,err) = module.run_command(command, cwd=dest)
-        if rc != 0:
-            module.fail_json(msg="Failed to %s: %s %s" % (label, out, err))
+    command = [git_path, 'remote', 'set-url', remote, repo]
+    (rc, out, err) = module.run_command(command, cwd=dest)
+    if rc != 0:
+        label = "set a new url %s for %s" % (repo, remote)
+        module.fail_json(msg="Failed to %s: %s %s" % (label, out, err))
+
+    # Return False if remote_url is None to maintain previous bevhavior
+    # for Git versions prior to 1.7.5 that lack required functionality.
+    return remote_url is not None
 
 def fetch(git_path, module, repo, dest, version, remote, depth, bare, refspec):
     ''' updates repo from remote sources '''
@@ -859,7 +878,14 @@ def main():
                 reset(git_path, module, dest)
 
         # exit if already at desired sha version
-        set_remote_url(git_path, module, repo, dest, remote)
+        if module.check_mode:
+            remote_url = get_remote_url(git_path, module, dest, remote)
+            remote_url_changed = remote_url and remote_url != repo and remote_url != unfrackpath(repo)
+        else:
+            remote_url_changed = set_remote_url(git_path, module, repo, dest, remote)
+        if remote_url_changed:
+            result.update(remote_url_changed=True)
+
         remote_head = get_remote_head(git_path, module, dest, version, remote, bare)
         if result['before'] == remote_head:
             if local_mods:
@@ -908,9 +934,7 @@ def main():
         if module.check_mode:
             if submodules_updated:
                 result.update(changed=True, after=remote_head)
-            else:
-                result.update(changed=False, after=remote_head)
-            module.exit_json(**result)
+                module.exit_json(**result)
 
         if submodules_updated:
             # Switch to version specified
@@ -920,7 +944,7 @@ def main():
     result['after'] = get_version(module, git_path, dest)
 
     result.update(changed=False)
-    if result['before'] != result['after'] or local_mods or submodules_updated:
+    if result['before'] != result['after'] or local_mods or submodules_updated or remote_url_changed:
         result.update(changed=True)
         if module._diff:
             diff = get_diff(module, git_path, dest, repo, remote, depth, bare, result['before'], result['after'])


Test patch: