From e997b1974fb0d77e192e5a0514a911966bbe101f Mon Sep 17 00:00:00 2001
From: Avielle Wolfe <awolfe@gitlab.com>
Date: Wed, 10 Jan 2024 16:23:54 +0000
Subject: [PATCH] Store full include path for CI components

The `path` field on `ci_components` currently holds the file path of the
component within the component project repository. However, we aren't
currently using that data. Instead, we need to provide the include path
for the component so we can display it on the catalog resource details
  page. This commit stores the include path instead of the file path.

Existing component records will still have the file path. We'll decide
later whether it is necessary to update them with a data migration.

Changelog: changed
---
 .../components/details/ci_resource_components.vue        | 4 ++--
 .../get_ci_catalog_resource_components.query.graphql     | 2 +-
 app/graphql/types/ci/catalog/resources/component_type.rb | 3 ++-
 .../ci/catalog/resources/versions/create_service.rb      | 6 ++++--
 doc/api/graphql/reference/index.md                       | 2 +-
 .../components/details/ci_resource_components_spec.js    | 4 ++--
 spec/frontend/ci/catalog/mock.js                         | 6 +++---
 .../types/ci/catalog/resources/component_type_spec.rb    | 2 +-
 spec/requests/api/graphql/ci/catalog/resource_spec.rb    | 6 +++---
 .../ci/catalog/resources/versions/create_service_spec.rb | 9 +++++----
 10 files changed, 24 insertions(+), 20 deletions(-)

