From 82c60db49b7b2f64c68308bcdb9d61231c21df24 Mon Sep 17 00:00:00 2001
From: Rick Elrod <rick@elrod.me>
Date: Mon, 6 Apr 2020 11:18:48 -0500
Subject: [PATCH] pip - Fix check_mode for prerelease packages (#68690)

* pip - Fix check_mode for prerelease packages

Fixes #68592.

Signed-off-by: Rick Elrod <rick@elrod.me>
Co-authored-by: Matt Martz <matt@sivel.net>
---
 .../68592-pip-check_mode-prereleases.yml      |  2 ++
 lib/ansible/modules/packaging/language/pip.py |  2 +-
 test/integration/targets/pip/tasks/pip.yml    | 35 +++++++++++++++++++
 test/integration/targets/pip/vars/main.yml    |  2 +-
 4 files changed, 39 insertions(+), 2 deletions(-)
 create mode 100644 changelogs/fragments/68592-pip-check_mode-prereleases.yml

diff --git a/changelogs/fragments/68592-pip-check_mode-prereleases.yml b/changelogs/fragments/68592-pip-check_mode-prereleases.yml
new file mode 100644
index 00000000000..754ed7b2fa6
--- /dev/null
+++ b/changelogs/fragments/68592-pip-check_mode-prereleases.yml
@@ -0,0 +1,2 @@
+bugfixes:
+  - "pip - check_mode with ``state: present`` now returns the correct state for pre-release versioned packages"
diff --git a/lib/ansible/modules/packaging/language/pip.py b/lib/ansible/modules/packaging/language/pip.py
index 598722a58b0..19744623d0c 100644
--- a/lib/ansible/modules/packaging/language/pip.py
+++ b/lib/ansible/modules/packaging/language/pip.py
@@ -555,7 +555,7 @@ class Package:
         if not self._plain_package:
             return False
         try:
-            return self._requirement.specifier.contains(version_to_test)
+            return self._requirement.specifier.contains(version_to_test, prereleases=True)
         except AttributeError:
             # old setuptools has no specifier, do fallback
             version_to_test = LooseVersion(version_to_test)
diff --git a/test/integration/targets/pip/tasks/pip.yml b/test/integration/targets/pip/tasks/pip.yml
index 19bd5d81387..c119f5726e2 100644
--- a/test/integration/targets/pip/tasks/pip.yml
+++ b/test/integration/targets/pip/tasks/pip.yml
@@ -516,3 +516,38 @@
     assert:
       that: "'distribute' in remove_distribute.cmd"
   when: ansible_python.version.major == 2
+
+# https://github.com/ansible/ansible/issues/68592
+# Handle pre-release version numbers in check_mode for already-installed
+# packages.
+# TODO: Limiting to py3 test boxes for now so the example of 'black' installs,
+# we should probably find another package to use with a similar versioning
+# scheme or make a small one and enable this test for py2 as well.
+- block:
+  - name: Install a beta version of a package
+    pip:
+      name: black
+      version: 19.10b0
+      state: present
+
+  - name: Use check_mode and ensure that the package is shown as installed
+    check_mode: true
+    pip:
+      name: black
+      state: present
+    register: pip_prereleases
+
+  - name: Uninstall the beta package if we need to
+    pip:
+      name: black
+      version: 19.10b0
+      state: absent
+    when: pip_prereleases is changed
+
+  - assert:
+      that:
+        - pip_prereleases is successful
+        - pip_prereleases is not changed
+        - '"black==19.10b0" in pip_prereleases.stdout_lines'
+
+  when: ansible_python.version.major == 3
diff --git a/test/integration/targets/pip/vars/main.yml b/test/integration/targets/pip/vars/main.yml
index 74723fefe11..87091ea5b97 100644
--- a/test/integration/targets/pip/vars/main.yml
+++ b/test/integration/targets/pip/vars/main.yml
@@ -3,7 +3,7 @@ pip_test_packages:
   - sampleproject
   - jiphy
 pip_test_pkg_ver:
-  - sampleproject<=100, !=9.0.0,>=0.0.1 
+  - sampleproject<=100, !=9.0.0,>=0.0.1
   - jiphy<100 ,!=9,>=0.0.1
 pip_test_pkg_ver_unsatisfied:
   - sampleproject>= 999.0.0