Repository: nautobot/nautobot

Issue:
Provide additional filter params for extras.GitRepository object
### As ...

Austin - Network Automation Engineer

### I want ...

The ability to filter the GitRepository UI and API views by additional fields

### So that ...

I can limit the choices returned in a view

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

- I can filter by repository provider_contents

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

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

### Database Changes

None

### External Dependencies

None


Discussion:

Resolving patch:
diff --git a/nautobot/extras/filters.py b/nautobot/extras/filters.py
--- a/nautobot/extras/filters.py
+++ b/nautobot/extras/filters.py
@@ -496,7 +496,7 @@ class GitRepositoryFilterSet(NautobotFilterSet):
 
     class Meta:
         model = GitRepository
-        fields = ["id", "name", "slug", "remote_url", "branch"]
+        fields = ["id", "name", "slug", "remote_url", "branch", "provided_contents"]
 
 
 #
diff --git a/nautobot/extras/forms.py b/nautobot/extras/forms.py
--- a/nautobot/extras/forms.py
+++ b/nautobot/extras/forms.py
@@ -856,6 +856,18 @@ class Meta:
         nullable_fields = ["secrets_group"]
 
 
+class GitRepositoryFilterForm(BootstrapMixin, forms.Form):
+    model = GitRepository
+    q = forms.CharField(required=False, label="Search")
+    name = forms.CharField(required=False)
+    branch = forms.CharField(required=False)
+    provided_contents = forms.ChoiceField(
+        required=False,
+        label="Provides",
+        choices=add_blank_choice(get_git_datasource_content_choices()),
+    )
+
+
 #
 # GraphQL saved queries
 #
diff --git a/nautobot/extras/views.py b/nautobot/extras/views.py
--- a/nautobot/extras/views.py
+++ b/nautobot/extras/views.py
@@ -681,8 +681,8 @@ class ExportTemplateBulkDeleteView(generic.BulkDeleteView):
 
 class GitRepositoryListView(generic.ObjectListView):
     queryset = GitRepository.objects.all()
-    # filterset = filters.GitRepositoryFilterSet
-    # filterset_form = forms.GitRepositoryFilterForm
+    filterset = filters.GitRepositoryFilterSet
+    filterset_form = forms.GitRepositoryFilterForm
     table = tables.GitRepositoryTable
     template_name = "extras/gitrepository_list.html"
 


Test patch:
diff --git a/nautobot/extras/tests/test_filters.py b/nautobot/extras/tests/test_filters.py
--- a/nautobot/extras/tests/test_filters.py
+++ b/nautobot/extras/tests/test_filters.py
@@ -15,6 +15,7 @@
     ConfigContextFilterSet,
     CustomLinkFilterSet,
     ExportTemplateFilterSet,
+    GitRepositoryFilterSet,
     GraphQLQueryFilterSet,
     ImageAttachmentFilterSet,
     JobFilterSet,
@@ -316,6 +317,71 @@ def test_search(self):
         self.assertEqual(self.filterset(params, self.queryset).qs.count(), 3)
 
 
+class GitRepositoryTestCase(TestCase):
+    queryset = GitRepository.objects.all()
+    filterset = GitRepositoryFilterSet
+
+    @classmethod
+    def setUpTestData(cls):
+        # Create Three GitRepository records
+        repos = (
+            GitRepository(
+                name="Repo 1",
+                slug="repo-1",
+                branch="main",
+                provided_contents=[
+                    "extras.configcontext",
+                ],
+                remote_url="https://example.com/repo1.git",
+            ),
+            GitRepository(
+                name="Repo 2",
+                slug="repo-2",
+                branch="develop",
+                provided_contents=[
+                    "extras.configcontext",
+                    "extras.job",
+                ],
+                remote_url="https://example.com/repo2.git",
+            ),
+            GitRepository(
+                name="Repo 3",
+                slug="repo-3",
+                branch="next",
+                provided_contents=[
+                    "extras.configcontext",
+                    "extras.job",
+                    "extras.exporttemplate",
+                ],
+                remote_url="https://example.com/repo3.git",
+            ),
+        )
+        for repo in repos:
+            repo.save(trigger_resync=False)
+
+    def test_id(self):
+        params = {"id": self.queryset.values_list("pk", flat=True)[:2]}
+        self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
+
+    def test_name(self):
+        params = {"name": ["Repo 3", "Repo 2"]}
+        self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
+
+    def test_remote_url(self):
+        params = {"remote_url": ["https://example.com/repo1.git"]}
+        self.assertEqual(self.filterset(params, self.queryset).qs.count(), 1)
+
+    def test_branch(self):
+        params = {"branch": ["main", "next"]}
+        self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
+
+    def test_provided_contents(self):
+        params = {"provided_contents": ["extras.exporttemplate"]}
+        self.assertEqual(self.filterset(params, self.queryset).qs.count(), 1)
+        params = {"provided_contents": ["extras.job"]}
+        self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
+
+
 class GraphQLTestCase(TestCase):
     queryset = GraphQLQuery.objects.all()
     filterset = GraphQLQueryFilterSet