nebius/SWE-rebench-V2-PRs huggingface dataset:
Repository: ansible/tower-cli
Pull request #308 (2017-06-20 21:51:40)

Implement provisioning callback
Connect #249.

coveralls: 
[![Coverage Status](https://:/builds/12057760/badge)](https://:/builds/12057760)

Coverage decreased (-0.2%) to 90.581% when pulling **e9cab5a3bbb40a80c27118f3758a3c0a8c3200d4 on jangsutsr:issue249_implement_provisioning_callback** into **fb6540b605fab703307c11f4544ba6c3e4ad5e1c on ansible:master**.


Patch:
diff --git a/tower_cli/resources/job_template.py b/tower_cli/resources/job_template.py
index 34e6b03..60746c3 100644
--- a/tower_cli/resources/job_template.py
+++ b/tower_cli/resources/job_template.py
@@ -18,7 +18,8 @@ from __future__ import absolute_import, unicode_literals
 import click
 
 from tower_cli import models, resources
-from tower_cli.utils import types
+from tower_cli.utils import types, parser
+from tower_cli.api import client
 
 
 class Resource(models.SurveyResource):
@@ -145,3 +146,18 @@ class Resource(models.SurveyResource):
         """Disassociate a notification template from this job template."""
         return self._disassoc('notification_templates_%s' % status,
                               job_template, notification_template)
+
+    @resources.command(use_fields_as_options=('extra_vars'))
+    @click.option('--host-config-key', help='Job-template-specific string used to authenticate '
+                  'host during provisioning callback.')
+    def callback(self, pk=None, host_config_key='', extra_vars=None):
+        """Contact Tower and request a configuration update using this job template."""
+        url = self.endpoint + '%s/callback/' % pk
+        if not host_config_key:
+            host_config_key = client.get(url).json()['host_config_key']
+        post_data = {'host_config_key': host_config_key}
+        if extra_vars:
+            post_data['extra_vars'] = parser.process_extra_vars(list(extra_vars), force_json=True)
+        r = client.post(url, data=post_data, auth=None)
+        if r.status_code == 201:
+            return {'changed': True}


Test patch:
diff --git a/tests/test_resources_job_template.py b/tests/test_resources_job_template.py
index 79cc44f..575cbee 100644
--- a/tests/test_resources_job_template.py
+++ b/tests/test_resources_job_template.py
@@ -182,3 +182,12 @@ class TemplateTests(unittest.TestCase):
             self.res.disassociate_notification_template(5, 3, 'any')
             self.assertEqual(t.requests[1].body,
                              json.dumps({'disassociate': True, 'id': 3}))
+
+    def test_callback(self):
+        """Establish that a job template should be able to conduct provisioning callback
+        """
+        with client.test_mode as t:
+            t.register_json('/job_templates/5/callback/', {'host_config_key': 'foobar'})
+            t.register_json('/job_templates/5/callback/', {}, method='POST')
+            self.res.callback(5)
+            self.assertEqual(t.requests[1].body, json.dumps({"host_config_key": "foobar"}))
Repository: ansible/tower-cli
Pull request #398 (2017-10-11 13:34:00)

fix copy error with extra_vars
Connect #392

This doesn't use the solution I mentioned in that issue. I think we should eventually do that as well, but this is just a band-aid to fix the particular problem that is being experienced.


Patch:
diff --git a/tower_cli/models/base.py b/tower_cli/models/base.py
index b6a43b4..bfd0ced 100644
--- a/tower_cli/models/base.py
+++ b/tower_cli/models/base.py
@@ -622,8 +622,15 @@ class Resource(BaseResource):
         newresource = copy(orig)
         newresource.pop('id')
         basename = newresource['name'].split('@', 1)[0].strip()
-        newresource['name'] = "%s @ %s" % (basename, time.strftime('%X'))
+
+        # Modify data to fit the call pattern of the tower-cli method
+        for field in self.fields:
+            if field.multiple and field.name in newresource:
+                newresource[field.name] = (newresource.get(field.name),)
+
         newresource.update(kwargs)
+        newresource['name'] = "%s @ %s" % (basename, time.strftime('%X'))
+
         return self.write(create_on_missing=True, **newresource)
 
     @resources.command(ignore_defaults=True)


Test patch:
diff --git a/tests/test_models_base.py b/tests/test_models_base.py
index c105bf0..e9dcbf7 100644
--- a/tests/test_models_base.py
+++ b/tests/test_models_base.py
@@ -604,6 +604,33 @@ class ResourceTests(unittest.TestCase):
             with self.assertRaises(exc.Found):
                 self.res._lookup(name='bar', fail_on_found=True)
 
+    def test_copy_with_multiples(self):
+        """
+        A resource with fields marked `multiple` has those fields copied fully
+        """
+        class BarResource(models.Resource):
+            endpoint = '/bar/'
+            name = models.Field(unique=True)
+            variables = models.Field(multiple=True)
+        res = BarResource()
+        with mock.patch.object(res, 'read') as read_mock:
+            read_mock.return_value = {
+                "count": 1,
+                "results": [
+                    {
+                        "id": 42,
+                        "name": "foobarin",
+                        "variables": "foobar: barfood"
+                    }
+                ]
+            }
+            with mock.patch.object(res, 'write') as write_mock:
+                res.copy()
+                name, args, kwargs = write_mock.mock_calls[0]
+                self.assertEqual(kwargs['name'][:len("foobarin")], "foobarin")
+                self.assertEqual(kwargs['variables'], ('foobar: barfood',))
+                self.assertNotIn('id', kwargs)
+
 
 class MonitorableResourcesTests(unittest.TestCase):
     """Estblaish that the MonitorableResource abstract class works in the
Repository: ansible/tower-cli
Pull request #399 (2017-10-11 13:46:53)

fix copy error with extra_vars
Connect #392


Patch:
diff --git a/tower_cli/models/base.py b/tower_cli/models/base.py
index 7810849..1875c99 100644
--- a/tower_cli/models/base.py
+++ b/tower_cli/models/base.py
@@ -937,8 +937,15 @@ class Resource(BaseResource):
         newresource = copy(orig)
         newresource.pop('id')
         basename = newresource['name'].split('@', 1)[0].strip()
-        newresource['name'] = "%s @ %s" % (basename, time.strftime('%X'))
+
+        # Modify data to fit the call pattern of the tower-cli method
+        for field in self.fields:
+            if field.multiple and field.name in newresource:
+                newresource[field.name] = (newresource.get(field.name),)
+
         newresource.update(kwargs)
+        newresource['name'] = "%s @ %s" % (basename, time.strftime('%X'))
+
         return self.write(create_on_missing=True, **newresource)
 
     @resources.command(ignore_defaults=True)


Test patch:
diff --git a/tests/test_models_base.py b/tests/test_models_base.py
index fef068a..8a176af 100644
--- a/tests/test_models_base.py
+++ b/tests/test_models_base.py
@@ -582,6 +582,33 @@ class ResourceTests(unittest.TestCase):
             with self.assertRaises(exc.Found):
                 self.res._lookup(name='bar', fail_on_found=True)
 
+    def test_copy_with_multiples(self):
+        """
+        A resource with fields marked `multiple` has those fields copied fully
+        """
+        class BarResource(models.Resource):
+            endpoint = '/bar/'
+            name = models.Field(unique=True)
+            variables = models.Field(multiple=True)
+        res = BarResource()
+        with mock.patch.object(res, 'read') as read_mock:
+            read_mock.return_value = {
+                "count": 1,
+                "results": [
+                    {
+                        "id": 42,
+                        "name": "foobarin",
+                        "variables": "foobar: barfood"
+                    }
+                ]
+            }
+            with mock.patch.object(res, 'write') as write_mock:
+                res.copy()
+                name, args, kwargs = write_mock.mock_calls[0]
+                self.assertEqual(kwargs['name'][:len("foobarin")], "foobarin")
+                self.assertEqual(kwargs['variables'], ('foobar: barfood',))
+                self.assertNotIn('id', kwargs)
+
 
 class MonitorableResourcesTests(unittest.TestCase):
     """Estblaish that the MonitorableResource abstract class works in the
Repository: ansible/tower-cli
Pull request #651 (2019-01-16 17:16:07)

Fixed page numbering when using all-pages and format human
This addresses: https://github.com/ansible/tower-cli/issues/650 

Older versions of the CLI did not print page information when there was only 1 page, that seems sensible to me so that's what I went with.   Test case was also updated to assert what I believe is the correct response.


Patch:
diff --git a/tower_cli/cli/resource.py b/tower_cli/cli/resource.py
index bc6f9bf..32df5a0 100644
--- a/tower_cli/cli/resource.py
+++ b/tower_cli/cli/resource.py
@@ -263,7 +263,8 @@ class ResSubcommand(click.MultiCommand):
             '\n'.join(data_rows),
             divider_row,
         ))
