Commit 60f3577e authored by Etienne Baqué's avatar Etienne Baqué Committed by Mark Lapierre

Moved project deploy tokens back to repository

Reverted deploy token section from ci/cd to repository.
Updated relevants assets, views, controllers, rspecs.
parent a349a7be
...@@ -3,7 +3,6 @@ import SecretValues from '~/behaviors/secret_values'; ...@@ -3,7 +3,6 @@ import SecretValues from '~/behaviors/secret_values';
import AjaxVariableList from '~/ci_variable_list/ajax_variable_list'; import AjaxVariableList from '~/ci_variable_list/ajax_variable_list';
import registrySettingsApp from '~/registry/settings/registry_settings_bundle'; import registrySettingsApp from '~/registry/settings/registry_settings_bundle';
import initVariableList from '~/ci_variable_list'; import initVariableList from '~/ci_variable_list';
import DueDateSelectors from '~/due_date_select';
import initDeployKeys from '~/deploy_keys'; import initDeployKeys from '~/deploy_keys';
document.addEventListener('DOMContentLoaded', () => { document.addEventListener('DOMContentLoaded', () => {
...@@ -41,9 +40,6 @@ document.addEventListener('DOMContentLoaded', () => { ...@@ -41,9 +40,6 @@ document.addEventListener('DOMContentLoaded', () => {
autoDevOpsExtraSettings.classList.toggle('hidden', !target.checked); autoDevOpsExtraSettings.classList.toggle('hidden', !target.checked);
}); });
// eslint-disable-next-line no-new
new DueDateSelectors();
registrySettingsApp(); registrySettingsApp();
initDeployKeys(); initDeployKeys();
}); });
...@@ -7,6 +7,6 @@ class Projects::DeployTokensController < Projects::ApplicationController ...@@ -7,6 +7,6 @@ class Projects::DeployTokensController < Projects::ApplicationController
@token = @project.deploy_tokens.find(params[:id]) @token = @project.deploy_tokens.find(params[:id])
@token.revoke! @token.revoke!
redirect_to project_settings_ci_cd_path(project, anchor: 'js-deploy-tokens') redirect_to project_settings_repository_path(project, anchor: 'js-deploy-tokens')
end end
end end
...@@ -48,33 +48,6 @@ module Projects ...@@ -48,33 +48,6 @@ module Projects
redirect_to namespace_project_settings_ci_cd_path redirect_to namespace_project_settings_ci_cd_path
end end
def create_deploy_token
result = Projects::DeployTokens::CreateService.new(@project, current_user, deploy_token_params).execute
@new_deploy_token = result[:deploy_token]
if result[:status] == :success
respond_to do |format|
format.json do
# IMPORTANT: It's a security risk to expose the token value more than just once here!
json = API::Entities::DeployTokenWithToken.represent(@new_deploy_token).as_json
render json: json, status: result[:http_status]
end
format.html do
flash.now[:notice] = s_('DeployTokens|Your new project deploy token has been created.')
render :show
end
end
else
respond_to do |format|
format.json { render json: { message: result[:message] }, status: result[:http_status] }
format.html do
flash.now[:alert] = result[:message]
render :show
end
end
end
end
private private
def update_params def update_params
...@@ -93,10 +66,6 @@ module Projects ...@@ -93,10 +66,6 @@ module Projects
end end
end end
def deploy_token_params
params.require(:deploy_token).permit(:name, :expires_at, :read_repository, :read_registry, :write_registry, :username)
end
def run_autodevops_pipeline(service) def run_autodevops_pipeline(service)
return unless service.run_auto_devops_pipeline? return unless service.run_auto_devops_pipeline?
...@@ -116,7 +85,6 @@ module Projects ...@@ -116,7 +85,6 @@ module Projects
def define_variables def define_variables
define_runners_variables define_runners_variables
define_ci_variables define_ci_variables
define_deploy_token_variables
define_triggers_variables define_triggers_variables
define_badges_variables define_badges_variables
define_auto_devops_variables define_auto_devops_variables
...@@ -168,12 +136,6 @@ module Projects ...@@ -168,12 +136,6 @@ module Projects
@auto_devops = @project.auto_devops || ProjectAutoDevops.new @auto_devops = @project.auto_devops || ProjectAutoDevops.new
end end
def define_deploy_token_variables
@deploy_tokens = @project.deploy_tokens.active
@new_deploy_token = DeployToken.new
end
def define_deploy_keys def define_deploy_keys
@deploy_keys = DeployKeysPresenter.new(@project, current_user: current_user) @deploy_keys = DeployKeysPresenter.new(@project, current_user: current_user)
end end
......
...@@ -4,7 +4,10 @@ module Projects ...@@ -4,7 +4,10 @@ module Projects
module Settings module Settings
class RepositoryController < Projects::ApplicationController class RepositoryController < Projects::ApplicationController
before_action :authorize_admin_project! before_action :authorize_admin_project!
before_action :remote_mirror, only: [:show] before_action :define_variables, only: [:create_deploy_token]
before_action do
push_frontend_feature_flag(:ajax_new_deploy_token, @project)
end
def show def show
render_show render_show
...@@ -24,15 +27,47 @@ module Projects ...@@ -24,15 +27,47 @@ module Projects
redirect_to project_settings_repository_path(project) redirect_to project_settings_repository_path(project)
end end
def create_deploy_token
result = Projects::DeployTokens::CreateService.new(@project, current_user, deploy_token_params).execute
@new_deploy_token = result[:deploy_token]
if result[:status] == :success
respond_to do |format|
format.json do
# IMPORTANT: It's a security risk to expose the token value more than just once here!
json = API::Entities::DeployTokenWithToken.represent(@new_deploy_token).as_json
render json: json, status: result[:http_status]
end
format.html do
flash.now[:notice] = s_('DeployTokens|Your new project deploy token has been created.')
render :show
end
end
else
respond_to do |format|
format.json { render json: { message: result[:message] }, status: result[:http_status] }
format.html do
flash.now[:alert] = result[:message]
render :show
end
end
end
end
private private
def render_show def render_show
define_protected_refs define_variables
remote_mirror
render 'show' render 'show'
end end
def define_variables
define_deploy_token_variables
define_protected_refs
remote_mirror
end
# rubocop: disable CodeReuse/ActiveRecord # rubocop: disable CodeReuse/ActiveRecord
def define_protected_refs def define_protected_refs
@protected_branches = @project.protected_branches.order(:name).page(params[:page]) @protected_branches = @project.protected_branches.order(:name).page(params[:page])
...@@ -51,6 +86,10 @@ module Projects ...@@ -51,6 +86,10 @@ module Projects
@remote_mirror = project.remote_mirrors.first_or_initialize @remote_mirror = project.remote_mirrors.first_or_initialize
end end
def deploy_token_params
params.require(:deploy_token).permit(:name, :expires_at, :read_repository, :read_registry, :write_registry, :username)
end
def access_levels_options def access_levels_options
{ {
create_access_levels: levels_for_dropdown, create_access_levels: levels_for_dropdown,
...@@ -74,6 +113,12 @@ module Projects ...@@ -74,6 +113,12 @@ module Projects
{ open_branches: ProtectableDropdown.new(@project, :branches).hash } { open_branches: ProtectableDropdown.new(@project, :branches).hash }
end end
def define_deploy_token_variables
@deploy_tokens = @project.deploy_tokens.active
@new_deploy_token ||= DeployToken.new
end
def load_gon_index def load_gon_index
gon.push(protectable_tags_for_dropdown) gon.push(protectable_tags_for_dropdown)
gon.push(protectable_branches_for_dropdown) gon.push(protectable_branches_for_dropdown)
......
...@@ -2368,7 +2368,7 @@ class Project < ApplicationRecord ...@@ -2368,7 +2368,7 @@ class Project < ApplicationRecord
end end
def deploy_token_create_url(opts = {}) def deploy_token_create_url(opts = {})
Gitlab::Routing.url_helpers.create_deploy_token_project_settings_ci_cd_path(self, opts) Gitlab::Routing.url_helpers.create_deploy_token_project_settings_repository_path(self, opts)
end end
def deploy_token_revoke_url_for(token) def deploy_token_revoke_url_for(token)
......
...@@ -4,7 +4,6 @@ ...@@ -4,7 +4,6 @@
- expanded = expanded_by_default? - expanded = expanded_by_default?
- general_expanded = @project.errors.empty? ? expanded : true - general_expanded = @project.errors.empty? ? expanded : true
- deploy_token_description = s_('DeployTokens|Deploy tokens allow access to your repository and registry images.')
%section.settings#js-general-pipeline-settings.no-animate{ class: ('expanded' if general_expanded) } %section.settings#js-general-pipeline-settings.no-animate{ class: ('expanded' if general_expanded) }
.settings-header .settings-header
...@@ -52,8 +51,6 @@ ...@@ -52,8 +51,6 @@
.settings-content .settings-content
= render 'ci/variables/index', save_endpoint: project_variables_path(@project) = render 'ci/variables/index', save_endpoint: project_variables_path(@project)
= render "shared/deploy_tokens/index", group_or_project: @project, description: deploy_token_description
= render @deploy_keys = render @deploy_keys
%section.settings.no-animate#js-pipeline-triggers{ class: ('expanded' if expanded) } %section.settings.no-animate#js-pipeline-triggers{ class: ('expanded' if expanded) }
......
- breadcrumb_title _("Repository Settings") - breadcrumb_title _("Repository Settings")
- page_title _("Repository") - page_title _("Repository")
- @content_class = "limit-container-width" unless fluid_layout - @content_class = "limit-container-width" unless fluid_layout
- deploy_token_description = s_('DeployTokens|Deploy tokens allow access to your repository and registry images.')
= render "projects/default_branch/show" = render "projects/default_branch/show"
= render_if_exists "projects/push_rules/index" = render_if_exists "projects/push_rules/index"
...@@ -11,6 +12,7 @@ ...@@ -11,6 +12,7 @@
-# Those are used throughout the actual views. These `shared` views are then -# Those are used throughout the actual views. These `shared` views are then
-# reused in EE. -# reused in EE.
= render "projects/settings/repository/protected_branches" = render "projects/settings/repository/protected_branches"
= render "shared/deploy_tokens/index", group_or_project: @project, description: deploy_token_description
= render "projects/cleanup/show" = render "projects/cleanup/show"
= render_if_exists 'shared/promotions/promote_repository_features' = render_if_exists 'shared/promotions/promote_repository_features'
...@@ -73,7 +73,7 @@ constraints(::Constraints::ProjectUrlConstrainer.new) do ...@@ -73,7 +73,7 @@ constraints(::Constraints::ProjectUrlConstrainer.new) do
resource :ci_cd, only: [:show, :update], controller: 'ci_cd' do resource :ci_cd, only: [:show, :update], controller: 'ci_cd' do
post :reset_cache post :reset_cache
put :reset_registration_token put :reset_registration_token
post :create_deploy_token, path: 'deploy_token/create' post :create_deploy_token, path: 'deploy_token/create', to: 'repository#create_deploy_token'
end end
resource :operations, only: [:show, :update] do resource :operations, only: [:show, :update] do
...@@ -87,7 +87,7 @@ constraints(::Constraints::ProjectUrlConstrainer.new) do ...@@ -87,7 +87,7 @@ constraints(::Constraints::ProjectUrlConstrainer.new) do
resource :repository, only: [:show], controller: :repository do resource :repository, only: [:show], controller: :repository do
# TODO: Removed this "create_deploy_token" route after change was made in app/helpers/ci_variables_helper.rb:14 # TODO: Removed this "create_deploy_token" route after change was made in app/helpers/ci_variables_helper.rb:14
# See MR comment for more detail: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/27059#note_311585356 # See MR comment for more detail: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/27059#note_311585356
post :create_deploy_token, path: 'deploy_token/create', to: 'ci_cd#create_deploy_token' post :create_deploy_token, path: 'deploy_token/create'
post :cleanup post :cleanup
end end
end end
......
...@@ -8,8 +8,8 @@ module EE ...@@ -8,8 +8,8 @@ module EE
extend ActiveSupport::Concern extend ActiveSupport::Concern
prepended do prepended do
before_action :assign_variables_to_gon, only: [:show, :create_deploy_token] before_action :assign_variables_to_gon, only: [:show]
before_action :define_protected_env_variables, only: [:show, :create_deploy_token] before_action :define_protected_env_variables, only: [:show]
end end
# rubocop:disable Gitlab/ModuleWithInstanceVariables # rubocop:disable Gitlab/ModuleWithInstanceVariables
......
...@@ -9,7 +9,7 @@ module EE ...@@ -9,7 +9,7 @@ module EE
prepended do prepended do
include SafeMirrorParams include SafeMirrorParams
before_action :push_rule, only: [:show] before_action :push_rule, only: [:show, :create_deploy_token]
end end
private private
...@@ -41,15 +41,10 @@ module EE ...@@ -41,15 +41,10 @@ module EE
gon.push(current_project_id: project.id) if project gon.push(current_project_id: project.id) if project
end end
# rubocop:disable Gitlab/ModuleWithInstanceVariables
def render_show def render_show
@deploy_tokens = @project.deploy_tokens.active
define_protected_refs
push_rule push_rule
remote_mirror
render 'show' super
end end
end end
end end
......
---
title: Move project deploy tokens section back to Repository settings
merge_request: 29280
author:
type: changed
...@@ -13,20 +13,10 @@ module QA ...@@ -13,20 +13,10 @@ module QA
element :variables_settings_content element :variables_settings_content
end end
view 'app/views/shared/deploy_tokens/_index.html.haml' do
element :deploy_tokens_settings
end
view 'app/views/projects/deploy_keys/_index.html.haml' do view 'app/views/projects/deploy_keys/_index.html.haml' do
element :deploy_keys_settings element :deploy_keys_settings
end end
def expand_deploy_tokens(&block)
expand_section(:deploy_tokens_settings) do
Settings::DeployTokens.perform(&block)
end
end
def expand_deploy_keys(&block) def expand_deploy_keys(&block)
expand_section(:deploy_keys_settings) do expand_section(:deploy_keys_settings) do
Settings::DeployKeys.perform(&block) Settings::DeployKeys.perform(&block)
......
...@@ -15,6 +15,16 @@ module QA ...@@ -15,6 +15,16 @@ module QA
element :mirroring_repositories_settings_section element :mirroring_repositories_settings_section
end end
view 'app/views/shared/deploy_tokens/_index.html.haml' do
element :deploy_tokens_settings
end
def expand_deploy_tokens(&block)
expand_section(:deploy_tokens_settings) do
Settings::DeployTokens.perform(&block)
end
end
def expand_protected_branches(&block) def expand_protected_branches(&block)
expand_section(:protected_branches_settings) do expand_section(:protected_branches_settings) do
ProtectedBranches.perform(&block) ProtectedBranches.perform(&block)
......
...@@ -6,16 +6,16 @@ module QA ...@@ -6,16 +6,16 @@ module QA
attr_accessor :name, :expires_at attr_accessor :name, :expires_at
attribute :username do attribute :username do
Page::Project::Settings::CICD.perform do |cicd_page| Page::Project::Settings::Repository.perform do |repository_page|
cicd_page.expand_deploy_tokens do |token| repository_page.expand_deploy_tokens do |token|
token.token_username token.token_username
end end
end end
end end
attribute :password do attribute :password do
Page::Project::Settings::CICD.perform do |cicd_page| Page::Project::Settings::Repository.perform do |repository_page|
cicd_page.expand_deploy_tokens do |token| repository_page.expand_deploy_tokens do |token|
token.token_password token.token_password
end end
end end
...@@ -31,10 +31,10 @@ module QA ...@@ -31,10 +31,10 @@ module QA
def fabricate! def fabricate!
project.visit! project.visit!
Page::Project::Menu.perform(&:go_to_ci_cd_settings) Page::Project::Menu.perform(&:go_to_repository_settings)
Page::Project::Settings::CICD.perform do |cicd| Page::Project::Settings::Repository.perform do |setting|
cicd.expand_deploy_tokens do |page| setting.expand_deploy_tokens do |page|
page.fill_token_name(name) page.fill_token_name(name)
page.fill_token_expires_at(expires_at) page.fill_token_expires_at(expires_at)
page.fill_scopes(read_repository: true, read_registry: false) page.fill_scopes(read_repository: true, read_registry: false)
......
...@@ -266,84 +266,4 @@ describe Projects::Settings::CiCdController do ...@@ -266,84 +266,4 @@ describe Projects::Settings::CiCdController do
end end
end end
end end
describe 'POST create_deploy_token' do
context 'when ajax_new_deploy_token feature flag is disabled for the project' do
before do
stub_feature_flags(ajax_new_deploy_token: { enabled: false, thing: project })
end
it_behaves_like 'a created deploy token' do
let(:entity) { project }
let(:create_entity_params) { { namespace_id: project.namespace, project_id: project } }
let(:deploy_token_type) { DeployToken.deploy_token_types[:project_type] }
end
end
context 'when ajax_new_deploy_token feature flag is enabled for the project' do
let(:good_deploy_token_params) do
{
name: 'name',
expires_at: 1.day.from_now.to_s,
username: 'deployer',
read_repository: '1',
deploy_token_type: DeployToken.deploy_token_types[:project_type]
}
end
let(:request_params) do
{
namespace_id: project.namespace.to_param,
project_id: project.to_param,
deploy_token: deploy_token_params
}
end
subject { post :create_deploy_token, params: request_params, format: :json }
context('a good request') do
let(:deploy_token_params) { good_deploy_token_params }
let(:expected_response) do
{
'id' => be_a(Integer),
'name' => deploy_token_params[:name],
'username' => deploy_token_params[:username],
'expires_at' => Time.parse(deploy_token_params[:expires_at]),
'token' => be_a(String),
'scopes' => deploy_token_params.inject([]) do |scopes, kv|
key, value = kv
key.to_s.start_with?('read_') && !value.to_i.zero? ? scopes << key.to_s : scopes
end
}
end
it 'creates the deploy token' do
subject
expect(response).to have_gitlab_http_status(:created)
expect(response).to match_response_schema('public_api/v4/deploy_token')
expect(json_response).to match(expected_response)
end
end
context('a bad request') do
let(:deploy_token_params) { good_deploy_token_params.except(:read_repository) }
let(:expected_response) { { 'message' => "Scopes can't be blank" } }
it 'does not create the deploy token' do
subject
expect(response).to have_gitlab_http_status(:bad_request)
expect(json_response).to match(expected_response)
end
end
context('an invalid request') do
let(:deploy_token_params) { good_deploy_token_params.except(:name) }
it 'raises a validation error' do
expect { subject }.to raise_error(ActiveRecord::StatementInvalid)
end
end
end
end
end end
...@@ -32,4 +32,84 @@ describe Projects::Settings::RepositoryController do ...@@ -32,4 +32,84 @@ describe Projects::Settings::RepositoryController do
expect(RepositoryCleanupWorker).to have_received(:perform_async).once expect(RepositoryCleanupWorker).to have_received(:perform_async).once
end end
end end
describe 'POST create_deploy_token' do
context 'when ajax_new_deploy_token feature flag is disabled for the project' do
before do
stub_feature_flags(ajax_new_deploy_token: { enabled: false, thing: project })
end
it_behaves_like 'a created deploy token' do
let(:entity) { project }
let(:create_entity_params) { { namespace_id: project.namespace, project_id: project } }
let(:deploy_token_type) { DeployToken.deploy_token_types[:project_type] }
end
end
context 'when ajax_new_deploy_token feature flag is enabled for the project' do
let(:good_deploy_token_params) do
{
name: 'name',
expires_at: 1.day.from_now.to_s,
username: 'deployer',
read_repository: '1',
deploy_token_type: DeployToken.deploy_token_types[:project_type]
}
end
let(:request_params) do
{
namespace_id: project.namespace.to_param,
project_id: project.to_param,
deploy_token: deploy_token_params
}
end
subject { post :create_deploy_token, params: request_params, format: :json }
context('a good request') do
let(:deploy_token_params) { good_deploy_token_params }
let(:expected_response) do
{
'id' => be_a(Integer),
'name' => deploy_token_params[:name],
'username' => deploy_token_params[:username],
'expires_at' => Time.parse(deploy_token_params[:expires_at]),
'token' => be_a(String),
'scopes' => deploy_token_params.inject([]) do |scopes, kv|
key, value = kv
key.to_s.start_with?('read_') && !value.to_i.zero? ? scopes << key.to_s : scopes
end
}
end
it 'creates the deploy token' do
subject
expect(response).to have_gitlab_http_status(:created)
expect(response).to match_response_schema('public_api/v4/deploy_token')
expect(json_response).to match(expected_response)
end
end
context('a bad request') do
let(:deploy_token_params) { good_deploy_token_params.except(:read_repository) }
let(:expected_response) { { 'message' => "Scopes can't be blank" } }
it 'does not create the deploy token' do
subject
expect(response).to have_gitlab_http_status(:bad_request)
expect(json_response).to match(expected_response)
end
end
context('an invalid request') do
let(:deploy_token_params) { good_deploy_token_params.except(:name) }
it 'raises a validation error' do
expect { subject }.to raise_error(ActiveRecord::StatementInvalid)
end
end
end
end
end end
...@@ -7,22 +7,6 @@ describe 'Projects > Settings > CI / CD settings' do ...@@ -7,22 +7,6 @@ describe 'Projects > Settings > CI / CD settings' do
let_it_be(:user) { create(:user) } let_it_be(:user) { create(:user) }
let_it_be(:role) { :maintainer } let_it_be(:role) { :maintainer }
context 'Deploy tokens' do
let!(:deploy_token) { create(:deploy_token, projects: [project]) }
before do
project.add_role(user, role)
sign_in(user)
stub_container_registry_config(enabled: true)
stub_feature_flags(ajax_new_deploy_token: { enabled: false, thing: project })
visit project_settings_ci_cd_path(project)
end
it_behaves_like 'a deploy token in settings' do
let(:entity_type) { 'project' }
end
end
context 'Deploy Keys', :js do context 'Deploy Keys', :js do
let_it_be(:private_deploy_key) { create(:deploy_key, title: 'private_deploy_key', public: false) } let_it_be(:private_deploy_key) { create(:deploy_key, title: 'private_deploy_key', public: false) }
let_it_be(:public_deploy_key) { create(:another_deploy_key, title: 'public_deploy_key', public: true) } let_it_be(:public_deploy_key) { create(:another_deploy_key, title: 'public_deploy_key', public: true) }
......
...@@ -25,6 +25,20 @@ describe 'Projects > Settings > Repository settings' do ...@@ -25,6 +25,20 @@ describe 'Projects > Settings > Repository settings' do
context 'for maintainer' do context 'for maintainer' do
let(:role) { :maintainer } let(:role) { :maintainer }
context 'Deploy tokens' do
let!(:deploy_token) { create(:deploy_token, projects: [project]) }
before do
stub_container_registry_config(enabled: true)
stub_feature_flags(ajax_new_deploy_token: { enabled: false, thing: project })
visit project_settings_repository_path(project)
end
it_behaves_like 'a deploy token in settings' do
let(:entity_type) { 'project' }
end
end
context 'remote mirror settings' do context 'remote mirror settings' do
before do before do
visit project_settings_repository_path(project) visit project_settings_repository_path(project)
......
...@@ -12,7 +12,7 @@ describe 'Repository Settings > User sees revoke deploy token modal', :js do ...@@ -12,7 +12,7 @@ describe 'Repository Settings > User sees revoke deploy token modal', :js do
project.add_role(user, role) project.add_role(user, role)
sign_in(user) sign_in(user)
stub_feature_flags(ajax_new_deploy_token: { enabled: false, thing: project }) stub_feature_flags(ajax_new_deploy_token: { enabled: false, thing: project })
visit(project_settings_ci_cd_path(project)) visit(project_settings_repository_path(project))
click_link('Revoke') click_link('Revoke')
end end
......
...@@ -800,9 +800,8 @@ describe 'project routing' do ...@@ -800,9 +800,8 @@ describe 'project routing' do
it_behaves_like 'redirecting a legacy project path', "/gitlab/gitlabhq/settings/repository", "/gitlab/gitlabhq/-/settings/repository" it_behaves_like 'redirecting a legacy project path', "/gitlab/gitlabhq/settings/repository", "/gitlab/gitlabhq/-/settings/repository"
# TODO: remove this test as part of https://gitlab.com/gitlab-org/gitlab/issues/207079 (12.9) it 'to repository#create_deploy_token' do
it 'to ci_cd#create_deploy_token' do expect(post('gitlab/gitlabhq/-/settings/ci_cd/deploy_token/create')).to route_to('projects/settings/repository#create_deploy_token', namespace_id: 'gitlab', project_id: 'gitlabhq')
expect(post('gitlab/gitlabhq/-/settings/ci_cd/deploy_token/create')).to route_to('projects/settings/ci_cd#create_deploy_token', namespace_id: 'gitlab', project_id: 'gitlabhq')
end end
end end
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment