From 4720e1cbb764c3807dc881dc06a145e4ba19d2c5 Mon Sep 17 00:00:00 2001
From: Aaron Huntsman <ahuntsman@gitlab.com>
Date: Tue, 9 Apr 2024 19:25:50 +0000
Subject: [PATCH] Add referrer_type filtering to containerRepository tags
 GraphQL query

Changelog: added
---
 .../container_repository_tags_resolver.rb         |  8 +++++++-
 app/models/container_repository.rb                |  5 +++--
 doc/api/graphql/reference/index.md                |  1 +
 lib/container_registry/gitlab_api_client.rb       |  3 ++-
 .../container_repository_tags_resolver_spec.rb    | 15 ++++++++-------
 .../container_registry/gitlab_api_client_spec.rb  | 11 +++++++----
 spec/models/container_repository_spec.rb          |  8 ++++++--
 .../api/project_container_repositories_spec.rb    |  3 ++-
 8 files changed, 36 insertions(+), 18 deletions(-)

diff --git a/app/graphql/resolvers/container_repository_tags_resolver.rb b/app/graphql/resolvers/container_repository_tags_resolver.rb
index d3929451bd02..1b37ed526979 100644
--- a/app/graphql/resolvers/container_repository_tags_resolver.rb
+++ b/app/graphql/resolvers/container_repository_tags_resolver.rb
@@ -19,6 +19,11 @@ class ContainerRepositoryTagsResolver < BaseResolver
         required: false,
         default_value: nil
 
+    argument :referrer_type, GraphQL::Types::String,
+        description: 'Comma-separated list of artifact types used to filter referrers. Applies only when `referrers` is set to `true`.',
+        required: false,
+        default_value: nil
+
     alias_method :container_repository, :object
 
     def resolve(sort:, **filters)
@@ -31,7 +36,8 @@ def resolve(sort:, **filters)
           sort: map_sort_field(sort),
           name: filters[:name],
           page_size: page_size,