diff --git a/app/assets/javascripts/ci/catalog/components/details/ci_resource_components.vue b/app/assets/javascripts/ci/catalog/components/details/ci_resource_components.vue
index 6d062d8b7f17c..7085397c6495f 100644
--- a/app/assets/javascripts/ci/catalog/components/details/ci_resource_components.vue
+++ b/app/assets/javascripts/ci/catalog/components/details/ci_resource_components.vue
@@ -106,7 +106,7 @@ export default {
         <div class="gl-display-flex">
           <pre
             class="gl-w-85p gl-py-4 gl-display-flex gl-justify-content-space-between gl-m-0 gl-border-r-none"
-          ><span>{{ generateSnippet(component.path) }}</span>
+          ><span>{{ generateSnippet(component.includePath) }}</span>
         </pre>
           <div class="gl--flex-center gl-bg-gray-10 gl-border gl-border-l-none">
             <gl-button
@@ -115,7 +115,7 @@ export default {
               icon="copy-to-clipboard"
               size="small"
               :title="$options.i18n.copyText"
-              :data-clipboard-text="generateSnippet(component.path)"
+              :data-clipboard-text="generateSnippet(component.includePath)"
               data-testid="copy-to-clipboard"
               :aria-label="$options.i18n.copyAriaText"
             />
diff --git a/app/assets/javascripts/ci/catalog/graphql/queries/get_ci_catalog_resource_components.query.graphql b/app/assets/javascripts/ci/catalog/graphql/queries/get_ci_catalog_resource_components.query.graphql
index 41ac72aa9de31..bf1edf1af6e9a 100644
--- a/app/assets/javascripts/ci/catalog/graphql/queries/get_ci_catalog_resource_components.query.graphql
+++ b/app/assets/javascripts/ci/catalog/graphql/queries/get_ci_catalog_resource_components.query.graphql
@@ -8,7 +8,7 @@ query getCiCatalogResourceComponents($fullPath: ID!) {
         nodes {
           id
           name
-          path
+          includePath
           inputs {
             name
             required
diff --git a/app/graphql/types/ci/catalog/resources/component_type.rb b/app/graphql/types/ci/catalog/resources/component_type.rb
index 3b4771446cb1b..71ed31725a665 100644
--- a/app/graphql/types/ci/catalog/resources/component_type.rb
+++ b/app/graphql/types/ci/catalog/resources/component_type.rb
@@ -16,7 +16,8 @@ class ComponentType < BaseObject
             description: 'Name of the component.',
             alpha: { milestone: '16.7' }
 
-          field :path, GraphQL::Types::String, null: true,
+          field :include_path, GraphQL::Types::String, null: true,
+            method: :path,
             description: 'Path used to include the component.',
             alpha: { milestone: '16.7' }
 
diff --git a/app/services/ci/catalog/resources/versions/create_service.rb b/app/services/ci/catalog/resources/versions/create_service.rb
index 863bad4327112..9547db7bcf169 100644
--- a/app/services/ci/catalog/resources/versions/create_service.rb
+++ b/app/services/ci/catalog/resources/versions/create_service.rb
@@ -65,10 +65,12 @@ def build_components(component_paths)
           end
 
           def extract_metadata(blob)
+            component_name = components_project.extract_component_name(blob.path)
+
             {
-              name: components_project.extract_component_name(blob.path),
+              name: component_name,
               inputs: components_project.extract_inputs(blob.data),
-              path: blob.path
+              path: "#{Settings.gitlab.host}/#{project.full_path}/#{component_name}@#{release.tag}"
             }
           end
 
diff --git a/doc/api/graphql/reference/index.md b/doc/api/graphql/reference/index.md
index f17d979456840..9e196de50b8d9 100644
--- a/doc/api/graphql/reference/index.md
+++ b/doc/api/graphql/reference/index.md
@@ -15560,9 +15560,9 @@ four standard [pagination arguments](#connection-pagination-arguments):
 | Name | Type | Description |
 | ---- | ---- | ----------- |
 | <a id="cicatalogresourcecomponentid"></a>`id` **{warning-solid}** | [`CiCatalogResourcesComponentID!`](#cicatalogresourcescomponentid) | **Introduced** in 16.7. This feature is an Experiment. It can be changed or removed at any time. ID of the component. |
+| <a id="cicatalogresourcecomponentincludepath"></a>`includePath` **{warning-solid}** | [`String`](#string) | **Introduced** in 16.7. This feature is an Experiment. It can be changed or removed at any time. Path used to include the component. |
 | <a id="cicatalogresourcecomponentinputs"></a>`inputs` **{warning-solid}** | [`[CiCatalogResourceComponentInput!]`](#cicatalogresourcecomponentinput) | **Introduced** in 16.7. This feature is an Experiment. It can be changed or removed at any time. Inputs for the component. |
 | <a id="cicatalogresourcecomponentname"></a>`name` **{warning-solid}** | [`String`](#string) | **Introduced** in 16.7. This feature is an Experiment. It can be changed or removed at any time. Name of the component. |
-| <a id="cicatalogresourcecomponentpath"></a>`path` **{warning-solid}** | [`String`](#string) | **Introduced** in 16.7. This feature is an Experiment. It can be changed or removed at any time. Path used to include the component. |
 
 ### `CiCatalogResourceComponentInput`
 
diff --git a/spec/frontend/ci/catalog/components/details/ci_resource_components_spec.js b/spec/frontend/ci/catalog/components/details/ci_resource_components_spec.js
index 330163e9f39b7..f81344fa29105 100644
--- a/spec/frontend/ci/catalog/components/details/ci_resource_components_spec.js
+++ b/spec/frontend/ci/catalog/components/details/ci_resource_components_spec.js
@@ -115,7 +115,7 @@ describe('CiResourceComponents', () => {
       it('renders the component name and snippet', () => {
         components.forEach((component) => {
           expect(wrapper.text()).toContain(component.name);
-          expect(wrapper.text()).toContain(component.path);
+          expect(wrapper.text()).toContain(component.includePath);
         });
       });
 
@@ -124,7 +124,7 @@ describe('CiResourceComponents', () => {
           const button = findCopyToClipboardButton(i);
 
           expect(button.props().icon).toBe('copy-to-clipboard');
-          expect(button.attributes('data-clipboard-text')).toContain(component.path);
+          expect(button.attributes('data-clipboard-text')).toContain(component.includePath);
         });
       });
 
diff --git a/spec/frontend/ci/catalog/mock.js b/spec/frontend/ci/catalog/mock.js
index 9ca35943ae522..6e6bd3ba14a99 100644
--- a/spec/frontend/ci/catalog/mock.js
+++ b/spec/frontend/ci/catalog/mock.js
@@ -387,14 +387,14 @@ const componentsMockData = {
       id: 'gid://gitlab/Ci::Component/1',
       name: 'Ruby gal',
       description: 'This is a pretty amazing component that does EVERYTHING ruby.',
-      path: 'gitlab.com/gitlab-org/ruby-gal@~latest',
+      includePath: 'gitlab.com/gitlab-org/ruby-gal@~latest',
       inputs: [{ name: 'version', default: '1.0.0', required: true }],
     },
     {
       id: 'gid://gitlab/Ci::Component/2',
       name: 'Javascript madness',
       description: 'Adds some spice to your life.',
-      path: 'gitlab.com/gitlab-org/javascript-madness@~latest',
+      includePath: 'gitlab.com/gitlab-org/javascript-madness@~latest',
       inputs: [
         { name: 'isFun', default: 'true', required: true },
         { name: 'RandomNumber', default: '10', required: false },
@@ -404,7 +404,7 @@ const componentsMockData = {
       id: 'gid://gitlab/Ci::Component/3',
       name: 'Go go go',
       description: 'When you write Go, you gotta go go go.',
-      path: 'gitlab.com/gitlab-org/go-go-go@~latest',
+      includePath: 'gitlab.com/gitlab-org/go-go-go@~latest',
       inputs: [{ name: 'version', default: '1.0.0', required: true }],
     },
   ],
diff --git a/spec/graphql/types/ci/catalog/resources/component_type_spec.rb b/spec/graphql/types/ci/catalog/resources/component_type_spec.rb
index 93ab926d4068e..821d41ea7b4fa 100644
--- a/spec/graphql/types/ci/catalog/resources/component_type_spec.rb
+++ b/spec/graphql/types/ci/catalog/resources/component_type_spec.rb
@@ -10,7 +10,7 @@
       id
       inputs
       name
-      path
+      include_path
     ]
 
     expect(described_class).to have_graphql_fields(*expected_fields)
diff --git a/spec/requests/api/graphql/ci/catalog/resource_spec.rb b/spec/requests/api/graphql/ci/catalog/resource_spec.rb
index e97f09aa1d4fe..836e52197a31b 100644
--- a/spec/requests/api/graphql/ci/catalog/resource_spec.rb
+++ b/spec/requests/api/graphql/ci/catalog/resource_spec.rb
@@ -81,7 +81,7 @@
                   nodes {
                     id
                     name
-                    path
+                    includePath
                     inputs {
                       name
                       default
@@ -126,7 +126,7 @@
           a_graphql_entity_for(
             components.first,
             name: components.first.name,
-            path: components.first.path,
+            include_path: components.first.path,
             inputs: [
               a_graphql_entity_for(
                 name: 'tags',
@@ -148,7 +148,7 @@
           a_graphql_entity_for(
             components.last,
             name: components.last.name,
-            path: components.last.path
+            include_path: components.last.path
           )
         )
       end
diff --git a/spec/services/ci/catalog/resources/versions/create_service_spec.rb b/spec/services/ci/catalog/resources/versions/create_service_spec.rb
index e614a74a4a165..b57525fc8e1ce 100644
--- a/spec/services/ci/catalog/resources/versions/create_service_spec.rb
+++ b/spec/services/ci/catalog/resources/versions/create_service_spec.rb
@@ -115,6 +115,7 @@
           expect(response).to be_success
 
           version = Ci::Catalog::Resources::Version.last
+          base_path = "#{Settings.gitlab.host}/#{project.full_path}"
 
           expect(project.ci_components.count).to eq(4)
           expect(project.ci_components.first.name).to eq('blank-yaml')
@@ -122,25 +123,25 @@
           expect(project.ci_components.first.inputs).to eq({})
           expect(project.ci_components.first.catalog_resource).to eq(version.catalog_resource)
           expect(project.ci_components.first.version).to eq(version)
-          expect(project.ci_components.first.path).to eq('templates/blank-yaml.yml')
+          expect(project.ci_components.first.path).to eq("#{base_path}/blank-yaml@#{version.name}")
           expect(project.ci_components.second.name).to eq('dast')
           expect(project.ci_components.second.project).to eq(version.project)
           expect(project.ci_components.second.inputs).to eq({})
           expect(project.ci_components.second.catalog_resource).to eq(version.catalog_resource)
           expect(project.ci_components.second.version).to eq(version)
-          expect(project.ci_components.second.path).to eq('templates/dast/template.yml')
+          expect(project.ci_components.second.path).to eq("#{base_path}/dast@#{version.name}")
           expect(project.ci_components.third.name).to eq('secret-detection')
           expect(project.ci_components.third.project).to eq(version.project)
           expect(project.ci_components.third.inputs).to eq({ "website" => nil })
           expect(project.ci_components.third.catalog_resource).to eq(version.catalog_resource)
           expect(project.ci_components.third.version).to eq(version)
-          expect(project.ci_components.third.path).to eq('templates/secret-detection.yml')
+          expect(project.ci_components.third.path).to eq("#{base_path}/secret-detection@#{version.name}")
           expect(project.ci_components.fourth.name).to eq('template')
           expect(project.ci_components.fourth.project).to eq(version.project)
           expect(project.ci_components.fourth.inputs).to eq({ "environment" => nil })
           expect(project.ci_components.fourth.catalog_resource).to eq(version.catalog_resource)
           expect(project.ci_components.fourth.version).to eq(version)
-          expect(project.ci_components.fourth.path).to eq('templates/template.yml')
+          expect(project.ci_components.fourth.path).to eq("#{base_path}/template@#{version.name}")
         end
       end
     end
-- 
GitLab