Commit f5641dcf authored by Grzegorz Bizon's avatar Grzegorz Bizon

Merge branch 'master' into 'fix/gb/improve-stage-id-foreign-key-migration'

# Conflicts:
#   db/schema.rb
parents 5af3eb5f 75ac425c
...@@ -2,6 +2,10 @@ ...@@ -2,6 +2,10 @@
documentation](doc/development/changelog.md) for instructions on adding your own documentation](doc/development/changelog.md) for instructions on adding your own
entry. entry.
## 9.3.4 (2017-07-03)
- No changes.
## 9.3.3 (2017-06-30) ## 9.3.3 (2017-06-30)
- Fix head pipeline stored in merge request for external pipelines. !12478 - Fix head pipeline stored in merge request for external pipelines. !12478
......
import autosize from 'vendor/autosize'; import autosize from 'vendor/autosize';
$(() => { document.addEventListener('DOMContentLoaded', () => {
const $fields = $('.js-autosize'); const autosizeEls = document.querySelectorAll('.js-autosize');
$fields.on('autosize:resized', function resized() { autosize(autosizeEls);
const $field = $(this); autosize.update(autosizeEls);
$field.data('height', $field.outerHeight());
});
$fields.on('resize.autosize', function resize() {
const $field = $(this);
if ($field.data('height') !== $field.outerHeight()) {
$field.data('height', $field.outerHeight());
autosize.destroy($field);
$field.css('max-height', window.outerHeight);
}
});
autosize($fields);
autosize.update($fields);
$fields.css('resize', 'vertical');
}); });
...@@ -104,7 +104,7 @@ ...@@ -104,7 +104,7 @@
} }
this.data = query.result[0].values; this.data = query.result[0].values;
this.unitOfDisplay = query.unit || 'N/A'; this.unitOfDisplay = query.unit || 'N/A';
this.yAxisLabel = this.columnData.y_axis || 'Values'; this.yAxisLabel = this.columnData.y_label || 'Values';
this.legendTitle = query.legend || 'Average'; this.legendTitle = query.legend || 'Average';
this.graphWidth = this.$refs.baseSvg.clientWidth - this.graphWidth = this.$refs.baseSvg.clientWidth -
this.margin.left - this.margin.right; this.margin.left - this.margin.right;
......
...@@ -83,7 +83,12 @@ class LabelsFinder < UnionFinder ...@@ -83,7 +83,12 @@ class LabelsFinder < UnionFinder
def projects def projects
return @projects if defined?(@projects) return @projects if defined?(@projects)
@projects = skip_authorization ? Project.all : ProjectsFinder.new(current_user: current_user).execute @projects = if skip_authorization
Project.all
else
ProjectsFinder.new(params: { non_archived: true }, current_user: current_user).execute
end
@projects = @projects.in_namespace(params[:group_id]) if group? @projects = @projects.in_namespace(params[:group_id]) if group?
@projects = @projects.where(id: params[:project_ids]) if projects? @projects = @projects.where(id: params[:project_ids]) if projects?
@projects = @projects.reorder(nil) @projects = @projects.reorder(nil)
......
...@@ -5,7 +5,7 @@ module Ci ...@@ -5,7 +5,7 @@ module Ci
belongs_to :project belongs_to :project
validates :key, uniqueness: { scope: :project_id } validates :key, uniqueness: { scope: [:project_id, :environment_scope] }
scope :unprotected, -> { where(protected: false) } scope :unprotected, -> { where(protected: false) }
end end
......
...@@ -1074,21 +1074,21 @@ class Project < ActiveRecord::Base ...@@ -1074,21 +1074,21 @@ class Project < ActiveRecord::Base
merge_requests.where(source_project_id: self.id) merge_requests.where(source_project_id: self.id)
end end
def create_repository def create_repository(force: false)
# Forked import is handled asynchronously # Forked import is handled asynchronously
unless forked? return if forked? && !force
if gitlab_shell.add_repository(repository_storage_path, path_with_namespace)
repository.after_create if gitlab_shell.add_repository(repository_storage_path, path_with_namespace)
true repository.after_create
else true
errors.add(:base, 'Failed to create repository via gitlab-shell') else
false errors.add(:base, 'Failed to create repository via gitlab-shell')
end false
end end
end end
def ensure_repository def ensure_repository
create_repository unless repository_exists? create_repository(force: true) unless repository_exists?
end end
def repository_exists? def repository_exists?
......
...@@ -11,8 +11,7 @@ ...@@ -11,8 +11,7 @@
.col-sm-10.col-sm-offset-2 .col-sm-10.col-sm-offset-2
- if issuable.can_remove_source_branch?(current_user) - if issuable.can_remove_source_branch?(current_user)
.checkbox .checkbox
- initial_checkbox_value = issuable.merge_params.key?('force_remove_source_branch') ? issuable.force_remove_source_branch? : true
= label_tag 'merge_request[force_remove_source_branch]' do = label_tag 'merge_request[force_remove_source_branch]' do
= hidden_field_tag 'merge_request[force_remove_source_branch]', '0', id: nil = hidden_field_tag 'merge_request[force_remove_source_branch]', '0', id: nil
= check_box_tag 'merge_request[force_remove_source_branch]', '1', initial_checkbox_value = check_box_tag 'merge_request[force_remove_source_branch]', '1', issuable.force_remove_source_branch?
Remove source branch when merge request is accepted. Remove source branch when merge request is accepted.
---
title: Set default for Remove source branch to false.
merge_request: !12576
author:
---
title: Rename duplicated variables with the same key for projects. Add environment_scope
column to variables and add unique constraint to make sure that no variables could
be created with the same key within a project
merge_request: 12363
author:
---
title: Hide archived project labels from group issue tracker
merge_request: 12547
author: Horacio Bertorello
---
title: Fixed the y_label not setting correctly for each graph on the monitoring dashboard
merge_request:
author:
---
title: Make Project#ensure_repository force create a repo
merge_request:
author:
---
title: Optimize creation of commit API by using Repository#commit instead of Repository#commits
merge_request:
author:
class RenameDuplicatedVariableKey < ActiveRecord::Migration
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
disable_ddl_transaction!
def up
execute(<<~SQL)
UPDATE ci_variables
SET #{key} = CONCAT(#{key}, #{underscore}, id)
WHERE id IN (
SELECT *
FROM ( -- MySQL requires an extra layer
SELECT dup.id
FROM ci_variables dup
INNER JOIN (SELECT max(id) AS id, #{key}, project_id
FROM ci_variables tmp
GROUP BY #{key}, project_id) var
USING (#{key}, project_id) where dup.id <> var.id
) dummy
)
SQL
end
def down
# noop
end
def key
# key needs to be quoted in MySQL
quote_column_name('key')
end
def underscore
quote('_')
end
end
class AddEnvironmentScopeToCiVariables < ActiveRecord::Migration
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
disable_ddl_transaction!
def up
add_column_with_default(:ci_variables, :environment_scope, :string, default: '*')
end
def down
remove_column(:ci_variables, :environment_scope)
end
end
class AddUniqueConstraintToCiVariables < ActiveRecord::Migration
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
disable_ddl_transaction!
def up
unless this_index_exists?
add_concurrent_index(:ci_variables, columns, name: index_name, unique: true)
end
end
def down
if this_index_exists?
if Gitlab::Database.mysql? && !index_exists?(:ci_variables, :project_id)
# Need to add this index for MySQL project_id foreign key constraint
add_concurrent_index(:ci_variables, :project_id)
end
remove_concurrent_index(:ci_variables, columns, name: index_name)
end
end
private
def this_index_exists?
index_exists?(:ci_variables, columns, name: index_name)
end
def columns
@columns ||= [:project_id, :key, :environment_scope]
end
def index_name
'index_ci_variables_on_project_id_and_key_and_environment_scope'
end
end
class RemoveCiVariablesProjectIdIndex < ActiveRecord::Migration
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
disable_ddl_transaction!
def up
if index_exists?(:ci_variables, :project_id)
remove_concurrent_index(:ci_variables, :project_id)
end
end
def down
unless index_exists?(:ci_variables, :project_id)
add_concurrent_index(:ci_variables, :project_id)
end
end
end
...@@ -374,9 +374,10 @@ ActiveRecord::Schema.define(version: 20170703102400) do ...@@ -374,9 +374,10 @@ ActiveRecord::Schema.define(version: 20170703102400) do
t.string "encrypted_value_iv" t.string "encrypted_value_iv"
t.integer "project_id", null: false t.integer "project_id", null: false
t.boolean "protected", default: false, null: false t.boolean "protected", default: false, null: false
t.string "environment_scope", default: "*", null: false
end end
add_index "ci_variables", ["project_id"], name: "index_ci_variables_on_project_id", using: :btree add_index "ci_variables", ["project_id", "key", "environment_scope"], name: "index_ci_variables_on_project_id_and_key_and_environment_scope", unique: true, using: :btree
create_table "container_repositories", force: :cascade do |t| create_table "container_repositories", force: :cascade do |t|
t.integer "project_id", null: false t.integer "project_id", null: false
......
...@@ -67,7 +67,7 @@ module API ...@@ -67,7 +67,7 @@ module API
result = ::Files::MultiService.new(user_project, current_user, attrs).execute result = ::Files::MultiService.new(user_project, current_user, attrs).execute
if result[:status] == :success if result[:status] == :success
commit_detail = user_project.repository.commits(result[:result], limit: 1).first commit_detail = user_project.repository.commit(result[:result])
present commit_detail, with: Entities::RepoCommitDetail present commit_detail, with: Entities::RepoCommitDetail
else else
render_api_error!(result[:message], 400) render_api_error!(result[:message], 400)
......
...@@ -2,6 +2,8 @@ require 'securerandom' ...@@ -2,6 +2,8 @@ require 'securerandom'
module Gitlab module Gitlab
class Shell class Shell
GITLAB_SHELL_ENV_VARS = %w(GIT_TERMINAL_PROMPT).freeze
Error = Class.new(StandardError) Error = Class.new(StandardError)
KeyAdder = Struct.new(:io) do KeyAdder = Struct.new(:io) do
...@@ -67,8 +69,8 @@ module Gitlab ...@@ -67,8 +69,8 @@ module Gitlab
# add_repository("/path/to/storage", "gitlab/gitlab-ci") # add_repository("/path/to/storage", "gitlab/gitlab-ci")
# #
def add_repository(storage, name) def add_repository(storage, name)
Gitlab::Utils.system_silent([gitlab_shell_projects_path, gitlab_shell_fast_execute([gitlab_shell_projects_path,
'add-project', storage, "#{name}.git"]) 'add-project', storage, "#{name}.git"])
end end
# Import repository # Import repository
...@@ -82,10 +84,9 @@ module Gitlab ...@@ -82,10 +84,9 @@ module Gitlab
def import_repository(storage, name, url) def import_repository(storage, name, url)
# Timeout should be less than 900 ideally, to prevent the memory killer # Timeout should be less than 900 ideally, to prevent the memory killer
# to silently kill the process without knowing we are timing out here. # to silently kill the process without knowing we are timing out here.
output, status = Popen.popen([gitlab_shell_projects_path, 'import-project', cmd = [gitlab_shell_projects_path, 'import-project',
storage, "#{name}.git", url, "#{Gitlab.config.gitlab_shell.git_timeout}"]) storage, "#{name}.git", url, "#{Gitlab.config.gitlab_shell.git_timeout}"]
raise Error, output unless status.zero? gitlab_shell_fast_execute_raise_error(cmd)
true
end end
# Fetch remote for repository # Fetch remote for repository
...@@ -103,9 +104,7 @@ module Gitlab ...@@ -103,9 +104,7 @@ module Gitlab
args << '--force' if forced args << '--force' if forced
args << '--no-tags' if no_tags args << '--no-tags' if no_tags
output, status = Popen.popen(args) gitlab_shell_fast_execute_raise_error(args)
raise Error, output unless status.zero?
true
end end
# Move repository # Move repository
...@@ -117,8 +116,8 @@ module Gitlab ...@@ -117,8 +116,8 @@ module Gitlab
# mv_repository("/path/to/storage", "gitlab/gitlab-ci", "randx/gitlab-ci-new") # mv_repository("/path/to/storage", "gitlab/gitlab-ci", "randx/gitlab-ci-new")
# #
def mv_repository(storage, path, new_path) def mv_repository(storage, path, new_path)
Gitlab::Utils.system_silent([gitlab_shell_projects_path, 'mv-project', gitlab_shell_fast_execute([gitlab_shell_projects_path, 'mv-project',
storage, "#{path}.git", "#{new_path}.git"]) storage, "#{path}.git", "#{new_path}.git"])
end end
# Fork repository to new namespace # Fork repository to new namespace
...@@ -131,9 +130,9 @@ module Gitlab ...@@ -131,9 +130,9 @@ module Gitlab
# fork_repository("/path/to/forked_from/storage", "gitlab/gitlab-ci", "/path/to/forked_to/storage", "randx") # fork_repository("/path/to/forked_from/storage", "gitlab/gitlab-ci", "/path/to/forked_to/storage", "randx")
# #
def fork_repository(forked_from_storage, path, forked_to_storage, fork_namespace) def fork_repository(forked_from_storage, path, forked_to_storage, fork_namespace)
Gitlab::Utils.system_silent([gitlab_shell_projects_path, 'fork-project', gitlab_shell_fast_execute([gitlab_shell_projects_path, 'fork-project',
forked_from_storage, "#{path}.git", forked_to_storage, forked_from_storage, "#{path}.git", forked_to_storage,
fork_namespace]) fork_namespace])
end end
# Remove repository from file system # Remove repository from file system
...@@ -145,8 +144,8 @@ module Gitlab ...@@ -145,8 +144,8 @@ module Gitlab
# remove_repository("/path/to/storage", "gitlab/gitlab-ci") # remove_repository("/path/to/storage", "gitlab/gitlab-ci")
# #
def remove_repository(storage, name) def remove_repository(storage, name)
Gitlab::Utils.system_silent([gitlab_shell_projects_path, gitlab_shell_fast_execute([gitlab_shell_projects_path,
'rm-project', storage, "#{name}.git"]) 'rm-project', storage, "#{name}.git"])
end end
# Add new key to gitlab-shell # Add new key to gitlab-shell
...@@ -155,8 +154,8 @@ module Gitlab ...@@ -155,8 +154,8 @@ module Gitlab
# add_key("key-42", "sha-rsa ...") # add_key("key-42", "sha-rsa ...")
# #
def add_key(key_id, key_content) def add_key(key_id, key_content)
Gitlab::Utils.system_silent([gitlab_shell_keys_path, gitlab_shell_fast_execute([gitlab_shell_keys_path,
'add-key', key_id, self.class.strip_key(key_content)]) 'add-key', key_id, self.class.strip_key(key_content)])
end end
# Batch-add keys to authorized_keys # Batch-add keys to authorized_keys
...@@ -175,8 +174,10 @@ module Gitlab ...@@ -175,8 +174,10 @@ module Gitlab
# remove_key("key-342", "sha-rsa ...") # remove_key("key-342", "sha-rsa ...")
# #
def remove_key(key_id, key_content) def remove_key(key_id, key_content)
Gitlab::Utils.system_silent([gitlab_shell_keys_path, args = [gitlab_shell_keys_path, 'rm-key', key_id]
'rm-key', key_id, key_content]) args << key_content if key_content
gitlab_shell_fast_execute(args)
end end
# Remove all ssh keys from gitlab shell # Remove all ssh keys from gitlab shell
...@@ -185,7 +186,7 @@ module Gitlab ...@@ -185,7 +186,7 @@ module Gitlab
# remove_all_keys # remove_all_keys
# #
def remove_all_keys def remove_all_keys
Gitlab::Utils.system_silent([gitlab_shell_keys_path, 'clear']) gitlab_shell_fast_execute([gitlab_shell_keys_path, 'clear'])
end end
# Add empty directory for storing repositories # Add empty directory for storing repositories
...@@ -267,5 +268,31 @@ module Gitlab ...@@ -267,5 +268,31 @@ module Gitlab
def gitlab_shell_keys_path def gitlab_shell_keys_path
File.join(gitlab_shell_path, 'bin', 'gitlab-keys') File.join(gitlab_shell_path, 'bin', 'gitlab-keys')
end end
private
def gitlab_shell_fast_execute(cmd)
output, status = gitlab_shell_fast_execute_helper(cmd)
return true if status.zero?
Rails.logger.error("gitlab-shell failed with error #{status}: #{output}")
false
end
def gitlab_shell_fast_execute_raise_error(cmd)
output, status = gitlab_shell_fast_execute_helper(cmd)
raise Error, output unless status.zero?
true
end
def gitlab_shell_fast_execute_helper(cmd)
vars = ENV.to_h.slice(*GITLAB_SHELL_ENV_VARS)
# Don't pass along the entire parent environment to prevent gitlab-shell
# from wasting I/O by searching through GEM_PATH
Bundler.with_original_env { Popen.popen(cmd, nil, vars) }
end
end end
end end
...@@ -49,12 +49,12 @@ describe LabelsFinder do ...@@ -49,12 +49,12 @@ describe LabelsFinder do
end end
context 'filtering by group_id' do context 'filtering by group_id' do
it 'returns labels available for any project within the group' do it 'returns labels available for any non-archived project within the group' do
group_1.add_developer(user) group_1.add_developer(user)
project_1.archive!
finder = described_class.new(user, group_id: group_1.id) finder = described_class.new(user, group_id: group_1.id)
expect(finder.execute).to eq [group_label_2, project_label_1, group_label_1, project_label_5] expect(finder.execute).to eq [group_label_2, group_label_1, project_label_5]
end end
end end
......
...@@ -13,7 +13,7 @@ const metricsGroupsAPIResponse = { ...@@ -13,7 +13,7 @@ const metricsGroupsAPIResponse = {
'queries': [ 'queries': [
{ {
'query_range': 'avg(container_memory_usage_bytes{%{environment_filter}}) / 2^20', 'query_range': 'avg(container_memory_usage_bytes{%{environment_filter}}) / 2^20',
'label': 'Container memory', 'y_label': 'Memory',
'unit': 'MiB', 'unit': 'MiB',
'result': [ 'result': [
{ {
...@@ -2477,7 +2477,7 @@ export const singleRowMetrics = [ ...@@ -2477,7 +2477,7 @@ export const singleRowMetrics = [
{ {
'title': 'CPU usage', 'title': 'CPU usage',
'weight': 1, 'weight': 1,
'y_label': 'Values', 'y_label': 'Memory',
'queries': [ 'queries': [
{ {
'query_range': 'avg(rate(container_cpu_usage_seconds_total{%{environment_filter}}[2m])) * 100', 'query_range': 'avg(rate(container_cpu_usage_seconds_total{%{environment_filter}}[2m])) * 100',
......
...@@ -94,4 +94,15 @@ describe('MonitoringColumn', () => { ...@@ -94,4 +94,15 @@ describe('MonitoringColumn', () => {
done(); done();
}); });
}); });
it('has a title for the y-axis that comes from the backend', () => {
const component = createComponent({
columnData: singleRowMetrics[0],
classType: 'col-md-6',
updateAspectRatio: false,
deploymentData,
});
expect(component.yAxisLabel).toEqual(component.columnData.y_label);
});
}); });
...@@ -32,6 +32,17 @@ describe 'Gitlab::Popen', lib: true, no_db: true do ...@@ -32,6 +32,17 @@ describe 'Gitlab::Popen', lib: true, no_db: true do
end end
end end
context 'with custom options' do
let(:vars) { { 'foobar' => 123, 'PWD' => path } }
let(:options) { { chdir: path } }
it 'calls popen3 with the provided environment variables' do
expect(Open3).to receive(:popen3).with(vars, 'ls', options)
@output, @status = @klass.new.popen(%w(ls), path, { 'foobar' => 123 })
end
end
context 'without a directory argument' do context 'without a directory argument' do
before do before do
@output, @status = @klass.new.popen(%w(ls)) @output, @status = @klass.new.popen(%w(ls))
...@@ -45,7 +56,7 @@ describe 'Gitlab::Popen', lib: true, no_db: true do ...@@ -45,7 +56,7 @@ describe 'Gitlab::Popen', lib: true, no_db: true do
before do before do
@output, @status = @klass.new.popen(%w[cat]) { |stdin| stdin.write 'hello' } @output, @status = @klass.new.popen(%w[cat]) { |stdin| stdin.write 'hello' }
end end
it { expect(@status).to be_zero } it { expect(@status).to be_zero }
it { expect(@output).to eq('hello') } it { expect(@output).to eq('hello') }
end end
......
...@@ -4,6 +4,7 @@ require 'stringio' ...@@ -4,6 +4,7 @@ require 'stringio'
describe Gitlab::Shell, lib: true do describe Gitlab::Shell, lib: true do
let(:project) { double('Project', id: 7, path: 'diaspora') } let(:project) { double('Project', id: 7, path: 'diaspora') }
let(:gitlab_shell) { Gitlab::Shell.new } let(:gitlab_shell) { Gitlab::Shell.new }
let(:popen_vars) { { 'GIT_TERMINAL_PROMPT' => ENV['GIT_TERMINAL_PROMPT'] } }
before do before do
allow(Project).to receive(:find).and_return(project) allow(Project).to receive(:find).and_return(project)
...@@ -50,7 +51,7 @@ describe Gitlab::Shell, lib: true do ...@@ -50,7 +51,7 @@ describe Gitlab::Shell, lib: true do
describe '#add_key' do describe '#add_key' do
it 'removes trailing garbage' do it 'removes trailing garbage' do
allow(gitlab_shell).to receive(:gitlab_shell_keys_path).and_return(:gitlab_shell_keys_path) allow(gitlab_shell).to receive(:gitlab_shell_keys_path).and_return(:gitlab_shell_keys_path)
expect(Gitlab::Utils).to receive(:system_silent).with( expect(gitlab_shell).to receive(:gitlab_shell_fast_execute).with(
[:gitlab_shell_keys_path, 'add-key', 'key-123', 'ssh-rsa foobar'] [:gitlab_shell_keys_path, 'add-key', 'key-123', 'ssh-rsa foobar']
) )
...@@ -100,17 +101,91 @@ describe Gitlab::Shell, lib: true do ...@@ -100,17 +101,91 @@ describe Gitlab::Shell, lib: true do
allow(Gitlab.config.gitlab_shell).to receive(:git_timeout).and_return(800) allow(Gitlab.config.gitlab_shell).to receive(:git_timeout).and_return(800)
end end
describe '#add_repository' do
it 'returns true when the command succeeds' do
expect(Gitlab::Popen).to receive(:popen)
.with([projects_path, 'add-project', 'current/storage', 'project/path.git'],
nil, popen_vars).and_return([nil, 0])
expect(gitlab_shell.add_repository('current/storage', 'project/path')).to be true
end
it 'returns false when the command fails' do
expect(Gitlab::Popen).to receive(:popen)
.with([projects_path, 'add-project', 'current/storage', 'project/path.git'],
nil, popen_vars).and_return(["error", 1])
expect(gitlab_shell.add_repository('current/storage', 'project/path')).to be false
end
end
describe '#remove_repository' do
it 'returns true when the command succeeds' do
expect(Gitlab::Popen).to receive(:popen)
.with([projects_path, 'rm-project', 'current/storage', 'project/path.git'],
nil, popen_vars).and_return([nil, 0])
expect(gitlab_shell.remove_repository('current/storage', 'project/path')).to be true
end
it 'returns false when the command fails' do
expect(Gitlab::Popen).to receive(:popen)
.with([projects_path, 'rm-project', 'current/storage', 'project/path.git'],
nil, popen_vars).and_return(["error", 1])
expect(gitlab_shell.remove_repository('current/storage', 'project/path')).to be false
end
end
describe '#mv_repository' do
it 'returns true when the command succeeds' do
expect(Gitlab::Popen).to receive(:popen)
.with([projects_path, 'mv-project', 'current/storage', 'project/path.git', 'project/newpath.git'],
nil, popen_vars).and_return([nil, 0])
expect(gitlab_shell.mv_repository('current/storage', 'project/path', 'project/newpath')).to be true
end
it 'returns false when the command fails' do
expect(Gitlab::Popen).to receive(:popen)
.with([projects_path, 'mv-project', 'current/storage', 'project/path.git', 'project/newpath.git'],
nil, popen_vars).and_return(["error", 1])
expect(gitlab_shell.mv_repository('current/storage', 'project/path', 'project/newpath')).to be false
end
end
describe '#fork_repository' do
it 'returns true when the command succeeds' do
expect(Gitlab::Popen).to receive(:popen)
.with([projects_path, 'fork-project', 'current/storage', 'project/path.git', 'new/storage', 'new-namespace'],
nil, popen_vars).and_return([nil, 0])
expect(gitlab_shell.fork_repository('current/storage', 'project/path', 'new/storage', 'new-namespace')).to be true
end
it 'return false when the command fails' do
expect(Gitlab::Popen).to receive(:popen)
.with([projects_path, 'fork-project', 'current/storage', 'project/path.git', 'new/storage', 'new-namespace'],
nil, popen_vars).and_return(["error", 1])
expect(gitlab_shell.fork_repository('current/storage', 'project/path', 'new/storage', 'new-namespace')).to be false
end
end
describe '#fetch_remote' do describe '#fetch_remote' do
it 'returns true when the command succeeds' do it 'returns true when the command succeeds' do
expect(Gitlab::Popen).to receive(:popen) expect(Gitlab::Popen).to receive(:popen)
.with([projects_path, 'fetch-remote', 'current/storage', 'project/path.git', 'new/storage', '800']).and_return([nil, 0]) .with([projects_path, 'fetch-remote', 'current/storage', 'project/path.git', 'new/storage', '800'],
nil, popen_vars).and_return([nil, 0])
expect(gitlab_shell.fetch_remote('current/storage', 'project/path', 'new/storage')).to be true expect(gitlab_shell.fetch_remote('current/storage', 'project/path', 'new/storage')).to be true
end end
it 'raises an exception when the command fails' do it 'raises an exception when the command fails' do
expect(Gitlab::Popen).to receive(:popen) expect(Gitlab::Popen).to receive(:popen)
.with([projects_path, 'fetch-remote', 'current/storage', 'project/path.git', 'new/storage', '800']).and_return(["error", 1]) .with([projects_path, 'fetch-remote', 'current/storage', 'project/path.git', 'new/storage', '800'],
nil, popen_vars).and_return(["error", 1])
expect { gitlab_shell.fetch_remote('current/storage', 'project/path', 'new/storage') }.to raise_error(Gitlab::Shell::Error, "error") expect { gitlab_shell.fetch_remote('current/storage', 'project/path', 'new/storage') }.to raise_error(Gitlab::Shell::Error, "error")
end end
...@@ -119,14 +194,16 @@ describe Gitlab::Shell, lib: true do ...@@ -119,14 +194,16 @@ describe Gitlab::Shell, lib: true do
describe '#import_repository' do describe '#import_repository' do
it 'returns true when the command succeeds' do it 'returns true when the command succeeds' do
expect(Gitlab::Popen).to receive(:popen) expect(Gitlab::Popen).to receive(:popen)
.with([projects_path, 'import-project', 'current/storage', 'project/path.git', 'https://gitlab.com/gitlab-org/gitlab-ce.git', "800"]).and_return([nil, 0]) .with([projects_path, 'import-project', 'current/storage', 'project/path.git', 'https://gitlab.com/gitlab-org/gitlab-ce.git', "800"],
nil, popen_vars).and_return([nil, 0])
expect(gitlab_shell.import_repository('current/storage', 'project/path', 'https://gitlab.com/gitlab-org/gitlab-ce.git')).to be true expect(gitlab_shell.import_repository('current/storage', 'project/path', 'https://gitlab.com/gitlab-org/gitlab-ce.git')).to be true
end end
it 'raises an exception when the command fails' do it 'raises an exception when the command fails' do
expect(Gitlab::Popen).to receive(:popen) expect(Gitlab::Popen).to receive(:popen)
.with([projects_path, 'import-project', 'current/storage', 'project/path.git', 'https://gitlab.com/gitlab-org/gitlab-ce.git', "800"]).and_return(["error", 1]) .with([projects_path, 'import-project', 'current/storage', 'project/path.git', 'https://gitlab.com/gitlab-org/gitlab-ce.git', "800"],
nil, popen_vars).and_return(["error", 1])
expect { gitlab_shell.import_repository('current/storage', 'project/path', 'https://gitlab.com/gitlab-org/gitlab-ce.git') }.to raise_error(Gitlab::Shell::Error, "error") expect { gitlab_shell.import_repository('current/storage', 'project/path', 'https://gitlab.com/gitlab-org/gitlab-ce.git') }.to raise_error(Gitlab::Shell::Error, "error")
end end
......
require 'spec_helper'
require Rails.root.join('db', 'migrate', '20170622135451_rename_duplicated_variable_key.rb')
describe RenameDuplicatedVariableKey, :migration do
let(:variables) { table(:ci_variables) }
let(:projects) { table(:projects) }
before do
projects.create!(id: 1)
variables.create!(id: 1, key: 'key1', project_id: 1)
variables.create!(id: 2, key: 'key2', project_id: 1)
variables.create!(id: 3, key: 'keyX', project_id: 1)
variables.create!(id: 4, key: 'keyX', project_id: 1)
variables.create!(id: 5, key: 'keyY', project_id: 1)
variables.create!(id: 6, key: 'keyX', project_id: 1)
variables.create!(id: 7, key: 'key7', project_id: 1)
variables.create!(id: 8, key: 'keyY', project_id: 1)
end
it 'correctly remove duplicated records with smaller id' do
migrate!
expect(variables.pluck(:id, :key)).to contain_exactly(
[1, 'key1'],
[2, 'key2'],
[3, 'keyX_3'],
[4, 'keyX_4'],
[5, 'keyY_5'],
[6, 'keyX'],
[7, 'key7'],
[8, 'keyY']
)
end
end
...@@ -3,8 +3,16 @@ require 'spec_helper' ...@@ -3,8 +3,16 @@ require 'spec_helper'
describe Ci::Variable, models: true do describe Ci::Variable, models: true do
subject { build(:ci_variable) } subject { build(:ci_variable) }
it { is_expected.to include_module(HasVariable) } let(:secret_value) { 'secret' }
it { is_expected.to validate_uniqueness_of(:key).scoped_to(:project_id) }
describe 'validations' do
it { is_expected.to include_module(HasVariable) }
it { is_expected.to validate_uniqueness_of(:key).scoped_to(:project_id, :environment_scope) }
it { is_expected.to validate_length_of(:key).is_at_most(255) }
it { is_expected.to allow_value('foo').for(:key) }
it { is_expected.not_to allow_value('foo bar').for(:key) }
it { is_expected.not_to allow_value('foo/bar').for(:key) }
end
describe '.unprotected' do describe '.unprotected' do
subject { described_class.unprotected } subject { described_class.unprotected }
......
...@@ -1346,7 +1346,7 @@ describe Project, models: true do ...@@ -1346,7 +1346,7 @@ describe Project, models: true do
.with(project.repository_storage_path, project.path_with_namespace) .with(project.repository_storage_path, project.path_with_namespace)
.and_return(true) .and_return(true)
expect(project).to receive(:create_repository) expect(project).to receive(:create_repository).with(force: true)
project.ensure_repository project.ensure_repository
end end
...@@ -1359,6 +1359,19 @@ describe Project, models: true do ...@@ -1359,6 +1359,19 @@ describe Project, models: true do
project.ensure_repository project.ensure_repository
end end
it 'creates the repository if it is a fork' do
expect(project).to receive(:forked?).and_return(true)
allow(project).to receive(:repository_exists?)
.and_return(false)
expect(shell).to receive(:add_repository)
.with(project.repository_storage_path, project.path_with_namespace)
.and_return(true)
project.ensure_repository
end
end end
describe '#user_can_push_to_empty_repo?' do describe '#user_can_push_to_empty_repo?' do
......
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