-          referrers: filters[:referrers]
+          referrers: filters[:referrers],
+          referrer_type: filters[:referrer_type]
         )
 
         Gitlab::Graphql::ExternallyPaginatedArray.new(
diff --git a/app/models/container_repository.rb b/app/models/container_repository.rb
index cc75b1a17371..6914ad056c52 100644
--- a/app/models/container_repository.rb
+++ b/app/models/container_repository.rb
@@ -498,7 +498,7 @@ def each_tags_page(page_size: 100, &block)
     raise 'too many pages requested' if page_count >= MAX_TAGS_PAGES
   end
 
-  def tags_page(before: nil, last: nil, sort: nil, name: nil, page_size: 100, referrers: nil)
+  def tags_page(before: nil, last: nil, sort: nil, name: nil, page_size: 100, referrers: nil, referrer_type: nil)
     raise ArgumentError, 'not a migrated repository' unless migrated?
 
     page = gitlab_api_client.tags(
@@ -508,7 +508,8 @@ def tags_page(before: nil, last: nil, sort: nil, name: nil, page_size: 100, refe
       last: last,
       sort: sort,
       name: name,
-      referrers: referrers
+      referrers: referrers,
+      referrer_type: referrer_type
     )
 
     {
diff --git a/doc/api/graphql/reference/index.md b/doc/api/graphql/reference/index.md
index bdcc18bff8a5..cf0852806807 100644
--- a/doc/api/graphql/reference/index.md
+++ b/doc/api/graphql/reference/index.md
@@ -17600,6 +17600,7 @@ four standard [pagination arguments](#pagination-arguments):
 | Name | Type | Description |
 | ---- | ---- | ----------- |
 | <a id="containerrepositorydetailstagsname"></a>`name` | [`String`](#string) | Search by tag name. |
+| <a id="containerrepositorydetailstagsreferrertype"></a>`referrerType` | [`String`](#string) | Comma-separated list of artifact types used to filter referrers. Applies only when `referrers` is set to `true`. |
 | <a id="containerrepositorydetailstagsreferrers"></a>`referrers` | [`Boolean`](#boolean) | Include tag referrers. |
 | <a id="containerrepositorydetailstagssort"></a>`sort` | [`ContainerRepositoryTagSort`](#containerrepositorytagsort) | Sort tags by these criteria. |
 
diff --git a/lib/container_registry/gitlab_api_client.rb b/lib/container_registry/gitlab_api_client.rb
index 2c2878e54280..e29581afc490 100644
--- a/lib/container_registry/gitlab_api_client.rb
+++ b/lib/container_registry/gitlab_api_client.rb
@@ -172,7 +172,7 @@ def repository_details(path, sizing: nil)
     end
 
     # https://gitlab.com/gitlab-org/container-registry/-/blob/master/docs/spec/gitlab/api.md#list-repository-tags
-    def tags(path, page_size: 100, last: nil, before: nil, name: nil, sort: nil, referrers: nil)
+    def tags(path, page_size: 100, last: nil, before: nil, name: nil, sort: nil, referrers: nil, referrer_type: nil)
       limited_page_size = [page_size, MAX_TAGS_PAGE_SIZE].min
       with_token_faraday do |faraday_client|
         url = "#{GITLAB_REPOSITORIES_PATH}/#{path}/tags/list/"
@@ -183,6 +183,7 @@ def tags(path, page_size: 100, last: nil, before: nil, name: nil, sort: nil, ref
           req.params['name'] = name if name.present?
           req.params['sort'] = sort if sort
           req.params['referrers'] = 'true' if referrers
+          req.params['referrer_type'] = referrer_type if referrer_type
         end
 
         unless response.success?
diff --git a/spec/graphql/resolvers/container_repository_tags_resolver_spec.rb b/spec/graphql/resolvers/container_repository_tags_resolver_spec.rb
index 4d0f1676c7f1..6490cf53aec6 100644
--- a/spec/graphql/resolvers/container_repository_tags_resolver_spec.rb
+++ b/spec/graphql/resolvers/container_repository_tags_resolver_spec.rb
@@ -83,16 +83,16 @@
       context 'with parameters' do
         using RSpec::Parameterized::TableSyntax
 
-        where(:before, :after, :sort, :name, :first, :last, :sort_value, :referrers) do
-          nil  | nil  | 'NAME_DESC' | ''  | 10  | nil | '-name' | nil
-          'bb' | nil  | 'NAME_ASC'  | 'a' | nil | 5   | 'name'  | false
-          nil  | 'aa' | 'NAME_DESC' | 'a' | 10  | nil | '-name' | true
+        where(:before, :after, :sort, :name, :first, :last, :sort_value, :referrers, :referrer_type) do
+          nil  | nil  | 'NAME_DESC' | ''  | 10  | nil | '-name' | nil   | nil
+          'bb' | nil  | 'NAME_ASC'  | 'a' | nil | 5   | 'name'  | false | nil
+          nil  | 'aa' | 'NAME_DESC' | 'a' | 10  | nil | '-name' | true  | 'application/example'
         end
 
         with_them do
           let(:args) do
-            { before: before, after: after, sort: sort, name: name,
-              first: first, last: last, referrers: referrers }.compact
+            { before: before, after: after, sort: sort, name: name, first: first,
+              last: last, referrers: referrers, referrer_type: referrer_type }.compact
           end
 
           it 'calls ContainerRepository#tags_page with correct parameters' do
@@ -102,7 +102,8 @@
               sort: sort_value,
               name: name,
               page_size: [first, last].map(&:to_i).max,
-              referrers: referrers
+              referrers: referrers,
+              referrer_type: referrer_type
             )
 
             resolver(args)
diff --git a/spec/lib/container_registry/gitlab_api_client_spec.rb b/spec/lib/container_registry/gitlab_api_client_spec.rb
index 44155698095e..a2792d8a2262 100644
--- a/spec/lib/container_registry/gitlab_api_client_spec.rb
+++ b/spec/lib/container_registry/gitlab_api_client_spec.rb
@@ -268,8 +268,6 @@
     end
 
     context 'with referrers included' do
-      subject { client.tags(path, page_size: page_size, referrers: true) }
-
       let(:expected) do
         {
           pagination: {},
@@ -277,8 +275,12 @@
         }
       end
 
+      let(:input) { { referrers: 'true', referrer_type: 'application/vnd.example%2Btype' } }
+
+      subject { client.tags(path, page_size: page_size, **input) }
+
       before do
-        stub_tags(path, page_size: page_size, input: { referrers: 'true' }, respond_with: response)
+        stub_tags(path, page_size: page_size, input: input, respond_with: response)
       end
 
       it { is_expected.to eq(expected) }
@@ -990,7 +992,8 @@ def stub_tags(path, page_size: nil, input: {}, previous_page_url: nil, next_page
       name: input[:name],
       sort: input[:sort],
       before: input[:before],
-      referrers: input[:referrers]
+      referrers: input[:referrers],
+      referrer_type: input[:referrer_type]
     }.compact
 
     url = "#{registry_api_url}/gitlab/v1/repositories/#{path}/tags/list/"
diff --git a/spec/models/container_repository_spec.rb b/spec/models/container_repository_spec.rb
index 8a6d4a00b590..32620efb576f 100644
--- a/spec/models/container_repository_spec.rb
+++ b/spec/models/container_repository_spec.rb
@@ -865,9 +865,12 @@ def expected_tags_from(client_tags)
     let_it_be(:last) { 'last' }
     let_it_be(:sort) { '-name' }
     let_it_be(:name) { 'repo' }
+    let_it_be(:referrers) { true }
+    let_it_be(:referrer_type) { 'application/example' }
 
     subject do
-      repository.tags_page(before: before, last: last, sort: sort, name: name, page_size: page_size)
+      repository.tags_page(before: before, last: last, sort: sort, name: name, page_size: page_size,
+        referrers: referrers, referrer_type: referrer_type)
     end
 
     before do
@@ -877,7 +880,8 @@ def expected_tags_from(client_tags)
     it 'calls GitlabApiClient#tags and passes parameters' do
       allow(repository.gitlab_api_client).to receive(:tags).and_return({})
       expect(repository.gitlab_api_client).to receive(:tags).with(
-        repository.path, page_size: page_size, before: before, last: last, sort: sort, name: name, referrers: nil)
+        repository.path, page_size: page_size, before: before, last: last, sort: sort, name: name,
+        referrers: referrers, referrer_type: referrer_type)
 
       subject
     end
diff --git a/spec/requests/api/project_container_repositories_spec.rb b/spec/requests/api/project_container_repositories_spec.rb
index 56e3f92f6d77..8ba05905596a 100644
--- a/spec/requests/api/project_container_repositories_spec.rb
+++ b/spec/requests/api/project_container_repositories_spec.rb
@@ -241,7 +241,8 @@
                       last: last_param,
                       name: nil,
                       before: nil,
-                      referrers: nil
+                      referrers: nil,
+                      referrer_type: nil
                     )
                   end
 
-- 
GitLab