-        if page:
+        # Don't print page numbers for 1 page results
+        if page and total_pages != 1:
             response += '(Page %d of %d.)' % (page, total_pages)
         if payload.get('changed', False):
             response = 'Resource changed.\n' + response
diff --git a/tower_cli/models/base.py b/tower_cli/models/base.py
index 16fe84d..69ed215 100644
--- a/tower_cli/models/base.py
+++ b/tower_cli/models/base.py
@@ -558,6 +558,7 @@ class BaseResource(six.with_metaclass(ResourceMeta)):
                 cursor = self.list(**dict(kwargs, page=cursor['next']))
                 response['results'] += cursor['results']
                 response['count'] += cursor['count']
+            response['next'] = None
 
         # Done; return the response
         return response


Test patch:
diff --git a/tests/test_resources_job.py b/tests/test_resources_job.py
index f73a960..3f9b2b0 100644
--- a/tests/test_resources_job.py
+++ b/tests/test_resources_job.py
@@ -577,7 +577,7 @@ class ListStatusesTests(unittest.TestCase):
             self.assertEqual(result, {
                 'count': 5,
                 'previous': None,
-                'next': 2,
+                'next': None,
                 'results': [{
                     'elapsed': 0.0,
                     'failed': False,
Repository: ansible/tower-cli
Pull request #708 (2019-06-11 01:02:30)

grant role to user: handle admin roles with space
Fix `Unable to add user` when granted role contains a space:

    $ awx-cli send <<EOF
    [
      {
        "asset_type": "organization",
        "name": "MyOrg",
        "asset_relation": {
          "roles": [
            {
              "name": "Inventory Admin",
              "user": ["misc"],
              "team": []
            }
          ]
        }
      }
    ]
    EOF

    ORGANIZATION [MyOrg] ***
    Asset up to date
    Unable to add user misc to Inventory Admin role: The requested object could not be found.


Patch:
diff --git a/tower_cli/resources/role.py b/tower_cli/resources/role.py
index 216c15f..213e794 100644
--- a/tower_cli/resources/role.py
+++ b/tower_cli/resources/role.py
@@ -172,7 +172,7 @@ class Resource(models.Resource):
         else:
             endpoint = '/roles/'
         if in_data.get('type', False):
-            data['role_field'] = '%s_role' % in_data['type'].lower()
+            data['role_field'] = '%s_role' % in_data['type'].replace(' ', '_').lower()
         # Add back fields unrelated to role lookup, such as all_pages
         for key, value in in_data.items():
             if key not in RESOURCE_FIELDS and key not in ['type', 'user', 'team']:


Test patch:
diff --git a/tests/test_resources_role.py b/tests/test_resources_role.py
index 9b06829..192a686 100644
--- a/tests/test_resources_role.py
+++ b/tests/test_resources_role.py
@@ -91,6 +91,15 @@ class RoleUnitTests(unittest.TestCase):
         self.assertIn('members__in', data)
         self.assertEqual(endpoint, '/roles/')
 
+    def test_data_endpoint_inventory_admin(self):
+        """Translation of input args to lookup args, space in type"""
+        kwargs = {'user': 2, 'type': 'Inventory Admin', 'inventory': 5}
+        data, endpoint = Role.data_endpoint(kwargs, ignore=['res'])
+        self.assertIn('members__in', data)
+        self.assertEqual(endpoint, '/roles/')
+        self.assertIn('role_field', data)
+        self.assertEqual(data['role_field'], 'inventory_admin_role')
+
 
 class RoleMethodTests(unittest.TestCase):
     """Test role commands."""