1# frozen_string_literal: true
2
3module QA
4  RSpec.describe 'Package Registry', :orchestrated, :packages, :reliable, :object_storage do
5    describe 'npm instance level endpoint' do
6      using RSpec::Parameterized::TableSyntax
7      include Runtime::Fixtures
8
9      let!(:registry_scope) { Runtime::Namespace.sandbox_name }
10      let!(:personal_access_token) do
11        unless Page::Main::Menu.perform(&:signed_in?)
12          Flow::Login.sign_in
13        end
14
15        Resource::PersonalAccessToken.fabricate!.token
16      end
17
18      let(:project_deploy_token) do
19        Resource::ProjectDeployToken.fabricate_via_api! do |deploy_token|
20          deploy_token.name = 'npm-deploy-token'
21          deploy_token.project = project
22          deploy_token.scopes = %w[
23            read_repository
24            read_package_registry
25            write_package_registry
26          ]
27        end
28      end
29
30      let(:uri) { URI.parse(Runtime::Scenario.gitlab_address) }
31      let(:gitlab_address_with_port) { "#{uri.scheme}://#{uri.host}:#{uri.port}" }
32      let(:gitlab_host_with_port) { "#{uri.host}:#{uri.port}" }
33
34      let!(:project) do
35        Resource::Project.fabricate_via_api! do |project|
36          project.name = 'npm-instace-level-publish'
37        end
38      end
39
40      let!(:another_project) do
41        Resource::Project.fabricate_via_api! do |another_project|
42          another_project.name = 'npm-instance-level-install'
43          another_project.template_name = 'express'
44          another_project.group = project.group
45        end
46      end
47
48      let!(:runner) do
49        Resource::Runner.fabricate! do |runner|
50          runner.name = "qa-runner-#{Time.now.to_i}"
51          runner.tags = ["runner-for-#{project.group.name}"]
52          runner.executor = :docker
53          runner.token = project.group.runners_token
54        end
55      end
56
57      let(:gitlab_ci_deploy_yaml) do
58        {
59          file_path: '.gitlab-ci.yml',
60          content:
61              <<~YAML
62              image: node:latest
63
64              stages:
65                - deploy
66
67              deploy:
68                stage: deploy
69                script:
70                  - echo "//${CI_SERVER_HOST}/api/v4/projects/${CI_PROJECT_ID}/packages/npm/:_authToken=#{auth_token}">.npmrc
71                  - npm publish
72                only:
73                  - "#{project.default_branch}"
74                tags:
75                  - "runner-for-#{project.group.name}"
76              YAML
77        }
78      end
79
80      let(:gitlab_ci_install_yaml) do
81        {
82          file_path: '.gitlab-ci.yml',
83          content:
84              <<~YAML
85              image: node:latest
86
87              stages:
88                - install
89
90              install:
91                stage: install
92                script:
93                  - "npm config set @#{registry_scope}:registry #{gitlab_address_with_port}/api/v4/packages/npm/"
94                  - "npm install #{package.name}"
95                cache:
96                  key: ${CI_BUILD_REF_NAME}
97                  paths:
98                    - node_modules/
99                artifacts:
100                  paths:
101                    - node_modules/
102                only:
103                  - "#{another_project.default_branch}"
104                tags:
105                  - "runner-for-#{another_project.group.name}"
106              YAML
107        }
108      end
109
110      let(:package_json) do
111        {
112          file_path: 'package.json',
113          content: <<~JSON
114            {
115              "name": "#{package.name}",
116              "version": "1.0.0",
117              "description": "Example package for GitLab npm registry",
118              "publishConfig": {
119                "@#{registry_scope}:registry": "#{gitlab_address_with_port}/api/v4/projects/#{project.id}/packages/npm/"
120              }
121            }
122          JSON
123      }
124      end
125
126      let(:package) do
127        Resource::Package.init do |package|
128          package.name = "@#{registry_scope}/#{project.name}-#{SecureRandom.hex(8)}"
129          package.project = project
130        end
131      end
132
133      after do
134        package.remove_via_api!
135        runner.remove_via_api!
136        project.remove_via_api!
137        another_project.remove_via_api!
138      end
139
140      where(:authentication_token_type, :token_name) do
141        :personal_access_token | 'Personal Access Token'
142        :ci_job_token          | 'CI Job Token'
143        :project_deploy_token  | 'Deploy Token'
144      end
145
146      with_them do
147        let(:auth_token) do
148          case authentication_token_type
149          when :personal_access_token
150            "\"#{personal_access_token}\""
151          when :ci_job_token
152            '${CI_JOB_TOKEN}'
153          when :project_deploy_token
154            "\"#{project_deploy_token.token}\""
155          end
156        end
157
158        it "push and pull a npm package via CI using a #{params[:token_name]}" do
159          Support::Retrier.retry_on_exception(max_attempts: 3, sleep_interval: 2) do
160            Resource::Repository::Commit.fabricate_via_api! do |commit|
161              commit.project = project
162              commit.commit_message = 'Add .gitlab-ci.yml'
163              commit.add_files([
164                                gitlab_ci_deploy_yaml,
165                                package_json
166                              ])
167            end
168          end
169
170          project.visit!
171          Flow::Pipeline.visit_latest_pipeline
172
173          Page::Project::Pipeline::Show.perform do |pipeline|
174            pipeline.click_job('deploy')
175          end
176
177          Page::Project::Job::Show.perform do |job|
178            expect(job).to be_successful(timeout: 800)
179          end
180
181          Support::Retrier.retry_on_exception(max_attempts: 3, sleep_interval: 2) do
182            Resource::Repository::Commit.fabricate_via_api! do |commit|
183              commit.project = another_project
184              commit.commit_message = 'Add .gitlab-ci.yml'
185              commit.add_files([
186                                gitlab_ci_install_yaml
187              ])
188            end
189          end
190
191          another_project.visit!
192          Flow::Pipeline.visit_latest_pipeline
193
194          Page::Project::Pipeline::Show.perform do |pipeline|
195            pipeline.click_job('install')
196          end
197
198          Page::Project::Job::Show.perform do |job|
199            expect(job).to be_successful(timeout: 800)
200            job.click_browse_button
201          end
202
203          Page::Project::Artifact::Show.perform do |artifacts|
204            artifacts.go_to_directory('node_modules')
205            artifacts.go_to_directory("@#{registry_scope}")
206            expect(artifacts).to have_content("#{project.name}")
207          end
208
209          project.visit!
210          Page::Project::Menu.perform(&:click_packages_link)
211
212          Page::Project::Packages::Index.perform do |index|
213            expect(index).to have_package(package.name)
214
215            index.click_package(package.name)
216          end
217
218          Page::Project::Packages::Show.perform do |show|
219            expect(show).to have_package_info(package.name, "1.0.0")
220
221            show.click_delete
222          end
223
224          Page::Project::Packages::Index.perform do |index|
225            expect(index).to have_content("Package deleted successfully")
226            expect(index).not_to have_package(package.name)
227          end
228        end
229      end
230    end
231  end
232end
233