Commit e0c150da authored by Shinya Maeda's avatar Shinya Maeda

Merge from master(Fix conflicts)

parents 45e516c9 87d90b5b
9.3.0-pre 9.4.0-pre
...@@ -396,6 +396,7 @@ import PerformanceBar from './performance_bar'; ...@@ -396,6 +396,7 @@ import PerformanceBar from './performance_bar';
initSettingsPanels(); initSettingsPanels();
break; break;
case 'projects:settings:ci_cd:show': case 'projects:settings:ci_cd:show':
case 'groups:settings:ci_cd:show':
new gl.ProjectVariables(); new gl.ProjectVariables();
break; break;
case 'ci:lints:create': case 'ci:lints:create':
......
...@@ -731,11 +731,11 @@ ...@@ -731,11 +731,11 @@
.merge-request-tabs-holder { .merge-request-tabs-holder {
top: $header-height; top: $header-height;
z-index: 100; z-index: 200;
background-color: $white-light; background-color: $white-light;
border-bottom: 1px solid $border-color; border-bottom: 1px solid $border-color;
@media(min-width: $screen-sm-min) { @media (min-width: $screen-sm-min) {
position: sticky; position: sticky;
position: -webkit-sticky; position: -webkit-sticky;
} }
...@@ -770,6 +770,12 @@ ...@@ -770,6 +770,12 @@
max-width: $limited-layout-width; max-width: $limited-layout-width;
margin-left: auto; margin-left: auto;
margin-right: auto; margin-right: auto;
.inner-page-scroll-tabs {
background-color: $white-light;
margin-left: -$gl-padding;
padding-left: $gl-padding;
}
} }
} }
......
module Groups
module Settings
class CiCdController < Groups::ApplicationController
before_action :authorize_admin_pipeline!
def show
define_secret_variables
end
private
def define_secret_variables
@variable = Ci::GroupVariable.new(group: group)
.present(current_user: current_user)
@variables = group.variables.order_key_asc
.map { |variable| variable.present(current_user: current_user) }
end
def authorize_admin_pipeline!
return render_404 unless can?(current_user, :admin_pipeline, group)
end
end
end
end
module Groups
class VariablesController < Groups::ApplicationController
before_action :variable, only: [:show, :update, :destroy]
before_action :authorize_admin_build!
def index
redirect_to group_settings_ci_cd_path(group)
end
def show
end
def update
if variable.update(variable_params)
redirect_to group_variables_path(group),
notice: 'Variable was successfully updated.'
else
render "show"
end
end
def create
@variable = group.variables.create(variable_params)
.present(current_user: current_user)
if @variable.persisted?
redirect_to group_settings_ci_cd_path(group),
notice: 'Variable was successfully created.'
else
render "show"
end
end
def destroy
if variable.destroy
redirect_to group_settings_ci_cd_path(group),
status: 302,
notice: 'Variable was successfully removed.'
else
redirect_to group_settings_ci_cd_path(group),
status: 302,
notice: 'Failed to remove the variable.'
end
end
private
def variable_params
params.require(:variable).permit(*variable_params_attributes)
end
def variable_params_attributes
%i[key value protected]
end
def variable
@variable ||= group.variables.find(params[:id]).present(current_user: current_user)
end
def authorize_admin_build!
return render_404 unless can?(current_user, :admin_build, group)
end
end
end
...@@ -21,7 +21,10 @@ module Projects ...@@ -21,7 +21,10 @@ module Projects
end end
def define_secret_variables def define_secret_variables
@variable = Ci::Variable.new @variable = Ci::Variable.new(project: project)
.present(current_user: current_user)
@variables = project.variables.order_key_asc
.map { |variable| variable.present(current_user: current_user) }
end end
def define_triggers_variables def define_triggers_variables
......
class Projects::VariablesController < Projects::ApplicationController class Projects::VariablesController < Projects::ApplicationController
before_action :variable, only: [:show, :update, :destroy]
before_action :authorize_admin_build! before_action :authorize_admin_build!
layout 'project_settings' layout 'project_settings'
...@@ -8,37 +9,39 @@ class Projects::VariablesController < Projects::ApplicationController ...@@ -8,37 +9,39 @@ class Projects::VariablesController < Projects::ApplicationController
end end
def show def show
@variable = @project.variables.find(params[:id])
end end
def update def update
@variable = @project.variables.find(params[:id]) if variable.update(variable_params)
redirect_to project_variables_path(project),
if @variable.update_attributes(variable_params) notice: 'Variable was successfully updated.'
redirect_to project_variables_path(project), notice: 'Variable was successfully updated.'
else else
render action: "show" render "show"
end end
end end
def create def create
@variable = @project.variables.new(variable_params) @variable = project.variables.create(variable_params)
.present(current_user: current_user)
if @variable.save if @variable.persisted?
flash[:notice] = 'Variables were successfully updated.' redirect_to project_settings_ci_cd_path(project),
redirect_to project_settings_ci_cd_path(project) notice: 'Variable was successfully created.'
else else
render "show" render "show"
end end
end end
def destroy def destroy
@key = @project.variables.find(params[:id]) if variable.destroy
@key.destroy
redirect_to project_settings_ci_cd_path(project), redirect_to project_settings_ci_cd_path(project),
status: 302, status: 302,
notice: 'Variable was successfully removed.' notice: 'Variable was successfully removed.'
else
redirect_to project_settings_ci_cd_path(project),
status: 302,
notice: 'Failed to remove the variable.'
end
end end
private private
...@@ -50,4 +53,8 @@ class Projects::VariablesController < Projects::ApplicationController ...@@ -50,4 +53,8 @@ class Projects::VariablesController < Projects::ApplicationController
def variable_params_attributes def variable_params_attributes
%i[id key value protected _destroy] %i[id key value protected _destroy]
end end
def variable
@variable ||= project.variables.find(params[:id]).present(current_user: current_user)
end
end end
...@@ -10,5 +10,11 @@ module BlobViewer ...@@ -10,5 +10,11 @@ module BlobViewer
def visible_to?(current_user) def visible_to?(current_user)
can?(current_user, :read_wiki, project) can?(current_user, :read_wiki, project)
end end
def render_error
return if project.has_external_wiki? || (project.wiki_enabled? && project.wiki.has_home_page?)
:no_wiki
end
end end
end end
...@@ -200,6 +200,7 @@ module Ci ...@@ -200,6 +200,7 @@ module Ci
variables += project.deployment_variables if has_environment? variables += project.deployment_variables if has_environment?
variables += yaml_variables variables += yaml_variables
variables += user_variables variables += user_variables
variables += project.group.secret_variables_for(ref, project).map(&:to_runner_variable) if project.group
variables += secret_variables(environment: environment) variables += secret_variables(environment: environment)
variables += trigger_request.user_variables if trigger_request variables += trigger_request.user_variables if trigger_request
variables += pipeline.pipeline_schedule.job_variables if pipeline.pipeline_schedule variables += pipeline.pipeline_schedule.job_variables if pipeline.pipeline_schedule
......
module Ci
class GroupVariable < ActiveRecord::Base
extend Ci::Model
include HasVariable
include Presentable
belongs_to :group
validates :key, uniqueness: { scope: :group_id }
scope :unprotected, -> { where(protected: false) }
end
end
...@@ -2,6 +2,7 @@ module Ci ...@@ -2,6 +2,7 @@ module Ci
class Variable < ActiveRecord::Base class Variable < ActiveRecord::Base
extend Ci::Model extend Ci::Model
include HasVariable include HasVariable
include Presentable
belongs_to :project belongs_to :project
......
...@@ -3,6 +3,8 @@ module ShaAttribute ...@@ -3,6 +3,8 @@ module ShaAttribute
module ClassMethods module ClassMethods
def sha_attribute(name) def sha_attribute(name)
return unless table_exists?
column = columns.find { |c| c.name == name.to_s } column = columns.find { |c| c.name == name.to_s }
# In case the table doesn't exist we won't be able to find the column, # In case the table doesn't exist we won't be able to find the column,
......
...@@ -22,6 +22,7 @@ class Group < Namespace ...@@ -22,6 +22,7 @@ class Group < Namespace
has_many :shared_projects, through: :project_group_links, source: :project has_many :shared_projects, through: :project_group_links, source: :project
has_many :notification_settings, dependent: :destroy, as: :source # rubocop:disable Cop/ActiveRecordDependent has_many :notification_settings, dependent: :destroy, as: :source # rubocop:disable Cop/ActiveRecordDependent
has_many :labels, class_name: 'GroupLabel' has_many :labels, class_name: 'GroupLabel'
has_many :variables, class_name: 'Ci::GroupVariable'
validate :avatar_type, if: ->(user) { user.avatar.present? && user.avatar_changed? } validate :avatar_type, if: ->(user) { user.avatar.present? && user.avatar_changed? }
validate :visibility_level_allowed_by_projects validate :visibility_level_allowed_by_projects
...@@ -248,6 +249,14 @@ class Group < Namespace ...@@ -248,6 +249,14 @@ class Group < Namespace
} }
end end
def secret_variables_for(ref, project)
list_of_ids = [self] + ancestors
variables = Ci::GroupVariable.where(group: list_of_ids)
variables = variables.unprotected unless project.protected_for?(ref)
variables = variables.group_by(&:group_id)
list_of_ids.reverse.map { |group| variables[group.id] }.compact.flatten
end
protected protected
def update_two_factor_requirement def update_two_factor_requirement
......
...@@ -63,6 +63,10 @@ class ProjectWiki ...@@ -63,6 +63,10 @@ class ProjectWiki
!!repository.exists? !!repository.exists?
end end
def has_home_page?
!!find_page('home')
end
# Returns an Array of Gitlab WikiPage instances or an # Returns an Array of Gitlab WikiPage instances or an
# empty Array if this Wiki has no pages. # empty Array if this Wiki has no pages.
def pages def pages
......
...@@ -31,6 +31,8 @@ class GroupPolicy < BasePolicy ...@@ -31,6 +31,8 @@ class GroupPolicy < BasePolicy
rule { master }.policy do rule { master }.policy do
enable :create_projects enable :create_projects
enable :admin_milestones enable :admin_milestones
enable :admin_pipeline
enable :admin_build
end end
rule { owner }.policy do rule { owner }.policy do
......
module Ci
class GroupVariablePresenter < Gitlab::View::Presenter::Delegated
presents :variable
def placeholder
'GROUP_VARIABLE'
end
def form_path
if variable.persisted?
group_variable_path(group, variable)
else
group_variables_path(group)
end
end
def edit_path
group_variable_path(group, variable)
end
def delete_path
group_variable_path(group, variable)
end
end
end
module Ci
class VariablePresenter < Gitlab::View::Presenter::Delegated
presents :variable
def placeholder
'PROJECT_VARIABLE'
end
def form_path
if variable.persisted?
project_variable_path(project, variable)
else
project_variables_path(project)
end
end
def edit_path
project_variable_path(project, variable)
end
def delete_path
project_variable_path(project, variable)
end
end
end
= form_for [@project.namespace.becomes(Namespace), @project, @variable] do |f| = form_for @variable, as: :variable, url: @variable.form_path do |f|
= form_errors(@variable) = form_errors(@variable)
.form-group .form-group
= f.label :key, "Key", class: "label-light" = f.label :key, "Key", class: "label-light"
= f.text_field :key, class: "form-control", placeholder: "PROJECT_VARIABLE", required: true = f.text_field :key, class: "form-control", placeholder: @variable.placeholder, required: true
.form-group .form-group
= f.label :value, "Value", class: "label-light" = f.label :value, "Value", class: "label-light"
= f.text_area :value, class: "form-control", placeholder: "PROJECT_VARIABLE" = f.text_area :value, class: "form-control", placeholder: @variable.placeholder
.form-group .form-group
.checkbox .checkbox
= f.label :protected do = f.label :protected do
......
.row.prepend-top-default.append-bottom-default .row.prepend-top-default.append-bottom-default
.col-lg-4 .col-lg-4
= render "projects/variables/content" = render "ci/variables/content"
.col-lg-8 .col-lg-8
%h5.prepend-top-0 %h5.prepend-top-0
Add a variable Add a variable
= render "projects/variables/form", btn_text: "Add new variable" = render "ci/variables/form", btn_text: "Add new variable"
%hr %hr
%h5.prepend-top-0 %h5.prepend-top-0
Your variables (#{@project.variables.size}) Your variables (#{@variables.size})
- if @project.variables.empty? - if @variables.empty?
%p.settings-message.text-center.append-bottom-0 %p.settings-message.text-center.append-bottom-0
No variables found, add one with the form above. No variables found, add one with the form above.
- else - else
= render "projects/variables/table" = render "ci/variables/table"
%button.btn.btn-info.js-btn-toggle-reveal-values{ "data-status" => 'hidden' } Reveal Values %button.btn.btn-info.js-btn-toggle-reveal-values{ "data-status" => 'hidden' } Reveal Values
- page_title "Variables"
.row.prepend-top-default.append-bottom-default
.col-lg-3
= render "ci/variables/content"
.col-lg-9
%h5.prepend-top-0
Update variable
= render "ci/variables/form", btn_text: "Save variable"
...@@ -11,18 +11,18 @@ ...@@ -11,18 +11,18 @@
%th Protected %th Protected
%th %th
%tbody %tbody
- @project.variables.order_key_asc.each do |variable| - @variables.each do |variable|
- if variable.id? - if variable.id?
%tr %tr
%td.variable-key= variable.key %td.variable-key= variable.key
%td.variable-value{ "data-value" => variable.value }****** %td.variable-value{ "data-value" => variable.value }******
%td.variable-protected= Gitlab::Utils.boolean_to_yes_no(variable.protected) %td.variable-protected= Gitlab::Utils.boolean_to_yes_no(variable.protected)
%td.variable-menu %td.variable-menu
= link_to project_variable_path(@project, variable), class: "btn btn-transparent btn-variable-edit" do = link_to variable.edit_path, class: "btn btn-transparent btn-variable-edit" do
%span.sr-only %span.sr-only
Update Update
= icon("pencil") = icon("pencil")
= link_to project_variable_path(@project, variable), class: "btn btn-transparent btn-variable-delete", method: :delete, data: { confirm: "Are you sure?" } do = link_to variable.delete_path, class: "btn btn-transparent btn-variable-delete", method: :delete, data: { confirm: "Are you sure?" } do
%span.sr-only %span.sr-only
Remove Remove
= icon("trash") = icon("trash")
...@@ -12,3 +12,8 @@ ...@@ -12,3 +12,8 @@
= link_to projects_group_path(@group), title: 'Projects' do = link_to projects_group_path(@group), title: 'Projects' do
%span %span
Projects Projects
= nav_link(controller: :ci_cd) do
= link_to group_settings_ci_cd_path(@group), title: 'Pipelines' do
%span
Pipelines
- page_title "Pipelines"
= render "groups/settings_head"
= render 'ci/variables/index'
= icon('info-circle fw') = icon('info-circle fw')
= succeed '.' do = succeed '.' do
To learn more about this project, read To learn more about this project, read
= link_to "the wiki", project_wikis_path(viewer.project) = link_to "the wiki", get_project_wiki_path(viewer.project)
...@@ -3,6 +3,6 @@ ...@@ -3,6 +3,6 @@
= render "projects/settings/head" = render "projects/settings/head"
= render 'projects/runners/index' = render 'projects/runners/index'
= render 'projects/variables/index' = render 'ci/variables/index'
= render 'projects/triggers/index' = render 'projects/triggers/index'
= render 'projects/pipelines_settings/show' = render 'projects/pipelines_settings/show'
- page_title "Variables" = render 'ci/variables/show'
.row.prepend-top-default.append-bottom-default
.col-lg-3
= render "content"
.col-lg-9
%h5.prepend-top-0
Update variable
= render "form", btn_text: "Save variable"
---
title: Don't show auxiliary blob viewer for README when there is no wiki
merge_request:
author:
---
title: Add Group secret variables
merge_request: 12582
author:
---
title: Remove option to disable Gitaly
merge_request: 12677
author:
...@@ -450,10 +450,6 @@ production: &base ...@@ -450,10 +450,6 @@ production: &base
# Gitaly settings # Gitaly settings
gitaly: gitaly:
# This setting controls whether GitLab uses Gitaly (new component
# introduced in 9.0). Eventually Gitaly use will become mandatory and
# this option will disappear.
enabled: true
# Default Gitaly authentication token. Can be overriden per storage. Can # Default Gitaly authentication token. Can be overriden per storage. Can
# be left blank when Gitaly is running locally on a Unix socket, which # be left blank when Gitaly is running locally on a Unix socket, which
# is the normal way to deploy Gitaly. # is the normal way to deploy Gitaly.
......
...@@ -483,7 +483,6 @@ Settings.rack_attack.git_basic_auth['bantime'] ||= 1.hour ...@@ -483,7 +483,6 @@ Settings.rack_attack.git_basic_auth['bantime'] ||= 1.hour
# Gitaly # Gitaly
# #
Settings['gitaly'] ||= Settingslogic.new({}) Settings['gitaly'] ||= Settingslogic.new({})
Settings.gitaly['enabled'] = true if Settings.gitaly['enabled'].nil?
# #
# Webpack settings # Webpack settings
......
require 'uri' require 'uri'
if Gitlab.config.gitaly.enabled || Rails.env.test? Gitlab.config.repositories.storages.keys.each do |storage|
Gitlab.config.repositories.storages.keys.each do |storage|
# Force validation of each address # Force validation of each address
Gitlab::GitalyClient.address(storage) Gitlab::GitalyClient.address(storage)
end
end end
...@@ -23,6 +23,14 @@ scope(path: 'groups/*group_id', ...@@ -23,6 +23,14 @@ scope(path: 'groups/*group_id',
resources :labels, except: [:show] do resources :labels, except: [:show] do
post :toggle_subscription, on: :member post :toggle_subscription, on: :member
end end
scope path: '-' do
namespace :settings do
resource :ci_cd, only: [:show], controller: 'ci_cd'
end
resources :variables, only: [:index, :show, :update, :create, :destroy]
end
end end
scope(path: 'groups/*id', scope(path: 'groups/*id',
......
class CreateGroupVariablesTable < ActiveRecord::Migration
DOWNTIME = false
def up
create_table :ci_group_variables do |t|
t.string :key, null: false
t.text :value
t.text :encrypted_value
t.string :encrypted_value_salt
t.string :encrypted_value_iv
t.integer :group_id, null: false
t.boolean :protected, default: false, null: false
t.timestamps_with_timezone null: false
end
add_index :ci_group_variables, [:group_id, :key], unique: true
end
def down
drop_table :ci_group_variables
end
end
class AddForeignKeyToGroupVariables < ActiveRecord::Migration
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
disable_ddl_transaction!
def up
add_concurrent_foreign_key :ci_group_variables, :namespaces, column: :group_id
end
def down
remove_foreign_key :ci_group_variables, column: :group_id
end
end
...@@ -266,6 +266,20 @@ ActiveRecord::Schema.define(version: 20170703102400) do ...@@ -266,6 +266,20 @@ ActiveRecord::Schema.define(version: 20170703102400) do
add_index "ci_pipeline_schedule_variables", ["pipeline_schedule_id", "key"], name: "index_ci_pipeline_schedule_variables_on_schedule_id_and_key", unique: true, using: :btree add_index "ci_pipeline_schedule_variables", ["pipeline_schedule_id", "key"], name: "index_ci_pipeline_schedule_variables_on_schedule_id_and_key", unique: true, using: :btree
create_table "ci_group_variables", force: :cascade do |t|
t.string "key", null: false
t.text "value"
t.text "encrypted_value"
t.string "encrypted_value_salt"
t.string "encrypted_value_iv"
t.integer "group_id", null: false
t.boolean "protected", default: false, null: false
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
add_index "ci_group_variables", ["group_id", "key"], name: "index_ci_group_variables_on_group_id_and_key", unique: true, using: :btree
create_table "ci_pipeline_schedules", force: :cascade do |t| create_table "ci_pipeline_schedules", force: :cascade do |t|
t.string "description" t.string "description"
t.string "ref" t.string "ref"
...@@ -1564,6 +1578,7 @@ ActiveRecord::Schema.define(version: 20170703102400) do ...@@ -1564,6 +1578,7 @@ ActiveRecord::Schema.define(version: 20170703102400) do
add_foreign_key "ci_builds", "ci_stages", column: "stage_id", name: "fk_3a9eaa254d", on_delete: :cascade add_foreign_key "ci_builds", "ci_stages", column: "stage_id", name: "fk_3a9eaa254d", on_delete: :cascade
add_foreign_key "ci_builds", "projects", name: "fk_befce0568a", on_delete: :cascade add_foreign_key "ci_builds", "projects", name: "fk_befce0568a", on_delete: :cascade
add_foreign_key "ci_pipeline_schedule_variables", "ci_pipeline_schedules", column: "pipeline_schedule_id", name: "fk_41c35fda51", on_delete: :cascade add_foreign_key "ci_pipeline_schedule_variables", "ci_pipeline_schedules", column: "pipeline_schedule_id", name: "fk_41c35fda51", on_delete: :cascade
add_foreign_key "ci_group_variables", "namespaces", column: "group_id", name: "fk_33ae4d58d8", on_delete: :cascade
add_foreign_key "ci_pipeline_schedules", "projects", name: "fk_8ead60fcc4", on_delete: :cascade add_foreign_key "ci_pipeline_schedules", "projects", name: "fk_8ead60fcc4", on_delete: :cascade
add_foreign_key "ci_pipeline_schedules", "users", column: "owner_id", name: "fk_9ea99f58d2", on_delete: :nullify add_foreign_key "ci_pipeline_schedules", "users", column: "owner_id", name: "fk_9ea99f58d2", on_delete: :nullify
add_foreign_key "ci_pipelines", "ci_pipeline_schedules", column: "pipeline_schedule_id", name: "fk_3d34ab2e06", on_delete: :nullify add_foreign_key "ci_pipelines", "ci_pipeline_schedules", column: "pipeline_schedule_id", name: "fk_3d34ab2e06", on_delete: :nullify
......
...@@ -179,6 +179,7 @@ have access to GitLab administration tools and settings. ...@@ -179,6 +179,7 @@ have access to GitLab administration tools and settings.
### Admin tools ### Admin tools
- [Gitaly](administration/gitaly/index.md): Configuring Gitaly, GitLab's Git repository storage service
- [Raketasks](raketasks/README.md): Backups, maintenance, automatic webhook setup and the importing of projects. - [Raketasks](raketasks/README.md): Backups, maintenance, automatic webhook setup and the importing of projects.
- [Backup and restore](raketasks/backup_restore.md): Backup and restore your GitLab instance. - [Backup and restore](raketasks/backup_restore.md): Backup and restore your GitLab instance.
- [Reply by email](administration/reply_by_email.md): Allow users to comment on issues and merge requests by replying to notification emails. - [Reply by email](administration/reply_by_email.md): Allow users to comment on issues and merge requests by replying to notification emails.
......
...@@ -2,8 +2,7 @@ ...@@ -2,8 +2,7 @@
[Gitaly](https://gitlab.com/gitlab-org/gitaly) (introduced in GitLab [Gitaly](https://gitlab.com/gitlab-org/gitaly) (introduced in GitLab
9.0) is a service that provides high-level RPC access to Git 9.0) is a service that provides high-level RPC access to Git
repositories. As of GitLab 9.3 it is still an optional component with repositories. Gitaly is a mandatory component in GitLab 9.4 and newer.
limited scope.
GitLab components that access Git repositories (gitlab-rails, GitLab components that access Git repositories (gitlab-rails,
gitlab-shell, gitlab-workhorse) act as clients to Gitaly. End users do gitlab-shell, gitlab-workhorse) act as clients to Gitaly. End users do
...@@ -149,6 +148,8 @@ git_data_dirs({ ...@@ -149,6 +148,8 @@ git_data_dirs({
{ 'default' => { 'path' => '/mnt/gitlab/default', 'gitaly_address' => 'tcp://gitlab.internal:9999' } }, { 'default' => { 'path' => '/mnt/gitlab/default', 'gitaly_address' => 'tcp://gitlab.internal:9999' } },
{ 'storage1' => { 'path' => '/mnt/gitlab/storage1', 'gitaly_address' => 'tcp://gitlab.internal:9999' } }, { 'storage1' => { 'path' => '/mnt/gitlab/storage1', 'gitaly_address' => 'tcp://gitlab.internal:9999' } },
}) })
gitlab_rails['gitaly_token'] = 'abc123secret'
``` ```
Source installations: Source installations:
...@@ -164,6 +165,9 @@ gitlab: ...@@ -164,6 +165,9 @@ gitlab:
storage1: storage1:
path: /mnt/gitlab/storage1/repositories path: /mnt/gitlab/storage1/repositories
gitaly_address: tcp://gitlab.internal:9999 gitaly_address: tcp://gitlab.internal:9999
gitaly:
token: 'abc123secret'
``` ```
Now reconfigure (Omnibus) or restart (source). When you tail the Now reconfigure (Omnibus) or restart (source). When you tail the
...@@ -172,36 +176,11 @@ Gitaly logs on your Gitaly server (`sudo gitlab-ctl tail gitaly` or ...@@ -172,36 +176,11 @@ Gitaly logs on your Gitaly server (`sudo gitlab-ctl tail gitaly` or
coming in. One sure way to trigger a Gitaly request is to clone a coming in. One sure way to trigger a Gitaly request is to clone a
repository from your GitLab server over HTTP. repository from your GitLab server over HTTP.
## Configuring GitLab to not use Gitaly
Gitaly is still an optional component in GitLab 9.3. This means you
can choose to not use it.
In Omnibus you can make the following change in
`/etc/gitlab/gitlab.rb` and reconfigure. This will both disable the
Gitaly service and configure the rest of GitLab not to use it.
```ruby
gitaly['enable'] = false
```
In source installations, edit `/home/git/gitlab/config/gitlab.yml` and
make sure `enabled` in the `gitaly` section is set to 'false'. This
does not disable the Gitaly service in your init script; it only
prevents it from being used.
Apply the change with `service gitlab restart`.
```yaml
gitaly:
enabled: false
```
## Disabling or enabling the Gitaly service ## Disabling or enabling the Gitaly service
Be careful: if you disable Gitaly without instructing the rest of your If you are running Gitaly [as a remote
GitLab installation not to use Gitaly, you may end up with errors service](#running-gitaly-on-its-own-server) you may want to disable
because GitLab tries to access a service that is not running. the local Gitaly service that runs on your Gitlab server by default.
To disable the Gitaly service in your Omnibus installation, add the To disable the Gitaly service in your Omnibus installation, add the
following line to `/etc/gitlab/gitlab.rb`: following line to `/etc/gitlab/gitlab.rb`:
......
...@@ -10,7 +10,8 @@ The variables can be overwritten and they take precedence over each other in ...@@ -10,7 +10,8 @@ The variables can be overwritten and they take precedence over each other in
this order: this order:
1. [Trigger variables][triggers] or [scheduled pipeline variables](../../user/project/pipelines/schedules.md#making-use-of-scheduled-pipeline-variables) (take precedence over all) 1. [Trigger variables][triggers] or [scheduled pipeline variables](../../user/project/pipelines/schedules.md#making-use-of-scheduled-pipeline-variables) (take precedence over all)
1. [Secret variables](#secret-variables) or [protected secret variables](#protected-secret-variables) 1. Project-level [secret variables](#secret-variables) or [protected secret variables](#protected-secret-variables)
1. Group-level [secret variables](#secret-variables) or [protected secret variables](#protected-secret-variables)
1. YAML-defined [job-level variables](../yaml/README.md#job-variables) 1. YAML-defined [job-level variables](../yaml/README.md#job-variables)
1. YAML-defined [global variables](../yaml/README.md#variables) 1. YAML-defined [global variables](../yaml/README.md#variables)
1. [Deployment variables](#deployment-variables) 1. [Deployment variables](#deployment-variables)
...@@ -142,23 +143,28 @@ script: ...@@ -142,23 +143,28 @@ script:
>**Notes:** >**Notes:**
- This feature requires GitLab Runner 0.4.0 or higher. - This feature requires GitLab Runner 0.4.0 or higher.
- Group-level secret variables added in GitLab 9.4.
- Be aware that secret variables are not masked, and their values can be shown - Be aware that secret variables are not masked, and their values can be shown
in the job logs if explicitly asked to do so. If your project is public or in the job logs if explicitly asked to do so. If your project is public or
internal, you can set the pipelines private from your project's Pipelines internal, you can set the pipelines private from your project's Pipelines
settings. Follow the discussion in issue [#13784][ce-13784] for masking the settings. Follow the discussion in issue [#13784][ce-13784] for masking the
secret variables. secret variables.
GitLab CI allows you to define per-project **secret variables** that are set in GitLab CI allows you to define per-project or per-group **secret variables**
the build environment. The secret variables are stored out of the repository that are set in the build environment. The secret variables are stored out of
(`.gitlab-ci.yml`) and are securely passed to GitLab Runner making them the repository (`.gitlab-ci.yml`) and are securely passed to GitLab Runner
available in the build environment. It's the recommended method to use for making them available in the build environment. It's the recommended method to
storing things like passwords, secret keys and credentials. use for storing things like passwords, secret keys and credentials.
Secret variables can be added by going to your project's Project-level secret variables can be added by going to your project's
**Settings ➔ Pipelines**, then finding the section called **Settings ➔ Pipelines**, then finding the section called **Secret variables**.
**Secret variables**.
Once you set them, they will be available for all subsequent pipelines. Likewise, group-level secret variables can be added by going to your group's
**Settings ➔ Pipelines**, then finding the section called **Secret variables**.
Any variables of [subgroups] will be inherited recursively.
Once you set them, they will be available for all subsequent pipelines. You can also
[protect your variables](#protected-secret-variables).
### Protected secret variables ### Protected secret variables
...@@ -434,3 +440,4 @@ export CI_REGISTRY_PASSWORD="longalfanumstring" ...@@ -434,3 +440,4 @@ export CI_REGISTRY_PASSWORD="longalfanumstring"
[shellexecutors]: https://docs.gitlab.com/runner/executors/ [shellexecutors]: https://docs.gitlab.com/runner/executors/
[triggered]: ../triggers/README.md [triggered]: ../triggers/README.md
[triggers]: ../triggers/README.md#pass-job-variables-to-a-trigger [triggers]: ../triggers/README.md#pass-job-variables-to-a-trigger
[subgroups]: ../../user/group/subgroups/index.md
...@@ -148,6 +148,8 @@ sudo -u git -H make ...@@ -148,6 +148,8 @@ sudo -u git -H make
If you have not yet set up Gitaly then follow [Gitaly section of the installation If you have not yet set up Gitaly then follow [Gitaly section of the installation
guide](../install/installation.md#install-gitaly). guide](../install/installation.md#install-gitaly).
As of GitLab 9.4, Gitaly is a mandatory component of GitLab.
#### Check Gitaly configuration #### Check Gitaly configuration
Due to a bug in the `rake gitlab:gitaly:install` script your Gitaly Due to a bug in the `rake gitlab:gitaly:install` script your Gitaly
......
...@@ -70,12 +70,8 @@ module Gitlab ...@@ -70,12 +70,8 @@ module Gitlab
params['gitaly_token'].presence || Gitlab.config.gitaly['token'] params['gitaly_token'].presence || Gitlab.config.gitaly['token']
end end
def self.enabled?
Gitlab.config.gitaly.enabled
end
def self.feature_enabled?(feature, status: MigrationStatus::OPT_IN) def self.feature_enabled?(feature, status: MigrationStatus::OPT_IN)
return false if !enabled? || status == MigrationStatus::DISABLED return false if status == MigrationStatus::DISABLED
feature = Feature.get("gitaly_#{feature}") feature = Feature.get("gitaly_#{feature}")
......
...@@ -112,6 +112,7 @@ module Gitlab ...@@ -112,6 +112,7 @@ module Gitlab
# this group would not be accessible through `/groups/parent/activity` since # this group would not be accessible through `/groups/parent/activity` since
# this would map to the activity-page of its parent. # this would map to the activity-page of its parent.
GROUP_ROUTES = %w[ GROUP_ROUTES = %w[
-
activity activity
analytics analytics
audit_events audit_events
......
...@@ -25,7 +25,6 @@ module Gitlab ...@@ -25,7 +25,6 @@ module Gitlab
RepoPath: repo_path RepoPath: repo_path
} }
if Gitlab.config.gitaly.enabled
server = { server = {
address: Gitlab::GitalyClient.address(project.repository_storage), address: Gitlab::GitalyClient.address(project.repository_storage),
token: Gitlab::GitalyClient.token(project.repository_storage) token: Gitlab::GitalyClient.token(project.repository_storage)
...@@ -46,7 +45,6 @@ module Gitlab ...@@ -46,7 +45,6 @@ module Gitlab
params[:GitalyAddress] = server[:address] # This field will be deprecated params[:GitalyAddress] = server[:address] # This field will be deprecated
params[:GitalyServer] = server params[:GitalyServer] = server
end end
end
params params
end end
......
require 'spec_helper'
describe Groups::Settings::CiCdController do
let(:group) { create(:group) }
let(:user) { create(:user) }
before do
group.add_master(user)
sign_in(user)
end
describe 'GET #show' do
it 'renders show with 200 status code' do
get :show, group_id: group
expect(response).to have_http_status(200)
expect(response).to render_template(:show)
end
end
end
require 'spec_helper'
describe Groups::VariablesController do
let(:group) { create(:group) }
let(:user) { create(:user) }
before do
sign_in(user)
group.add_master(user)
end
describe 'POST #create' do
context 'variable is valid' do
it 'shows a success flash message' do
post :create, group_id: group, variable: { key: "one", value: "two" }
expect(flash[:notice]).to include 'Variable was successfully created.'
expect(response).to redirect_to(group_settings_ci_cd_path(group))
end
end
context 'variable is invalid' do
it 'renders show' do
post :create, group_id: group, variable: { key: "..one", value: "two" }
expect(response).to render_template("groups/variables/show")
end
end
end
describe 'POST #update' do
let(:variable) { create(:ci_group_variable) }
context 'updating a variable with valid characters' do
before do
group.variables << variable
end
it 'shows a success flash message' do
post :update, group_id: group,
id: variable.id, variable: { key: variable.key, value: 'two' }
expect(flash[:notice]).to include 'Variable was successfully updated.'
expect(response).to redirect_to(group_variables_path(group))
end
it 'renders the action #show if the variable key is invalid' do
post :update, group_id: group,
id: variable.id, variable: { key: '?', value: variable.value }
expect(response).to have_http_status(200)
expect(response).to render_template :show
end
end
end
end
...@@ -15,13 +15,13 @@ describe Projects::VariablesController do ...@@ -15,13 +15,13 @@ describe Projects::VariablesController do
post :create, namespace_id: project.namespace.to_param, project_id: project, post :create, namespace_id: project.namespace.to_param, project_id: project,
variable: { key: "one", value: "two" } variable: { key: "one", value: "two" }
expect(flash[:notice]).to include 'Variables were successfully updated.' expect(flash[:notice]).to include 'Variable was successfully created.'
expect(response).to redirect_to(project_settings_ci_cd_path(project)) expect(response).to redirect_to(project_settings_ci_cd_path(project))
end end
end end
context 'variable is invalid' do context 'variable is invalid' do
it 'shows an alert flash message' do it 'renders show' do
post :create, namespace_id: project.namespace.to_param, project_id: project, post :create, namespace_id: project.namespace.to_param, project_id: project,
variable: { key: "..one", value: "two" } variable: { key: "..one", value: "two" }
...@@ -35,7 +35,6 @@ describe Projects::VariablesController do ...@@ -35,7 +35,6 @@ describe Projects::VariablesController do
context 'updating a variable with valid characters' do context 'updating a variable with valid characters' do
before do before do
variable.project_id = project.id
project.variables << variable project.variables << variable
end end
......
FactoryGirl.define do
factory :ci_group_variable, class: Ci::GroupVariable do
sequence(:key) { |n| "VARIABLE_#{n}" }
value 'VARIABLE_VALUE'
trait(:protected) do
protected true
end
group factory: :group
end
end
require 'spec_helper'
feature 'Group variables', js: true do
let(:user) { create(:user) }
let(:group) { create(:group) }
background do
group.add_master(user)
gitlab_sign_in(user)
end
context 'when user creates a new variable' do
background do
visit group_settings_ci_cd_path(group)
fill_in 'variable_key', with: 'AAA'
fill_in 'variable_value', with: 'AAA123'
find(:css, "#variable_protected").set(true)
click_on 'Add new variable'
end
scenario 'user sees the created variable' do
page.within('.variables-table') do
expect(find(".variable-key")).to have_content('AAA')
expect(find(".variable-value")).to have_content('******')
expect(find(".variable-protected")).to have_content('Yes')
end
click_on 'Reveal Values'
page.within('.variables-table') do
expect(find(".variable-value")).to have_content('AAA123')
end
end
end
context 'when user edits a variable' do
background do
create(:ci_group_variable, key: 'AAA', value: 'AAA123', protected: true,
group: group)
visit group_settings_ci_cd_path(group)
page.within('.variable-menu') do
click_on 'Update'
end
fill_in 'variable_key', with: 'BBB'
fill_in 'variable_value', with: 'BBB123'
find(:css, "#variable_protected").set(false)
click_on 'Save variable'
end
scenario 'user sees the updated variable' do
page.within('.variables-table') do
expect(find(".variable-key")).to have_content('BBB')
expect(find(".variable-value")).to have_content('******')
expect(find(".variable-protected")).to have_content('No')
end
end
end
context 'when user deletes a variable' do
background do
create(:ci_group_variable, key: 'BBB', value: 'BBB123', protected: false,
group: group)
visit group_settings_ci_cd_path(group)
page.within('.variable-menu') do
page.accept_alert 'Are you sure?' do
click_on 'Remove'
end
end
end
scenario 'user does not see the deleted variable' do
expect(page).to have_no_css('.variables-table')
end
end
end
...@@ -24,7 +24,7 @@ describe 'Project variables', js: true do ...@@ -24,7 +24,7 @@ describe 'Project variables', js: true do
fill_in('variable_value', with: 'key value') fill_in('variable_value', with: 'key value')
click_button('Add new variable') click_button('Add new variable')
expect(page).to have_content('Variables were successfully updated.') expect(page).to have_content('Variable was successfully created.')
page.within('.variables-table') do page.within('.variables-table') do
expect(page).to have_content('key') expect(page).to have_content('key')
expect(page).to have_content('No') expect(page).to have_content('No')
...@@ -36,7 +36,7 @@ describe 'Project variables', js: true do ...@@ -36,7 +36,7 @@ describe 'Project variables', js: true do
fill_in('variable_value', with: '') fill_in('variable_value', with: '')
click_button('Add new variable') click_button('Add new variable')
expect(page).to have_content('Variables were successfully updated.') expect(page).to have_content('Variable was successfully created.')
page.within('.variables-table') do page.within('.variables-table') do
expect(page).to have_content('new_key') expect(page).to have_content('new_key')
end end
...@@ -48,7 +48,7 @@ describe 'Project variables', js: true do ...@@ -48,7 +48,7 @@ describe 'Project variables', js: true do
check('Protected') check('Protected')
click_button('Add new variable') click_button('Add new variable')
expect(page).to have_content('Variables were successfully updated.') expect(page).to have_content('Variable was successfully created.')
page.within('.variables-table') do page.within('.variables-table') do
expect(page).to have_content('key') expect(page).to have_content('key')
expect(page).to have_content('Yes') expect(page).to have_content('Yes')
...@@ -82,7 +82,7 @@ describe 'Project variables', js: true do ...@@ -82,7 +82,7 @@ describe 'Project variables', js: true do
it 'deletes variable' do it 'deletes variable' do
page.within('.variables-table') do page.within('.variables-table') do
find('.btn-variable-delete').click click_on 'Remove'
end end
expect(page).not_to have_selector('variables-table') expect(page).not_to have_selector('variables-table')
...@@ -90,7 +90,7 @@ describe 'Project variables', js: true do ...@@ -90,7 +90,7 @@ describe 'Project variables', js: true do
it 'edits variable' do it 'edits variable' do
page.within('.variables-table') do page.within('.variables-table') do
find('.btn-variable-edit').click click_on 'Update'
end end
expect(page).to have_content('Update variable') expect(page).to have_content('Update variable')
...@@ -104,7 +104,7 @@ describe 'Project variables', js: true do ...@@ -104,7 +104,7 @@ describe 'Project variables', js: true do
it 'edits variable with empty value' do it 'edits variable with empty value' do
page.within('.variables-table') do page.within('.variables-table') do
find('.btn-variable-edit').click click_on 'Update'
end end
expect(page).to have_content('Update variable') expect(page).to have_content('Update variable')
...@@ -117,7 +117,7 @@ describe 'Project variables', js: true do ...@@ -117,7 +117,7 @@ describe 'Project variables', js: true do
it 'edits variable to be protected' do it 'edits variable to be protected' do
page.within('.variables-table') do page.within('.variables-table') do
find('.btn-variable-edit').click click_on 'Update'
end end
expect(page).to have_content('Update variable') expect(page).to have_content('Update variable')
...@@ -132,7 +132,7 @@ describe 'Project variables', js: true do ...@@ -132,7 +132,7 @@ describe 'Project variables', js: true do
project.variables.first.update(protected: true) project.variables.first.update(protected: true)
page.within('.variables-table') do page.within('.variables-table') do
find('.btn-variable-edit').click click_on 'Update'
end end
expect(page).to have_content('Update variable') expect(page).to have_content('Update variable')
......
require 'spec_helper'
describe BlobViewer::Readme, model: true do
include FakeBlobHelpers
let(:project) { create(:project, :repository) }
let(:blob) { fake_blob(path: 'README.md') }
subject { described_class.new(blob) }
describe '#render_error' do
context 'when there is no wiki' do
it 'returns :no_wiki' do
expect(subject.render_error).to eq(:no_wiki)
end
end
context 'when there is an external wiki' do
before do
project.has_external_wiki = true
end
it 'returns nil' do
expect(subject.render_error).to be_nil
end
end
context 'when there is a local wiki' do
before do
project.wiki_enabled = true
end
context 'when the wiki is empty' do
it 'returns :no_wiki' do
expect(subject.render_error).to eq(:no_wiki)
end
end
context 'when the wiki is not empty' do
before do
WikiPages::CreateService.new(project, project.owner, title: 'home', content: 'Home page').execute
end
it 'returns nil' do
expect(subject.render_error).to be_nil
end
end
end
end
end
...@@ -1356,6 +1356,59 @@ describe Ci::Build, :models do ...@@ -1356,6 +1356,59 @@ describe Ci::Build, :models do
end end
end end
context 'when group secret variable is defined' do
let(:secret_variable) do
{ key: 'SECRET_KEY', value: 'secret_value', public: false }
end
let(:group) { create(:group, :access_requestable) }
before do
build.project.update(group: group)
create(:ci_group_variable,
secret_variable.slice(:key, :value).merge(group: group))
end
it { is_expected.to include(secret_variable) }
end
context 'when group protected variable is defined' do
let(:protected_variable) do
{ key: 'PROTECTED_KEY', value: 'protected_value', public: false }
end
let(:group) { create(:group, :access_requestable) }
before do
build.project.update(group: group)
create(:ci_group_variable,
:protected,
protected_variable.slice(:key, :value).merge(group: group))
end
context 'when the branch is protected' do
before do
create(:protected_branch, project: build.project, name: build.ref)
end
it { is_expected.to include(protected_variable) }
end
context 'when the tag is protected' do
before do
create(:protected_tag, project: build.project, name: build.ref)
end
it { is_expected.to include(protected_variable) }
end
context 'when the ref is not protected' do
it { is_expected.not_to include(protected_variable) }
end
end
context 'when build is for triggers' do context 'when build is for triggers' do
let(:trigger) { create(:ci_trigger, project: project) } let(:trigger) { create(:ci_trigger, project: project) }
let(:trigger_request) { create(:ci_trigger_request_with_variables, pipeline: pipeline, trigger: trigger) } let(:trigger_request) { create(:ci_trigger_request_with_variables, pipeline: pipeline, trigger: trigger) }
......
require 'spec_helper'
describe Ci::GroupVariable, models: true do
subject { build(:ci_group_variable) }
it { is_expected.to include_module(HasVariable) }
it { is_expected.to include_module(Presentable) }
it { is_expected.to validate_uniqueness_of(:key).scoped_to(:group_id) }
describe '.unprotected' do
subject { described_class.unprotected }
context 'when variable is protected' do
before do
create(:ci_group_variable, :protected)
end
it 'returns nothing' do
is_expected.to be_empty
end
end
context 'when variable is not protected' do
let(:variable) { create(:ci_group_variable, protected: false) }
it 'returns the variable' do
is_expected.to contain_exactly(variable)
end
end
end
end
...@@ -3,10 +3,9 @@ require 'spec_helper' ...@@ -3,10 +3,9 @@ require 'spec_helper'
describe Ci::Variable, models: true do describe Ci::Variable, models: true do
subject { build(:ci_variable) } subject { build(:ci_variable) }
let(:secret_value) { 'secret' }
describe 'validations' do describe 'validations' do
it { is_expected.to include_module(HasVariable) } it { is_expected.to include_module(HasVariable) }
it { is_expected.to include_module(Presentable) }
it { is_expected.to validate_uniqueness_of(:key).scoped_to(:project_id, :environment_scope) } it { is_expected.to validate_uniqueness_of(:key).scoped_to(:project_id, :environment_scope) }
end end
......
...@@ -13,6 +13,11 @@ describe ShaAttribute do ...@@ -13,6 +13,11 @@ describe ShaAttribute do
end end
describe '#sha_attribute' do describe '#sha_attribute' do
context' when the table exists' do
before do
allow(model).to receive(:table_exists?).and_return(true)
end
it 'defines a SHA attribute for a binary column' do it 'defines a SHA attribute for a binary column' do
expect(model).to receive(:attribute) expect(model).to receive(:attribute)
.with(:sha1, an_instance_of(Gitlab::Database::ShaAttribute)) .with(:sha1, an_instance_of(Gitlab::Database::ShaAttribute))
...@@ -24,4 +29,18 @@ describe ShaAttribute do ...@@ -24,4 +29,18 @@ describe ShaAttribute do
expect { model.sha_attribute(:name) }.to raise_error(ArgumentError) expect { model.sha_attribute(:name) }.to raise_error(ArgumentError)
end end
end end
context' when the table does not exist' do
before do
allow(model).to receive(:table_exists?).and_return(false)
end
it 'does nothing' do
expect(model).not_to receive(:columns)
expect(model).not_to receive(:attribute)
model.sha_attribute(:name)
end
end
end
end end
...@@ -13,6 +13,7 @@ describe Group, models: true do ...@@ -13,6 +13,7 @@ describe Group, models: true do
it { is_expected.to have_many(:shared_projects).through(:project_group_links) } it { is_expected.to have_many(:shared_projects).through(:project_group_links) }
it { is_expected.to have_many(:notification_settings).dependent(:destroy) } it { is_expected.to have_many(:notification_settings).dependent(:destroy) }
it { is_expected.to have_many(:labels).class_name('GroupLabel') } it { is_expected.to have_many(:labels).class_name('GroupLabel') }
it { is_expected.to have_many(:variables).class_name('Ci::GroupVariable') }
it { is_expected.to have_many(:uploads).dependent(:destroy) } it { is_expected.to have_many(:uploads).dependent(:destroy) }
it { is_expected.to have_one(:chat_team) } it { is_expected.to have_one(:chat_team) }
...@@ -418,4 +419,69 @@ describe Group, models: true do ...@@ -418,4 +419,69 @@ describe Group, models: true do
expect(calls).to eq 2 expect(calls).to eq 2
end end
end end
describe '#secret_variables_for' do
let(:project) { create(:empty_project, group: group) }
let!(:secret_variable) do
create(:ci_group_variable, value: 'secret', group: group)
end
let!(:protected_variable) do
create(:ci_group_variable, :protected, value: 'protected', group: group)
end
subject { group.secret_variables_for('ref', project) }
shared_examples 'ref is protected' do
it 'contains all the variables' do
is_expected.to contain_exactly(secret_variable, protected_variable)
end
end
context 'when the ref is not protected' do
before do
stub_application_setting(
default_branch_protection: Gitlab::Access::PROTECTION_NONE)
end
it 'contains only the secret variables' do
is_expected.to contain_exactly(secret_variable)
end
end
context 'when the ref is a protected branch' do
before do
create(:protected_branch, name: 'ref', project: project)
end
it_behaves_like 'ref is protected'
end
context 'when the ref is a protected tag' do
before do
create(:protected_tag, name: 'ref', project: project)
end
it_behaves_like 'ref is protected'
end
context 'when group has children' do
let!(:group_child) { create(:group, parent: group) }
let!(:variable_child) { create(:ci_group_variable, group: group_child) }
let!(:group_child_3) { create(:group, parent: group_child_2) }
let!(:variable_child_3) { create(:ci_group_variable, group: group_child_3) }
let!(:group_child_2) { create(:group, parent: group_child) }
let!(:variable_child_2) { create(:ci_group_variable, group: group_child_2) }
it 'returns all variables belong to the group and parent groups' do
expected_array1 = [protected_variable, secret_variable]
expected_array2 = [variable_child, variable_child_2, variable_child_3]
got_array = group_child_3.secret_variables_for('ref', project).to_a
expect(got_array.shift(2)).to contain_exactly(*expected_array1)
expect(got_array).to eq(expected_array2)
end
end
end
end end
require 'spec_helper'
describe Ci::GroupVariablePresenter do
include Gitlab::Routing.url_helpers
let(:group) { create(:group) }
let(:variable) { create(:ci_group_variable, group: group) }
subject(:presenter) do
described_class.new(variable)
end
it 'inherits from Gitlab::View::Presenter::Delegated' do
expect(described_class.superclass).to eq(Gitlab::View::Presenter::Delegated)
end
describe '#initialize' do
it 'takes a variable and optional params' do
expect { presenter }.not_to raise_error
end
it 'exposes variable' do
expect(presenter.variable).to eq(variable)
end
it 'forwards missing methods to variable' do
expect(presenter.key).to eq(variable.key)
end
end
describe '#placeholder' do
subject { described_class.new(variable).placeholder }
it { is_expected.to eq('GROUP_VARIABLE') }
end
describe '#form_path' do
context 'when variable is persisted' do
subject { described_class.new(variable).form_path }
it { is_expected.to eq(group_variable_path(group, variable)) }
end
context 'when variable is not persisted' do
let(:variable) { build(:ci_group_variable, group: group) }
subject { described_class.new(variable).form_path }
it { is_expected.to eq(group_variables_path(group)) }
end
end
describe '#edit_path' do
subject { described_class.new(variable).edit_path }
it { is_expected.to eq(group_variable_path(group, variable)) }
end
describe '#delete_path' do
subject { described_class.new(variable).delete_path }
it { is_expected.to eq(group_variable_path(group, variable)) }
end
end
require 'spec_helper'
describe Ci::VariablePresenter do
include Gitlab::Routing.url_helpers
let(:project) { create(:empty_project) }
let(:variable) { create(:ci_variable, project: project) }
subject(:presenter) do
described_class.new(variable)
end
it 'inherits from Gitlab::View::Presenter::Delegated' do
expect(described_class.superclass).to eq(Gitlab::View::Presenter::Delegated)
end
describe '#initialize' do
it 'takes a variable and optional params' do
expect { presenter }.not_to raise_error
end
it 'exposes variable' do
expect(presenter.variable).to eq(variable)
end
it 'forwards missing methods to variable' do
expect(presenter.key).to eq(variable.key)
end
end
describe '#placeholder' do
subject { described_class.new(variable).placeholder }
it { is_expected.to eq('PROJECT_VARIABLE') }
end
describe '#form_path' do
context 'when variable is persisted' do
subject { described_class.new(variable).form_path }
it { is_expected.to eq(project_variable_path(project, variable)) }
end
context 'when variable is not persisted' do
let(:variable) { build(:ci_variable, project: project) }
subject { described_class.new(variable).form_path }
it { is_expected.to eq(project_variables_path(project)) }
end
end
describe '#edit_path' do
subject { described_class.new(variable).edit_path }
it { is_expected.to eq(project_variable_path(project, variable)) }
end
describe '#delete_path' do
subject { described_class.new(variable).delete_path }
it { is_expected.to eq(project_variable_path(project, variable)) }
end
end
if Gitlab::GitalyClient.enabled? RSpec.configure do |config|
RSpec.configure do |config|
config.before(:each) do |example| config.before(:each) do |example|
next if example.metadata[:skip_gitaly_mock] next if example.metadata[:skip_gitaly_mock]
allow(Gitlab::GitalyClient).to receive(:feature_enabled?).and_return(true) allow(Gitlab::GitalyClient).to receive(:feature_enabled?).and_return(true)
end end
end
end end
...@@ -69,7 +69,7 @@ module TestEnv ...@@ -69,7 +69,7 @@ module TestEnv
# Setup GitLab shell for test instance # Setup GitLab shell for test instance
setup_gitlab_shell setup_gitlab_shell
setup_gitaly if Gitlab::GitalyClient.enabled? setup_gitaly
# Create repository for FactoryGirl.create(:project) # Create repository for FactoryGirl.create(:project)
setup_factory_repo setup_factory_repo
......
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