Repository: nautobot/nautobot
Issue category: Feature Request

Issue:
Improve returned data when syncing a Git repository via the REST API
### As ...

Austin - Network Automation Engineer

### I want ...

to be able to see more useful return data when syncing a Git repository via the REST API. Today, e.g.:

```
curl -s -X POST \
-H "Authorization: Token $TOKEN" \
-H "Content-Type: application/json" \
-H "Accept: application/json; version=2.4" \
http://nautobot/api/extras/git-repositories/2ecb8556-db58-466d-8278-860b8fd74627/sync/
```

returns

```
{
  "message": "Repository demo-git-datasource sync job added to queue."
}
```

I would want to see more data in that return data, including, for example:
- job-result ID
- selected job queue
- worker ID

### So that ...

I can make better programmatic decisions based on the return data.

### I know this is done when...

A more detailed JSON structure is returned, perhaps e.g.:
```
{
  "message": "Repository demo-git-datasource sync job added to queue.",
  "job-id": "XXXXXX",
  "job-queue": "XXXXXX"
  etc.
}
```

### Optional - Feature groups this request pertains to.

- [ ] Automation
- [ ] Circuits
- [ ] DCIM
- [ ] IPAM
- [x] Misc (including Data Sources)
- [ ] Organization
- [x] Apps (and other Extensibility)
- [ ] Security (Secrets, etc)
- [ ] Image Management
- [ ] UI/UX
- [ ] Documentation
- [ ] Other (not directly a platform feature)

### Database Changes

Already exists.

### External Dependencies

No
Improve returned data when syncing a Git repository via the REST API
### As ...

Austin - Network Automation Engineer

### I want ...

to be able to see more useful return data when syncing a Git repository via the REST API. Today, e.g.:

```
curl -s -X POST \
-H "Authorization: Token $TOKEN" \
-H "Content-Type: application/json" \
-H "Accept: application/json; version=2.4" \
http://nautobot/api/extras/git-repositories/2ecb8556-db58-466d-8278-860b8fd74627/sync/
```

returns

```
{
  "message": "Repository demo-git-datasource sync job added to queue."
}
```

I would want to see more data in that return data, including, for example:
- job-result ID
- selected job queue
- worker ID

### So that ...

I can make better programmatic decisions based on the return data.

### I know this is done when...

A more detailed JSON structure is returned, perhaps e.g.:
```
{
  "message": "Repository demo-git-datasource sync job added to queue.",
  "job-id": "XXXXXX",
  "job-queue": "XXXXXX"
  etc.
}
```

### Optional - Feature groups this request pertains to.

- [ ] Automation
- [ ] Circuits
- [ ] DCIM
- [ ] IPAM
- [x] Misc (including Data Sources)
- [ ] Organization
- [x] Apps (and other Extensibility)
- [ ] Security (Secrets, etc)
- [ ] Image Management
- [ ] UI/UX
- [ ] Documentation
- [ ] Other (not directly a platform feature)

### Database Changes

Already exists.

### External Dependencies

No


Hints:

Patch:
diff --git a/changes/6808.changed b/changes/6808.changed
new file mode 100644
index 0000000000..a363f1c45c
--- /dev/null
+++ b/changes/6808.changed
@@ -0,0 +1,1 @@
+Improved returned data when syncing a Git repository via the REST API.
diff --git a/nautobot/docs/user-guide/platform-functionality/gitrepository.md b/nautobot/docs/user-guide/platform-functionality/gitrepository.md
index 2435dbc5a0..3ce939605d 100644
--- a/nautobot/docs/user-guide/platform-functionality/gitrepository.md
+++ b/nautobot/docs/user-guide/platform-functionality/gitrepository.md
@@ -437,14 +437,50 @@ curl -s -X POST \
 -H "Authorization: Token $TOKEN" \
 -H "Content-Type: application/json" \
 -H "Accept: application/json; version=2.4" \
-http://nautobot/api/extras/git-repositories/2ecb8556-db58-466d-8278-860b8fd74627/sync/
+http://nautobot/api/extras/git-repositories/2ecb8556-db58-466d-8278-860b8fd74627/sync/ | jq '.'
 ```
 
 Which returns, for example:
 
 ```no-highlight
 {
-  "message": "Repository demo-git-datasource sync job added to queue."
+  "message": "Repository demo-git-datasource sync job added to queue.",
+  "job_result": {
+    "id": "68500ca5-27c3-488c-a24a-e98858bf52a1",
+    "object_type": "extras.jobresult",
+    "display": "Git Repository: Sync started at 2025-01-30 19:35:14.120625+00:00 (PENDING)",
+    "url": "http://nautobot/api/extras/job-results/68500ca5-27c3-488c-a24a-e98858bf52a1/",
+    "natural_slug": "68500ca5-27c3-488c-a24a-e98858bf52a1_6850",
+    "status": {
+      "value": "PENDING",
+      "label": "PENDING"
+    },
+    "name": "Git Repository: Sync",
+    "task_name": null,
+    "date_created": "2025-01-30T19:35:14.120625Z",
+    "date_done": null,
+    "result": null,
+    "worker": null,
+    "task_args": [],
+    "task_kwargs": {},
+    "celery_kwargs": {},
+    "traceback": null,
+    "meta": null,
+    "job_model": {
+      "id": "ad2b27c8-adf0-4e23-a4d3-a37fe3c42abd",
+      "object_type": "extras.job",
+      "url": "http://nautobot/api/extras/jobs/ad2b27c8-adf0-4e23-a4d3-a37fe3c42abd/"
+    },
+    "user": {
+      "id": "569138fe-f0b9-4abf-9812-c85a7ec73bbd",
+      "object_type": "users.user",
+      "url": "http://nautobot/api/users/users/569138fe-f0b9-4abf-9812-c85a7ec73bbd/"
+    },
+    "scheduled_job": null,
+    "custom_fields": {},
+    "computed_fields": {},
+    "files": []
+  }
 }
 ```
 
@@ -457,7 +493,7 @@ curl -s -X GET \
 -H "Authorization: Token $TOKEN" \
 -H "Content-Type: application/json" \
 -H "Accept: application/json; version=2.4" \
-http://nautobot/api/extras/jobs/?module_name__isw=demo_git_datasource. | jq .
+http://nautobot/api/extras/jobs/?module_name__isw=demo_git_datasource. | jq '.'
 ```
 
 Here are the first 20 lines of JSON returned:
@@ -527,7 +563,7 @@ curl -s -X GET \
 -H "Authorization: Token $TOKEN" \
 -H "Content-Type: application/json" \
 -H "Accept: application/json; version=2.4" \
-http://nautobot/api/extras/config-contexts/?owner_object_id=2ecb8556-db58-466d-8278-860b8fd74627 | jq .
+http://nautobot/api/extras/config-contexts/?owner_object_id=2ecb8556-db58-466d-8278-860b8fd74627 | jq '.'
 ```
 
 Here's the first part of the output:
diff --git a/nautobot/extras/api/serializers.py b/nautobot/extras/api/serializers.py
index a284604292..96ef7ebd71 100644
--- a/nautobot/extras/api/serializers.py
+++ b/nautobot/extras/api/serializers.py
@@ -1169,3 +1169,15 @@ def validate(self, attrs):
             raise serializers.ValidationError(conflicts)
 
         return validated_attrs
+
+
+#
+# More Git repositories
+#
+
+
+class GitRepositorySyncResponseSerializer(serializers.Serializer):
+    """Serializer representing responses from the GitRepository.sync() POST endpoint."""
+
+    message = serializers.CharField(read_only=True)
+    job_result = JobResultSerializer(read_only=True)
diff --git a/nautobot/extras/api/views.py b/nautobot/extras/api/views.py
index 37e7330429..ec2544e66a 100644
--- a/nautobot/extras/api/views.py
+++ b/nautobot/extras/api/views.py
@@ -425,7 +425,7 @@ class GitRepositoryViewSet(NautobotModelViewSet):
     serializer_class = serializers.GitRepositorySerializer
     filterset_class = filters.GitRepositoryFilterSet
 
-    @extend_schema(methods=["post"], request=serializers.GitRepositorySerializer)
+    @extend_schema(methods=["post"], responses={"200": serializers.GitRepositorySyncResponseSerializer}, request=None)
     # Since we are explicitly checking for `extras:change_gitrepository` in the API sync() method
     # We explicitly set the permission_classes to IsAuthenticated in the @action decorator
     # bypassing the default DRF permission check for `extras:add_gitrepository` and the permission check fall through to the function itself.
@@ -441,8 +441,16 @@ def sync(self, request, pk):
             raise CeleryWorkerNotRunningException()
 
         repository = get_object_or_404(GitRepository, id=pk)
-        repository.sync(user=request.user)
-        return Response({"message": f"Repository {repository} sync job added to queue."})
+        job_result = repository.sync(user=request.user)
+
+        data = {
+            # Kept message for backward compatibility for now
+            "message": f"Repository {repository} sync job added to queue.",
+            "job_result": job_result,
+        }
+
+        serializer = serializers.GitRepositorySyncResponseSerializer(data, context={"request": request})
+        return Response(serializer.data, status=status.HTTP_200_OK)
 
 
 #


Test patch:
diff --git a/nautobot/extras/tests/test_api.py b/nautobot/extras/tests/test_api.py
index af6efc332e..bb4f8ba759 100644
--- a/nautobot/extras/tests/test_api.py
+++ b/nautobot/extras/tests/test_api.py
@@ -1207,6 +1207,10 @@ def test_run_git_sync_with_permissions(self, _):
         url = reverse("extras-api:gitrepository-sync", kwargs={"pk": self.repos[0].id})
         response = self.client.post(url, format="json", **self.header)
         self.assertHttpStatus(response, status.HTTP_200_OK)
+        self.assertIn("message", response.data)
+        self.assertIn("job_result", response.data)
+        self.assertEqual(response.data["message"], f"Repository {self.repos[0].name} sync job added to queue.")
+        self.assertIsInstance(response.data["job_result"], dict)
 
     def test_create_with_app_provided_contents(self):
         """Test that `provided_contents` published by an App works."""