summaryrefslogtreecommitdiff
path: root/spec
diff options
context:
space:
mode:
authorLin Jen-Shin <godfat@godfat.org>2016-07-21 18:28:33 +0800
committerLin Jen-Shin <godfat@godfat.org>2016-07-21 18:28:33 +0800
commit83975914337d1dc05193a83d27be577c5631f801 (patch)
treeaeaf2450cb8a8a1c99b064d7d353e28d682c0b65 /spec
parente3ce02300bf90451b98479720d1093afe8b7eea8 (diff)
parent4211f50014faebf027fd2bc80e0cf1d3f012627c (diff)
downloadgitlab-ce-83975914337d1dc05193a83d27be577c5631f801.tar.gz
Merge branch 'artifacts-from-ref-and-build-name-api' into artifacts-from-ref-and-build-name
* artifacts-from-ref-and-build-name-api: (384 commits) Add API documentation for downloading the latest successful build Since it's too hard to use JOIN with Rails... feedback: Workaround MySQL with INNER JOIN: Just put setup directly in the test, feedback: Cleanup the use of let, feedback: Lose unneeded instance variables and variables, feedback: Add link to user profile to commit avatar (!5163) It's not longer than 80 chars Make sure there's a build Use the same logic, it should specify that it's not logged in Use 'when logging as guest' for context, feedback: Cleanup that a bit Refactor service settings view Fix a problem with processing a pipeline where stage only has manual actions Rename user2 to reporter_user Should check against `authorize_read_builds!` A CHANGELOG entry Don't show other actions of the same name Use limit parameter rather than hardcoded value Reuse those two methods ...
Diffstat (limited to 'spec')
-rw-r--r--spec/controllers/help_controller_spec.rb9
-rw-r--r--spec/controllers/projects_controller_spec.rb20
-rw-r--r--spec/factories/ci/builds.rb7
-rw-r--r--spec/features/environments_spec.rb38
-rw-r--r--spec/features/expand_collapse_diffs_spec.rb43
-rw-r--r--spec/features/groups/members/user_requests_access_spec.rb7
-rw-r--r--spec/features/pipelines_settings_spec.rb35
-rw-r--r--spec/features/pipelines_spec.rb22
-rw-r--r--spec/features/projects/badges/list_spec.rb2
-rw-r--r--spec/features/projects/members/user_requests_access_spec.rb7
-rw-r--r--spec/features/projects/slack_service/slack_service_spec.rb26
-rw-r--r--spec/helpers/ci_status_helper_spec.rb10
-rw-r--r--spec/helpers/diff_helper_spec.rb23
-rw-r--r--spec/helpers/time_helper_spec.rb25
-rw-r--r--spec/lib/banzai/filter/autolink_filter_spec.rb20
-rw-r--r--spec/lib/ci/gitlab_ci_yaml_processor_spec.rb2
-rw-r--r--spec/lib/gitlab/badge/build_spec.rb2
-rw-r--r--spec/lib/gitlab/diff/file_spec.rb14
-rw-r--r--spec/lib/gitlab/diff/position_spec.rb24
-rw-r--r--spec/lib/gitlab/diff/position_tracer_spec.rb3
-rw-r--r--spec/lib/gitlab/downtime_check/message_spec.rb17
-rw-r--r--spec/lib/gitlab/downtime_check_spec.rb113
-rw-r--r--spec/lib/gitlab/git_access_spec.rb319
-rw-r--r--spec/lib/gitlab/import_export/avatar_restorer_spec.rb25
-rw-r--r--spec/lib/gitlab/import_export/avatar_saver_spec.rb27
-rw-r--r--spec/lib/gitlab/import_export/project.json18
-rw-r--r--spec/lib/gitlab/import_export/project_tree_restorer_spec.rb7
-rw-r--r--spec/lib/gitlab/import_export/project_tree_saver_spec.rb9
-rw-r--r--spec/lib/gitlab/user_access_spec.rb88
-rw-r--r--spec/models/build_spec.rb330
-rw-r--r--spec/models/ci/pipeline_spec.rb88
-rw-r--r--spec/models/deployment_spec.rb1
-rw-r--r--spec/models/project_services/builds_email_service_spec.rb38
-rw-r--r--spec/models/project_services/slack_service_spec.rb71
-rw-r--r--spec/models/project_spec.rb120
-rw-r--r--spec/models/repository_spec.rb87
-rw-r--r--spec/models/user_spec.rb23
-rw-r--r--spec/requests/api/api_helpers_spec.rb27
-rw-r--r--spec/requests/api/branches_spec.rb87
-rw-r--r--spec/requests/api/builds_spec.rb102
-rw-r--r--spec/requests/api/todos_spec.rb3
-rw-r--r--spec/requests/ci/api/builds_spec.rb10
-rw-r--r--spec/routing/routing_spec.rb7
-rw-r--r--spec/services/git_push_service_spec.rb14
-rw-r--r--spec/services/issues/bulk_update_service_spec.rb38
-rw-r--r--spec/services/merge_requests/refresh_service_spec.rb3
-rw-r--r--spec/support/api_helpers.rb14
-rw-r--r--spec/support/test_env.rb4
-rw-r--r--spec/views/projects/builds/show.html.haml_spec.rb19
49 files changed, 1758 insertions, 290 deletions
diff --git a/spec/controllers/help_controller_spec.rb b/spec/controllers/help_controller_spec.rb
index 267d511c2db..347bef1e129 100644
--- a/spec/controllers/help_controller_spec.rb
+++ b/spec/controllers/help_controller_spec.rb
@@ -63,4 +63,13 @@ describe HelpController do
end
end
end
+
+ describe 'GET #ui' do
+ context 'for UI Development Kit' do
+ it 'renders found' do
+ get :ui
+ expect(response).to have_http_status(200)
+ end
+ end
+ end
end
diff --git a/spec/controllers/projects_controller_spec.rb b/spec/controllers/projects_controller_spec.rb
index 1b1b1bdf52d..3edce4d339c 100644
--- a/spec/controllers/projects_controller_spec.rb
+++ b/spec/controllers/projects_controller_spec.rb
@@ -43,6 +43,26 @@ describe ProjectsController do
end
end
+ context "project with empty repo" do
+ let(:empty_project) { create(:project_empty_repo, :public) }
+
+ before { sign_in(user) }
+
+ User.project_views.keys.each do |project_view|
+ context "with #{project_view} view set" do
+ before do
+ user.update_attributes(project_view: project_view)
+
+ get :show, namespace_id: empty_project.namespace.path, id: empty_project.path
+ end
+
+ it "renders the empty project view" do
+ expect(response).to render_template('empty')
+ end
+ end
+ end
+ end
+
context "rendering default project view" do
render_views
diff --git a/spec/factories/ci/builds.rb b/spec/factories/ci/builds.rb
index 5fb671df570..5e19e403c6b 100644
--- a/spec/factories/ci/builds.rb
+++ b/spec/factories/ci/builds.rb
@@ -3,6 +3,8 @@ include ActionDispatch::TestProcess
FactoryGirl.define do
factory :ci_build, class: Ci::Build do
name 'test'
+ stage 'test'
+ stage_idx 0
ref 'master'
tag false
created_at 'Di 29. Okt 09:50:00 CET 2013'
@@ -43,6 +45,11 @@ FactoryGirl.define do
status 'pending'
end
+ trait :manual do
+ status 'skipped'
+ self.when 'manual'
+ end
+
trait :allowed_to_fail do
allow_failure true
end
diff --git a/spec/features/environments_spec.rb b/spec/features/environments_spec.rb
index 7fb28f4174b..9c018be14b7 100644
--- a/spec/features/environments_spec.rb
+++ b/spec/features/environments_spec.rb
@@ -13,6 +13,7 @@ feature 'Environments', feature: true do
describe 'when showing environments' do
given!(:environment) { }
given!(:deployment) { }
+ given!(:manual) { }
before do
visit namespace_project_environments_path(project.namespace, project)
@@ -43,6 +44,24 @@ feature 'Environments', feature: true do
scenario 'does show deployment SHA' do
expect(page).to have_link(deployment.short_sha)
end
+
+ context 'with build and manual actions' do
+ given(:pipeline) { create(:ci_pipeline, project: project) }
+ given(:build) { create(:ci_build, pipeline: pipeline) }
+ given(:deployment) { create(:deployment, environment: environment, deployable: build) }
+ given(:manual) { create(:ci_build, :manual, pipeline: pipeline, name: 'deploy to production') }
+
+ scenario 'does show a play button' do
+ expect(page).to have_link(manual.name.humanize)
+ end
+
+ scenario 'does allow to play manual action' do
+ expect(manual).to be_skipped
+ expect{ click_link(manual.name.humanize) }.not_to change { Ci::Pipeline.count }
+ expect(page).to have_content(manual.name)
+ expect(manual.reload).to be_pending
+ end
+ end
end
end
@@ -54,6 +73,7 @@ feature 'Environments', feature: true do
describe 'when showing the environment' do
given(:environment) { create(:environment, project: project) }
given!(:deployment) { }
+ given!(:manual) { }
before do
visit namespace_project_environment_path(project.namespace, project, environment)
@@ -77,7 +97,8 @@ feature 'Environments', feature: true do
end
context 'with build' do
- given(:build) { create(:ci_build, project: project) }
+ given(:pipeline) { create(:ci_pipeline, project: project) }
+ given(:build) { create(:ci_build, pipeline: pipeline) }
given(:deployment) { create(:deployment, environment: environment, deployable: build) }
scenario 'does show build name' do
@@ -87,6 +108,21 @@ feature 'Environments', feature: true do
scenario 'does show retry button' do
expect(page).to have_link('Retry')
end
+
+ context 'with manual action' do
+ given(:manual) { create(:ci_build, :manual, pipeline: pipeline, name: 'deploy to production') }
+
+ scenario 'does show a play button' do
+ expect(page).to have_link(manual.name.humanize)
+ end
+
+ scenario 'does allow to play manual action' do
+ expect(manual).to be_skipped
+ expect{ click_link(manual.name.humanize) }.not_to change { Ci::Pipeline.count }
+ expect(page).to have_content(manual.name)
+ expect(manual.reload).to be_pending
+ end
+ end
end
end
end
diff --git a/spec/features/expand_collapse_diffs_spec.rb b/spec/features/expand_collapse_diffs_spec.rb
index 78bc888f2a6..688f68d3cff 100644
--- a/spec/features/expand_collapse_diffs_spec.rb
+++ b/spec/features/expand_collapse_diffs_spec.rb
@@ -3,10 +3,11 @@ require 'spec_helper'
feature 'Expand and collapse diffs', js: true, feature: true do
include WaitForAjax
+ let(:branch) { 'expand-collapse-diffs' }
+
before do
login_as :admin
project = create(:project)
- branch = 'expand-collapse-diffs'
# Ensure that undiffable.md is in .gitattributes
project.repository.copy_gitattributes(branch)
@@ -167,6 +168,46 @@ feature 'Expand and collapse diffs', js: true, feature: true do
end
end
+ context 'visiting a commit without collapsed diffs' do
+ let(:branch) { 'feature' }
+
+ it 'does not show Expand all button' do
+ expect(page).not_to have_link('Expand all')
+ end
+ end
+
+ context 'visiting a commit with more than safe files' do
+ let(:branch) { 'expand-collapse-files' }
+
+ # safe-files -> 100 | safe-lines -> 5000 | commit-files -> 105
+ it 'does collapsing from the safe number of files to the end on small files' do
+ expect(page).to have_link('Expand all')
+
+ expect(page).to have_selector('.diff-content', count: 105)
+ expect(page).to have_selector('.diff-collapsed', count: 5)
+
+ %w(file-95.txt file-96.txt file-97.txt file-98.txt file-99.txt).each do |filename|
+ expect(find("[data-blob-diff-path*='#{filename}']")).to have_selector('.diff-collapsed')
+ end
+ end
+ end
+
+ context 'visiting a commit with more than safe lines' do
+ let(:branch) { 'expand-collapse-lines' }
+
+ # safe-files -> 100 | safe-lines -> 5000 | commit_files -> 8 (each 1250 lines)
+ it 'does collapsing from the safe number of lines to the end' do
+ expect(page).to have_link('Expand all')
+
+ expect(page).to have_selector('.diff-content', count: 6)
+ expect(page).to have_selector('.diff-collapsed', count: 2)
+
+ %w(file-4.txt file-5.txt).each do |filename|
+ expect(find("[data-blob-diff-path*='#{filename}']")).to have_selector('.diff-collapsed')
+ end
+ end
+ end
+
context 'expanding all diffs' do
before do
click_link('Expand all')
diff --git a/spec/features/groups/members/user_requests_access_spec.rb b/spec/features/groups/members/user_requests_access_spec.rb
index d1a6a98ab72..b3baa2ab57c 100644
--- a/spec/features/groups/members/user_requests_access_spec.rb
+++ b/spec/features/groups/members/user_requests_access_spec.rb
@@ -12,6 +12,13 @@ feature 'Groups > Members > User requests access', feature: true do
visit group_path(group)
end
+ scenario 'request access feature is disabled' do
+ group.update_attributes(request_access_enabled: false)
+ visit group_path(group)
+
+ expect(page).not_to have_content 'Request Access'
+ end
+
scenario 'user can request access to a group' do
perform_enqueued_jobs { click_link 'Request Access' }
diff --git a/spec/features/pipelines_settings_spec.rb b/spec/features/pipelines_settings_spec.rb
new file mode 100644
index 00000000000..dcc364a3d01
--- /dev/null
+++ b/spec/features/pipelines_settings_spec.rb
@@ -0,0 +1,35 @@
+require 'spec_helper'
+
+feature "Pipelines settings", feature: true do
+ include GitlabRoutingHelper
+
+ let(:project) { create(:empty_project) }
+ let(:user) { create(:user) }
+ let(:role) { :developer }
+
+ background do
+ login_as(user)
+ project.team << [user, role]
+ visit namespace_project_pipelines_settings_path(project.namespace, project)
+ end
+
+ context 'for developer' do
+ given(:role) { :developer }
+
+ scenario 'to be disallowed to view' do
+ expect(page.status_code).to eq(404)
+ end
+ end
+
+ context 'for master' do
+ given(:role) { :master }
+
+ scenario 'be allowed to change' do
+ fill_in('Test coverage parsing', with: 'coverage_regex')
+ click_on 'Save changes'
+
+ expect(page.status_code).to eq(200)
+ expect(page).to have_field('Test coverage parsing', with: 'coverage_regex')
+ end
+ end
+end
diff --git a/spec/features/pipelines_spec.rb b/spec/features/pipelines_spec.rb
index e7ee0aaea3c..7f861db1969 100644
--- a/spec/features/pipelines_spec.rb
+++ b/spec/features/pipelines_spec.rb
@@ -62,6 +62,20 @@ describe "Pipelines" do
end
end
+ context 'with manual actions' do
+ let!(:manual) { create(:ci_build, :manual, pipeline: pipeline, name: 'manual build', stage: 'test', commands: 'test') }
+
+ before { visit namespace_project_pipelines_path(project.namespace, project) }
+
+ it { expect(page).to have_link('Manual build') }
+
+ context 'when playing' do
+ before { click_link('Manual build') }
+
+ it { expect(manual.reload).to be_pending }
+ end
+ end
+
context 'for generic statuses' do
context 'when running' do
let!(:running) { create(:generic_commit_status, status: 'running', pipeline: pipeline, stage: 'test') }
@@ -117,6 +131,7 @@ describe "Pipelines" do
@success = create(:ci_build, :success, pipeline: pipeline, stage: 'build', name: 'build')
@failed = create(:ci_build, :failed, pipeline: pipeline, stage: 'test', name: 'test', commands: 'test')
@running = create(:ci_build, :running, pipeline: pipeline, stage: 'deploy', name: 'deploy')
+ @manual = create(:ci_build, :manual, pipeline: pipeline, stage: 'deploy', name: 'manual build')
@external = create(:generic_commit_status, status: 'success', pipeline: pipeline, name: 'jenkins', stage: 'external')
end
@@ -131,6 +146,7 @@ describe "Pipelines" do
expect(page).to have_content(@external.id)
expect(page).to have_content('Retry failed')
expect(page).to have_content('Cancel running')
+ expect(page).to have_link('Play')
end
context 'retrying builds' do
@@ -154,6 +170,12 @@ describe "Pipelines" do
it { expect(page).to have_selector('.ci-canceled') }
end
end
+
+ context 'playing manual build' do
+ before { click_link('Play') }
+
+ it { expect(@manual.reload).to be_pending }
+ end
end
describe 'POST /:project/pipelines' do
diff --git a/spec/features/projects/badges/list_spec.rb b/spec/features/projects/badges/list_spec.rb
index 01e90618a98..75166bca119 100644
--- a/spec/features/projects/badges/list_spec.rb
+++ b/spec/features/projects/badges/list_spec.rb
@@ -6,7 +6,7 @@ feature 'list of badges' do
project = create(:project)
project.team << [user, :master]
login_as(user)
- visit namespace_project_badges_path(project.namespace, project)
+ visit namespace_project_pipelines_settings_path(project.namespace, project)
end
scenario 'user displays list of badges' do
diff --git a/spec/features/projects/members/user_requests_access_spec.rb b/spec/features/projects/members/user_requests_access_spec.rb
index f2fe3ef364d..56ede8eb5be 100644
--- a/spec/features/projects/members/user_requests_access_spec.rb
+++ b/spec/features/projects/members/user_requests_access_spec.rb
@@ -11,6 +11,13 @@ feature 'Projects > Members > User requests access', feature: true do
visit namespace_project_path(project.namespace, project)
end
+ scenario 'request access feature is disabled' do
+ project.update_attributes(request_access_enabled: false)
+ visit namespace_project_path(project.namespace, project)
+
+ expect(page).not_to have_content 'Request Access'
+ end
+
scenario 'user can request access to a project' do
perform_enqueued_jobs { click_link 'Request Access' }
diff --git a/spec/features/projects/slack_service/slack_service_spec.rb b/spec/features/projects/slack_service/slack_service_spec.rb
new file mode 100644
index 00000000000..16541f51d98
--- /dev/null
+++ b/spec/features/projects/slack_service/slack_service_spec.rb
@@ -0,0 +1,26 @@
+require 'spec_helper'
+
+feature 'Projects > Slack service > Setup events', feature: true do
+ let(:user) { create(:user) }
+ let(:service) { SlackService.new }
+ let(:project) { create(:project, slack_service: service) }
+
+ background do
+ service.fields
+ service.update_attributes(push_channel: 1, issue_channel: 2, merge_request_channel: 3, note_channel: 4, tag_push_channel: 5, build_channel: 6, wiki_page_channel: 7)
+ project.team << [user, :master]
+ login_as(user)
+ end
+
+ scenario 'user can filter events by channel' do
+ visit edit_namespace_project_service_path(project.namespace, project, service)
+
+ expect(page.find_field("service_push_channel").value).to have_content '1'
+ expect(page.find_field("service_issue_channel").value).to have_content '2'
+ expect(page.find_field("service_merge_request_channel").value).to have_content '3'
+ expect(page.find_field("service_note_channel").value).to have_content '4'
+ expect(page.find_field("service_tag_push_channel").value).to have_content '5'
+ expect(page.find_field("service_build_channel").value).to have_content '6'
+ expect(page.find_field("service_wiki_page_channel").value).to have_content '7'
+ end
+end
diff --git a/spec/helpers/ci_status_helper_spec.rb b/spec/helpers/ci_status_helper_spec.rb
index 45199d0f09d..637b02d9388 100644
--- a/spec/helpers/ci_status_helper_spec.rb
+++ b/spec/helpers/ci_status_helper_spec.rb
@@ -7,7 +7,13 @@ describe CiStatusHelper do
let(:failed_commit) { double("Ci::Pipeline", status: 'failed') }
describe 'ci_icon_for_status' do
- it { expect(helper.ci_icon_for_status(success_commit.status)).to include('fa-check') }
- it { expect(helper.ci_icon_for_status(failed_commit.status)).to include('fa-close') }
+ it 'renders to correct svg on success' do
+ expect(helper).to receive(:render).with('shared/icons/icon_status_success.svg', anything)
+ helper.ci_icon_for_status(success_commit.status)
+ end
+ it 'renders the correct svg on failure' do
+ expect(helper).to receive(:render).with('shared/icons/icon_status_failed.svg', anything)
+ helper.ci_icon_for_status(failed_commit.status)
+ end
end
end
diff --git a/spec/helpers/diff_helper_spec.rb b/spec/helpers/diff_helper_spec.rb
index 4b134a48410..c2fd2c8a533 100644
--- a/spec/helpers/diff_helper_spec.rb
+++ b/spec/helpers/diff_helper_spec.rb
@@ -30,12 +30,31 @@ describe DiffHelper do
expect(helper.diff_view).to eq 'inline'
end
end
-
+
describe 'diff_options' do
- it 'should return hard limit for a diff' do
+ it 'should return hard limit for a diff if force diff is true' do
allow(controller).to receive(:params) { { force_show_diff: true } }
expect(diff_options).to include(Commit.max_diff_options)
end
+
+ it 'should return hard limit for a diff if expand_all_diffs is true' do
+ allow(controller).to receive(:params) { { expand_all_diffs: true } }
+ expect(diff_options).to include(Commit.max_diff_options)
+ end
+
+ it 'should return no collapse false' do
+ expect(diff_options).to include(no_collapse: false)
+ end
+
+ it 'should return no collapse true if expand_all_diffs' do
+ allow(controller).to receive(:params) { { expand_all_diffs: true } }
+ expect(diff_options).to include(no_collapse: true)
+ end
+
+ it 'should return no collapse true if action name diff_for_path' do
+ allow(controller).to receive(:action_name) { 'diff_for_path' }
+ expect(diff_options).to include(no_collapse: true)
+ end
end
describe 'unfold_bottom_class' do
diff --git a/spec/helpers/time_helper_spec.rb b/spec/helpers/time_helper_spec.rb
index 3f62527c5bb..413ead944b9 100644
--- a/spec/helpers/time_helper_spec.rb
+++ b/spec/helpers/time_helper_spec.rb
@@ -1,7 +1,7 @@
require 'spec_helper'
describe TimeHelper do
- describe "#duration_in_words" do
+ describe "#time_interval_in_words" do
it "returns minutes and seconds" do
intervals_in_words = {
100 => "1 minute 40 seconds",
@@ -11,26 +11,23 @@ describe TimeHelper do
}
intervals_in_words.each do |interval, expectation|
- expect(duration_in_words(Time.now + interval, Time.now)).to eq(expectation)
+ expect(time_interval_in_words(interval)).to eq(expectation)
end
end
-
- it "calculates interval from now if there is no finished_at" do
- expect(duration_in_words(nil, Time.now - 5)).to eq("5 seconds")
- end
end
- describe "#time_interval_in_words" do
+ describe "#duration_in_numbers" do
it "returns minutes and seconds" do
- intervals_in_words = {
- 100 => "1 minute 40 seconds",
- 121 => "2 minutes 1 second",
- 3721 => "62 minutes 1 second",
- 0 => "0 seconds"
+ duration_in_numbers = {
+ [100, 0] => "01:40",
+ [121, 0] => "02:01",
+ [3721, 0] => "01:02:01",
+ [0, 0] => "00:00",
+ [nil, Time.now.to_i - 42] => "00:42"
}
- intervals_in_words.each do |interval, expectation|
- expect(time_interval_in_words(interval)).to eq(expectation)
+ duration_in_numbers.each do |interval, expectation|
+ expect(duration_in_numbers(*interval)).to eq(expectation)
end
end
end
diff --git a/spec/lib/banzai/filter/autolink_filter_spec.rb b/spec/lib/banzai/filter/autolink_filter_spec.rb
index 84c2ddf444e..dca7f997570 100644
--- a/spec/lib/banzai/filter/autolink_filter_spec.rb
+++ b/spec/lib/banzai/filter/autolink_filter_spec.rb
@@ -15,6 +15,16 @@ describe Banzai::Filter::AutolinkFilter, lib: true do
expect(filter(act).to_html).to eq exp
end
+ context 'when the input contains no links' do
+ it 'does not parse_html back the rinku returned value' do
+ act = HTML::Pipeline.parse('<p>This text contains no links to autolink</p>')
+
+ expect_any_instance_of(described_class).not_to receive(:parse_html)
+
+ filter(act).to_html
+ end
+ end
+
context 'Rinku schemes' do
it 'autolinks http' do
doc = filter("See #{link}")
@@ -58,6 +68,16 @@ describe Banzai::Filter::AutolinkFilter, lib: true do
expect(filter(act).to_html).to eq exp
end
end
+
+ context 'when the input contains link' do
+ it 'does parse_html back the rinku returned value' do
+ act = HTML::Pipeline.parse("<p>See #{link}</p>")
+
+ expect_any_instance_of(described_class).to receive(:parse_html).at_least(:once).and_call_original
+
+ filter(act).to_html
+ end
+ end
end
context 'other schemes' do
diff --git a/spec/lib/ci/gitlab_ci_yaml_processor_spec.rb b/spec/lib/ci/gitlab_ci_yaml_processor_spec.rb
index ad6587b4c25..d20fd4ab7dd 100644
--- a/spec/lib/ci/gitlab_ci_yaml_processor_spec.rb
+++ b/spec/lib/ci/gitlab_ci_yaml_processor_spec.rb
@@ -1141,7 +1141,7 @@ EOT
config = YAML.dump({ rspec: { script: "test", when: 1 } })
expect do
GitlabCiYamlProcessor.new(config, path)
- end.to raise_error(GitlabCiYamlProcessor::ValidationError, "rspec job: when parameter should be on_success, on_failure or always")
+ end.to raise_error(GitlabCiYamlProcessor::ValidationError, "rspec job: when parameter should be on_success, on_failure, always or manual")
end
it "returns errors if job artifacts:name is not an a string" do
diff --git a/spec/lib/gitlab/badge/build_spec.rb b/spec/lib/gitlab/badge/build_spec.rb
index 2034445a197..f3b522a02f5 100644
--- a/spec/lib/gitlab/badge/build_spec.rb
+++ b/spec/lib/gitlab/badge/build_spec.rb
@@ -113,7 +113,7 @@ describe Gitlab::Badge::Build do
sha: sha,
ref: branch)
- create(:ci_build, pipeline: pipeline)
+ create(:ci_build, pipeline: pipeline, stage: 'notify')
end
def status_node(data, status)
diff --git a/spec/lib/gitlab/diff/file_spec.rb b/spec/lib/gitlab/diff/file_spec.rb
index 0460dcf4658..e883a6eb9c2 100644
--- a/spec/lib/gitlab/diff/file_spec.rb
+++ b/spec/lib/gitlab/diff/file_spec.rb
@@ -32,4 +32,18 @@ describe Gitlab::Diff::File, lib: true do
expect(diff_file.too_large?).to eq(false)
end
end
+
+ describe '#collapsed?' do
+ it 'returns true for a file that is quite big' do
+ expect(diff).to receive(:collapsed?).and_return(true)
+
+ expect(diff_file.collapsed?).to eq(true)
+ end
+
+ it 'returns false for a file that is small enough' do
+ expect(diff).to receive(:collapsed?).and_return(false)
+
+ expect(diff_file.collapsed?).to eq(false)
+ end
+ end
end
diff --git a/spec/lib/gitlab/diff/position_spec.rb b/spec/lib/gitlab/diff/position_spec.rb
index cf28628cb96..10537bea008 100644
--- a/spec/lib/gitlab/diff/position_spec.rb
+++ b/spec/lib/gitlab/diff/position_spec.rb
@@ -338,4 +338,28 @@ describe Gitlab::Diff::Position, lib: true do
end
end
end
+
+ describe "#to_json" do
+ let(:hash) do
+ {
+ old_path: "files/ruby/popen.rb",
+ new_path: "files/ruby/popen.rb",
+ old_line: nil,
+ new_line: 14,
+ base_sha: nil,
+ head_sha: nil,
+ start_sha: nil
+ }
+ end
+
+ let(:diff_position) { described_class.new(hash) }
+
+ it "returns the position as JSON" do
+ expect(JSON.parse(diff_position.to_json)).to eq(hash.stringify_keys)
+ end
+
+ it "works when nested under another hash" do
+ expect(JSON.parse(JSON.generate(pos: diff_position))).to eq('pos' => hash.stringify_keys)
+ end
+ end
end
diff --git a/spec/lib/gitlab/diff/position_tracer_spec.rb b/spec/lib/gitlab/diff/position_tracer_spec.rb
index 08312e60f4a..c268f84c759 100644
--- a/spec/lib/gitlab/diff/position_tracer_spec.rb
+++ b/spec/lib/gitlab/diff/position_tracer_spec.rb
@@ -1639,7 +1639,8 @@ describe Gitlab::Diff::PositionTracer, lib: true do
committer: committer
}
- repository.merge(current_user, second_create_file_commit.sha, branch_name, options)
+ merge_request = create(:merge_request, source_branch: second_create_file_commit.sha, target_branch: branch_name, source_project: project)
+ repository.merge(current_user, merge_request, options)
project.commit(branch_name)
end
diff --git a/spec/lib/gitlab/downtime_check/message_spec.rb b/spec/lib/gitlab/downtime_check/message_spec.rb
new file mode 100644
index 00000000000..93094cda776
--- /dev/null
+++ b/spec/lib/gitlab/downtime_check/message_spec.rb
@@ -0,0 +1,17 @@
+require 'spec_helper'
+
+describe Gitlab::DowntimeCheck::Message do
+ describe '#to_s' do
+ it 'returns an ANSI formatted String for an offline migration' do
+ message = described_class.new('foo.rb', true, 'hello')
+
+ expect(message.to_s).to eq("[\e[32moffline\e[0m]: foo.rb: hello")
+ end
+
+ it 'returns an ANSI formatted String for an online migration' do
+ message = described_class.new('foo.rb')
+
+ expect(message.to_s).to eq("[\e[31monline\e[0m]: foo.rb")
+ end
+ end
+end
diff --git a/spec/lib/gitlab/downtime_check_spec.rb b/spec/lib/gitlab/downtime_check_spec.rb
new file mode 100644
index 00000000000..42d895e548e
--- /dev/null
+++ b/spec/lib/gitlab/downtime_check_spec.rb
@@ -0,0 +1,113 @@
+require 'spec_helper'
+
+describe Gitlab::DowntimeCheck do
+ subject { described_class.new }
+ let(:path) { 'foo.rb' }
+
+ describe '#check' do
+ before do
+ expect(subject).to receive(:require).with(path)
+ end
+
+ context 'when a migration does not specify if downtime is required' do
+ it 'raises RuntimeError' do
+ expect(subject).to receive(:class_for_migration_file).
+ with(path).
+ and_return(Class.new)
+
+ expect { subject.check([path]) }.
+ to raise_error(RuntimeError, /it requires downtime/)
+ end
+ end
+
+ context 'when a migration requires downtime' do
+ context 'when no reason is specified' do
+ it 'raises RuntimeError' do
+ stub_const('TestMigration::DOWNTIME', true)
+
+ expect(subject).to receive(:class_for_migration_file).
+ with(path).
+ and_return(TestMigration)
+
+ expect { subject.check([path]) }.
+ to raise_error(RuntimeError, /no reason was given/)
+ end
+ end
+
+ context 'when a reason is specified' do
+ it 'returns an Array of messages' do
+ stub_const('TestMigration::DOWNTIME', true)
+ stub_const('TestMigration::DOWNTIME_REASON', 'foo')
+
+ expect(subject).to receive(:class_for_migration_file).
+ with(path).
+ and_return(TestMigration)
+
+ messages = subject.check([path])
+
+ expect(messages).to be_an_instance_of(Array)
+ expect(messages[0]).to be_an_instance_of(Gitlab::DowntimeCheck::Message)
+
+ message = messages[0]
+
+ expect(message.path).to eq(path)
+ expect(message.offline).to eq(true)
+ expect(message.reason).to eq('foo')
+ end
+ end
+ end
+ end
+
+ describe '#check_and_print' do
+ it 'checks the migrations and prints the results to STDOUT' do
+ stub_const('TestMigration::DOWNTIME', true)
+ stub_const('TestMigration::DOWNTIME_REASON', 'foo')
+
+ expect(subject).to receive(:require).with(path)
+
+ expect(subject).to receive(:class_for_migration_file).
+ with(path).
+ and_return(TestMigration)
+
+ expect(subject).to receive(:puts).with(an_instance_of(String))
+
+ subject.check_and_print([path])
+ end
+ end
+
+ describe '#class_for_migration_file' do
+ it 'returns the class for a migration file path' do
+ expect(subject.class_for_migration_file('123_string.rb')).to eq(String)
+ end
+ end
+
+ describe '#online?' do
+ it 'returns true when a migration can be performed online' do
+ stub_const('TestMigration::DOWNTIME', false)
+
+ expect(subject.online?(TestMigration)).to eq(true)
+ end
+
+ it 'returns false when a migration can not be performed online' do
+ stub_const('TestMigration::DOWNTIME', true)
+
+ expect(subject.online?(TestMigration)).to eq(false)
+ end
+ end
+
+ describe '#downtime_reason' do
+ context 'when a reason is defined' do
+ it 'returns the downtime reason' do
+ stub_const('TestMigration::DOWNTIME_REASON', 'hello')
+
+ expect(subject.downtime_reason(TestMigration)).to eq('hello')
+ end
+ end
+
+ context 'when a reason is not defined' do
+ it 'returns nil' do
+ expect(subject.downtime_reason(Class.new)).to be_nil
+ end
+ end
+ end
+end
diff --git a/spec/lib/gitlab/git_access_spec.rb b/spec/lib/gitlab/git_access_spec.rb
index c79ba11f782..ae064a878b0 100644
--- a/spec/lib/gitlab/git_access_spec.rb
+++ b/spec/lib/gitlab/git_access_spec.rb
@@ -6,67 +6,6 @@ describe Gitlab::GitAccess, lib: true do
let(:user) { create(:user) }
let(:actor) { user }
- describe 'can_push_to_branch?' do
- describe 'push to none protected branch' do
- it "returns true if user is a master" do
- project.team << [user, :master]
- expect(access.can_push_to_branch?("random_branch")).to be_truthy
- end
-
- it "returns true if user is a developer" do
- project.team << [user, :developer]
- expect(access.can_push_to_branch?("random_branch")).to be_truthy
- end
-
- it "returns false if user is a reporter" do
- project.team << [user, :reporter]
- expect(access.can_push_to_branch?("random_branch")).to be_falsey
- end
- end
-
- describe 'push to protected branch' do
- before do
- @branch = create :protected_branch, project: project
- end
-
- it "returns true if user is a master" do
- project.team << [user, :master]
- expect(access.can_push_to_branch?(@branch.name)).to be_truthy
- end
-
- it "returns false if user is a developer" do
- project.team << [user, :developer]
- expect(access.can_push_to_branch?(@branch.name)).to be_falsey
- end
-
- it "returns false if user is a reporter" do
- project.team << [user, :reporter]
- expect(access.can_push_to_branch?(@branch.name)).to be_falsey
- end
- end
-
- describe 'push to protected branch if allowed for developers' do
- before do
- @branch = create :protected_branch, project: project, developers_can_push: true
- end
-
- it "returns true if user is a master" do
- project.team << [user, :master]
- expect(access.can_push_to_branch?(@branch.name)).to be_truthy
- end
-
- it "returns true if user is a developer" do
- project.team << [user, :developer]
- expect(access.can_push_to_branch?(@branch.name)).to be_truthy
- end
-
- it "returns false if user is a reporter" do
- project.team << [user, :reporter]
- expect(access.can_push_to_branch?(@branch.name)).to be_falsey
- end
- end
- end
-
describe '#check with single protocols allowed' do
def disable_protocol(protocol)
settings = ::ApplicationSetting.create_from_defaults
@@ -105,12 +44,12 @@ describe Gitlab::GitAccess, lib: true do
end
describe 'download_access_check' do
+ subject { access.check('git-upload-pack') }
+
describe 'master permissions' do
before { project.team << [user, :master] }
context 'pull code' do
- subject { access.download_access_check }
-
it { expect(subject.allowed?).to be_truthy }
end
end
@@ -119,8 +58,6 @@ describe Gitlab::GitAccess, lib: true do
before { project.team << [user, :guest] }
context 'pull code' do
- subject { access.download_access_check }
-
it { expect(subject.allowed?).to be_falsey }
end
end
@@ -132,16 +69,12 @@ describe Gitlab::GitAccess, lib: true do
end
context 'pull code' do
- subject { access.download_access_check }
-
it { expect(subject.allowed?).to be_falsey }
end
end
describe 'without acccess to project' do
context 'pull code' do
- subject { access.download_access_check }
-
it { expect(subject.allowed?).to be_falsey }
end
end
@@ -151,110 +84,208 @@ describe Gitlab::GitAccess, lib: true do
let(:actor) { key }
context 'pull code' do
- before { key.projects << project }
- subject { access.download_access_check }
+ context 'when project is authorized' do
+ before { key.projects << project }
- it { expect(subject.allowed?).to be_truthy }
+ it { expect(subject).to be_allowed }
+ end
+
+ context 'when unauthorized' do
+ context 'from public project' do
+ let(:project) { create(:project, :public) }
+
+ it { expect(subject).to be_allowed }
+ end
+
+ context 'from internal project' do
+ let(:project) { create(:project, :internal) }
+
+ it { expect(subject).not_to be_allowed }
+ end
+
+ context 'from private project' do
+ let(:project) { create(:project, :internal) }
+
+ it { expect(subject).not_to be_allowed }
+ end
+ end
end
end
end
describe 'push_access_check' do
- def protect_feature_branch
- create(:protected_branch, name: 'feature', project: project)
- end
+ before { merge_into_protected_branch }
+ let(:unprotected_branch) { FFaker::Internet.user_name }
- def changes
- {
- push_new_branch: "#{Gitlab::Git::BLANK_SHA} 570e7b2ab refs/heads/wow",
+ let(:changes) do
+ { push_new_branch: "#{Gitlab::Git::BLANK_SHA} 570e7b2ab refs/heads/wow",
push_master: '6f6d7e7ed 570e7b2ab refs/heads/master',
push_protected_branch: '6f6d7e7ed 570e7b2ab refs/heads/feature',
push_remove_protected_branch: "570e7b2ab #{Gitlab::Git::BLANK_SHA} "\
'refs/heads/feature',
push_tag: '6f6d7e7ed 570e7b2ab refs/tags/v1.0.0',
push_new_tag: "#{Gitlab::Git::BLANK_SHA} 570e7b2ab refs/tags/v7.8.9",
- push_all: ['6f6d7e7ed 570e7b2ab refs/heads/master', '6f6d7e7ed 570e7b2ab refs/heads/feature']
- }
+ push_all: ['6f6d7e7ed 570e7b2ab refs/heads/master', '6f6d7e7ed 570e7b2ab refs/heads/feature'],
+ merge_into_protected_branch: "0b4bc9a #{merge_into_protected_branch} refs/heads/feature" }
end
- def self.permissions_matrix
- {
- master: {
- push_new_branch: true,
- push_master: true,
- push_protected_branch: true,
- push_remove_protected_branch: false,
- push_tag: true,
- push_new_tag: true,
- push_all: true,
- },
-
- developer: {
- push_new_branch: true,
- push_master: true,
- push_protected_branch: false,
- push_remove_protected_branch: false,
- push_tag: false,
- push_new_tag: true,
- push_all: false,
- },
-
- reporter: {
- push_new_branch: false,
- push_master: false,
- push_protected_branch: false,
- push_remove_protected_branch: false,
- push_tag: false,
- push_new_tag: false,
- push_all: false,
- },
-
- guest: {
- push_new_branch: false,
- push_master: false,
- push_protected_branch: false,
- push_remove_protected_branch: false,
- push_tag: false,
- push_new_tag: false,
- push_all: false,
- }
- }
+ def stub_git_hooks
+ # Running the `pre-receive` hook is expensive, and not necessary for this test.
+ allow_any_instance_of(GitHooksService).to receive(:execute).and_yield
end
- def self.updated_permissions_matrix
- updated_permissions_matrix = permissions_matrix.dup
- updated_permissions_matrix[:developer][:push_protected_branch] = true
- updated_permissions_matrix[:developer][:push_all] = true
- updated_permissions_matrix
+ def merge_into_protected_branch
+ @protected_branch_merge_commit ||= begin
+ stub_git_hooks
+ project.repository.add_branch(user, unprotected_branch, 'feature')
+ target_branch = project.repository.lookup('feature')
+ source_branch = project.repository.commit_file(user, FFaker::InternetSE.login_user_name, FFaker::HipsterIpsum.paragraph, FFaker::HipsterIpsum.sentence, unprotected_branch, false)
+ rugged = project.repository.rugged
+ author = { email: "email@example.com", time: Time.now, name: "Example Git User" }
+
+ merge_index = rugged.merge_commits(target_branch, source_branch)
+ Rugged::Commit.create(rugged, author: author, committer: author, message: "commit message", parents: [target_branch, source_branch], tree: merge_index.write_tree(rugged))
+ end
end
- permissions_matrix.keys.each do |role|
- describe "#{role} access" do
- before { protect_feature_branch }
- before { project.team << [user, role] }
+ def self.run_permission_checks(permissions_matrix)
+ permissions_matrix.keys.each do |role|
+ describe "#{role} access" do
+ before { project.team << [user, role] }
- permissions_matrix[role].each do |action, allowed|
- context action do
- subject { access.push_access_check(changes[action]) }
+ permissions_matrix[role].each do |action, allowed|
+ context action do
+ subject { access.push_access_check(changes[action]) }
- it { expect(subject.allowed?).to allowed ? be_truthy : be_falsey }
+ it { expect(subject.allowed?).to allowed ? be_truthy : be_falsey }
+ end
end
end
end
end
- context "with enabled developers push to protected branches " do
- updated_permissions_matrix.keys.each do |role|
- describe "#{role} access" do
- before { create(:protected_branch, name: 'feature', developers_can_push: true, project: project) }
- before { project.team << [user, role] }
+ permissions_matrix = {
+ master: {
+ push_new_branch: true,
+ push_master: true,
+ push_protected_branch: true,
+ push_remove_protected_branch: false,
+ push_tag: true,
+ push_new_tag: true,
+ push_all: true,
+ merge_into_protected_branch: true
+ },
+
+ developer: {
+ push_new_branch: true,
+ push_master: true,
+ push_protected_branch: false,
+ push_remove_protected_branch: false,
+ push_tag: false,
+ push_new_tag: true,
+ push_all: false,
+ merge_into_protected_branch: false
+ },
+
+ reporter: {
+ push_new_branch: false,
+ push_master: false,
+ push_protected_branch: false,
+ push_remove_protected_branch: false,
+ push_tag: false,
+ push_new_tag: false,
+ push_all: false,
+ merge_into_protected_branch: false
+ },
+
+ guest: {
+ push_new_branch: false,
+ push_master: false,
+ push_protected_branch: false,
+ push_remove_protected_branch: false,
+ push_tag: false,
+ push_new_tag: false,
+ push_all: false,
+ merge_into_protected_branch: false
+ }
+ }
- updated_permissions_matrix[role].each do |action, allowed|
- context action do
- subject { access.push_access_check(changes[action]) }
+ [['feature', 'exact'], ['feat*', 'wildcard']].each do |protected_branch_name, protected_branch_type|
+ context do
+ before { create(:protected_branch, name: protected_branch_name, project: project) }
- it { expect(subject.allowed?).to allowed ? be_truthy : be_falsey }
+ run_permission_checks(permissions_matrix)
+ end
+
+ context "when 'developers can push' is turned on for the #{protected_branch_type} protected branch" do
+ before { create(:protected_branch, name: protected_branch_name, developers_can_push: true, project: project) }
+
+ run_permission_checks(permissions_matrix.deep_merge(developer: { push_protected_branch: true, push_all: true, merge_into_protected_branch: true }))
+ end
+
+ context "when 'developers can merge' is turned on for the #{protected_branch_type} protected branch" do
+ before { create(:protected_branch, name: protected_branch_name, developers_can_merge: true, project: project) }
+
+ context "when a merge request exists for the given source/target branch" do
+ context "when the merge request is in progress" do
+ before do
+ create(:merge_request, source_project: project, source_branch: unprotected_branch, target_branch: 'feature', state: 'locked', in_progress_merge_commit_sha: merge_into_protected_branch)
end
+
+ run_permission_checks(permissions_matrix.deep_merge(developer: { merge_into_protected_branch: true }))
+ end
+
+ context "when the merge request is not in progress" do
+ before do
+ create(:merge_request, source_project: project, source_branch: unprotected_branch, target_branch: 'feature', in_progress_merge_commit_sha: nil)
+ end
+
+ run_permission_checks(permissions_matrix.deep_merge(developer: { merge_into_protected_branch: false }))
+ end
+ end
+
+ context "when a merge request does not exist for the given source/target branch" do
+ run_permission_checks(permissions_matrix.deep_merge(developer: { merge_into_protected_branch: false }))
+ end
+ end
+
+ context "when 'developers can merge' and 'developers can push' are turned on for the #{protected_branch_type} protected branch" do
+ before { create(:protected_branch, name: protected_branch_name, developers_can_merge: true, developers_can_push: true, project: project) }
+
+ run_permission_checks(permissions_matrix.deep_merge(developer: { push_protected_branch: true, push_all: true, merge_into_protected_branch: true }))
+ end
+ end
+
+ describe 'deploy key permissions' do
+ let(:key) { create(:deploy_key) }
+ let(:actor) { key }
+
+ context 'push code' do
+ subject { access.check('git-receive-pack') }
+
+ context 'when project is authorized' do
+ before { key.projects << project }
+
+ it { expect(subject).not_to be_allowed }
+ end
+
+ context 'when unauthorized' do
+ context 'to public project' do
+ let(:project) { create(:project, :public) }
+
+ it { expect(subject).not_to be_allowed }
+ end
+
+ context 'to internal project' do
+ let(:project) { create(:project, :internal) }
+
+ it { expect(subject).not_to be_allowed }
+ end
+
+ context 'to private project' do
+ let(:project) { create(:project, :internal) }
+
+ it { expect(subject).not_to be_allowed }
end
end
end
diff --git a/spec/lib/gitlab/import_export/avatar_restorer_spec.rb b/spec/lib/gitlab/import_export/avatar_restorer_spec.rb
new file mode 100644
index 00000000000..5ae178414cc
--- /dev/null
+++ b/spec/lib/gitlab/import_export/avatar_restorer_spec.rb
@@ -0,0 +1,25 @@
+require 'spec_helper'
+
+describe Gitlab::ImportExport::AvatarRestorer, lib: true do
+ let(:shared) { Gitlab::ImportExport::Shared.new(relative_path: 'test') }
+ let(:project) { create(:empty_project) }
+
+ before do
+ allow_any_instance_of(described_class).to receive(:avatar_export_file)
+ .and_return(Rails.root + "spec/fixtures/dk.png")
+ end
+
+ after do
+ project.remove_avatar!
+ end
+
+ it 'restores a project avatar' do
+ expect(described_class.new(project: project, shared: shared).restore).to be true
+ end
+
+ it 'saves the avatar into the project' do
+ described_class.new(project: project, shared: shared).restore
+
+ expect(project.reload.avatar.file.exists?).to be true
+ end
+end
diff --git a/spec/lib/gitlab/import_export/avatar_saver_spec.rb b/spec/lib/gitlab/import_export/avatar_saver_spec.rb
new file mode 100644
index 00000000000..d6ee94442cb
--- /dev/null
+++ b/spec/lib/gitlab/import_export/avatar_saver_spec.rb
@@ -0,0 +1,27 @@
+require 'spec_helper'
+
+describe Gitlab::ImportExport::AvatarSaver, lib: true do
+ let(:shared) { Gitlab::ImportExport::Shared.new(relative_path: 'test') }
+ let(:export_path) { "#{Dir::tmpdir}/project_tree_saver_spec" }
+ let(:project_with_avatar) { create(:empty_project, avatar: fixture_file_upload(Rails.root + "spec/fixtures/dk.png", "image/png")) }
+ let(:project) { create(:empty_project) }
+
+ before do
+ FileUtils.mkdir_p("#{shared.export_path}/avatar/")
+ allow_any_instance_of(Gitlab::ImportExport).to receive(:storage_path).and_return(export_path)
+ end
+
+ after do
+ FileUtils.rm_rf("#{shared.export_path}/avatar")
+ end
+
+ it 'saves a project avatar' do
+ described_class.new(project: project_with_avatar, shared: shared).save
+
+ expect(File).to exist("#{shared.export_path}/avatar/dk.png")
+ end
+
+ it 'is fine not to have an avatar' do
+ expect(described_class.new(project: project, shared: shared).save).to be true
+ end
+end
diff --git a/spec/lib/gitlab/import_export/project.json b/spec/lib/gitlab/import_export/project.json
index 4113d829c3c..b1a5d72c624 100644
--- a/spec/lib/gitlab/import_export/project.json
+++ b/spec/lib/gitlab/import_export/project.json
@@ -2765,7 +2765,7 @@
"committer_email": "dmitriy.zaporozhets@gmail.com"
}
],
- "st_diffs": [
+ "utf8_st_diffs": [
{
"diff": "Binary files a/.DS_Store and /dev/null differ\n",
"new_path": ".DS_Store",
@@ -3138,7 +3138,7 @@
"committer_email": "dmitriy.zaporozhets@gmail.com"
}
],
- "st_diffs": [
+ "utf8_st_diffs": [
{
"diff": "--- /dev/null\n+++ b/files/ruby/feature.rb\n@@ -0,0 +1,5 @@\n+class Feature\n+ def foo\n+ puts 'bar'\n+ end\n+end\n",
"new_path": "files/ruby/feature.rb",
@@ -3423,7 +3423,7 @@
"committer_email": "james@jameslopez.es"
}
],
- "st_diffs": [
+ "utf8_st_diffs": [
{
"diff": "--- /dev/null\n+++ b/test\n",
"new_path": "test",
@@ -3960,7 +3960,7 @@
"committer_email": "dmitriy.zaporozhets@gmail.com"
}
],
- "st_diffs": [
+ "utf8_st_diffs": [
{
"diff": "Binary files a/.DS_Store and /dev/null differ\n",
"new_path": ".DS_Store",
@@ -4597,7 +4597,7 @@
"committer_email": "marmis85@gmail.com"
}
],
- "st_diffs": [
+ "utf8_st_diffs": [
{
"diff": "--- a/CHANGELOG\n+++ b/CHANGELOG\n@@ -1,4 +1,6 @@\n-v 6.7.0\n+v6.8.0\n+\n+v6.7.0\n - Add support for Gemnasium as a Project Service (Olivier Gonzalez)\n - Add edit file button to MergeRequest diff\n - Public groups (Jason Hollingsworth)\n",
"new_path": "CHANGELOG",
@@ -5108,7 +5108,7 @@
"committer_email": "stanhu@packetzoom.com"
}
],
- "st_diffs": [
+ "utf8_st_diffs": [
{
"diff": "--- a/CHANGELOG\n+++ b/CHANGELOG\n@@ -1,4 +1,6 @@\n-v 6.7.0\n+v6.8.0\n+\n+v6.7.0\n - Add support for Gemnasium as a Project Service (Olivier Gonzalez)\n - Add edit file button to MergeRequest diff\n - Public groups (Jason Hollingsworth)\n",
"new_path": "CHANGELOG",
@@ -5434,7 +5434,7 @@
"id": 11,
"state": "empty",
"st_commits": null,
- "st_diffs": [
+ "utf8_st_diffs": [
],
"merge_request_id": 11,
@@ -5961,7 +5961,7 @@
"committer_email": "dmitriy.zaporozhets@gmail.com"
}
],
- "st_diffs": [
+ "utf8_st_diffs": [
{
"diff": "Binary files a/.DS_Store and /dev/null differ\n",
"new_path": ".DS_Store",
@@ -6400,7 +6400,7 @@
"committer_email": "james@jameslopez.es"
}
],
- "st_diffs": [
+ "utf8_st_diffs": [
{
"diff": "--- /dev/null\n+++ b/test\n",
"new_path": "test",
diff --git a/spec/lib/gitlab/import_export/project_tree_restorer_spec.rb b/spec/lib/gitlab/import_export/project_tree_restorer_spec.rb
index 877be300262..6ae20c943b1 100644
--- a/spec/lib/gitlab/import_export/project_tree_restorer_spec.rb
+++ b/spec/lib/gitlab/import_export/project_tree_restorer_spec.rb
@@ -2,6 +2,7 @@ require 'spec_helper'
describe Gitlab::ImportExport::ProjectTreeRestorer, services: true do
describe 'restore project tree' do
+
let(:user) { create(:user) }
let(:namespace) { create(:namespace, owner: user) }
let(:shared) { Gitlab::ImportExport::Shared.new(relative_path: "", project_path: 'path') }
@@ -53,6 +54,12 @@ describe Gitlab::ImportExport::ProjectTreeRestorer, services: true do
expect(event.note.noteable.project).not_to be_nil
end
end
+
+ it 'has the correct data for merge request st_diffs' do
+ # makes sure we are renaming the custom method +utf8_st_diffs+ into +st_diffs+
+
+ expect { restored_project_json }.to change(MergeRequestDiff.where.not(st_diffs: nil), :count).by(9)
+ end
end
end
end
diff --git a/spec/lib/gitlab/import_export/project_tree_saver_spec.rb b/spec/lib/gitlab/import_export/project_tree_saver_spec.rb
index 1424de9e60b..057ef6e76a0 100644
--- a/spec/lib/gitlab/import_export/project_tree_saver_spec.rb
+++ b/spec/lib/gitlab/import_export/project_tree_saver_spec.rb
@@ -102,12 +102,17 @@ describe Gitlab::ImportExport::ProjectTreeSaver, services: true do
it 'has ci pipeline notes' do
expect(saved_project_json['pipelines'].first['notes']).not_to be_empty
end
+
+ it 'does not complain about non UTF-8 characters in MR diffs' do
+ ActiveRecord::Base.connection.execute("UPDATE merge_request_diffs SET st_diffs = '---\n- :diff: !binary |-\n LS0tIC9kZXYvbnVsbAorKysgYi9pbWFnZXMvbnVjb3IucGRmCkBAIC0wLDAg\n KzEsMTY3OSBAQAorJVBERi0xLjUNJeLjz9MNCisxIDAgb2JqDTw8L01ldGFk\n YXR'")
+
+ expect(project_tree_saver.save).to be true
+ end
end
end
def setup_project
issue = create(:issue, assignee: user)
- merge_request = create(:merge_request)
label = create(:label)
snippet = create(:project_snippet)
release = create(:release)
@@ -115,12 +120,12 @@ describe Gitlab::ImportExport::ProjectTreeSaver, services: true do
project = create(:project,
:public,
issues: [issue],
- merge_requests: [merge_request],
labels: [label],
snippets: [snippet],
releases: [release]
)
+ merge_request = create(:merge_request, source_project: project)
commit_status = create(:commit_status, project: project)
ci_pipeline = create(:ci_pipeline,
diff --git a/spec/lib/gitlab/user_access_spec.rb b/spec/lib/gitlab/user_access_spec.rb
new file mode 100644
index 00000000000..aa9ec243498
--- /dev/null
+++ b/spec/lib/gitlab/user_access_spec.rb
@@ -0,0 +1,88 @@
+require 'spec_helper'
+
+describe Gitlab::UserAccess, lib: true do
+ let(:access) { Gitlab::UserAccess.new(user, project: project) }
+ let(:project) { create(:project) }
+ let(:user) { create(:user) }
+
+ describe 'can_push_to_branch?' do
+ describe 'push to none protected branch' do
+ it 'returns true if user is a master' do
+ project.team << [user, :master]
+ expect(access.can_push_to_branch?('random_branch')).to be_truthy
+ end
+
+ it 'returns true if user is a developer' do
+ project.team << [user, :developer]
+ expect(access.can_push_to_branch?('random_branch')).to be_truthy
+ end
+
+ it 'returns false if user is a reporter' do
+ project.team << [user, :reporter]
+ expect(access.can_push_to_branch?('random_branch')).to be_falsey
+ end
+ end
+
+ describe 'push to protected branch' do
+ let(:branch) { create :protected_branch, project: project }
+
+ it 'returns true if user is a master' do
+ project.team << [user, :master]
+ expect(access.can_push_to_branch?(branch.name)).to be_truthy
+ end
+
+ it 'returns false if user is a developer' do
+ project.team << [user, :developer]
+ expect(access.can_push_to_branch?(branch.name)).to be_falsey
+ end
+
+ it 'returns false if user is a reporter' do
+ project.team << [user, :reporter]
+ expect(access.can_push_to_branch?(branch.name)).to be_falsey
+ end
+ end
+
+ describe 'push to protected branch if allowed for developers' do
+ before do
+ @branch = create :protected_branch, project: project, developers_can_push: true
+ end
+
+ it 'returns true if user is a master' do
+ project.team << [user, :master]
+ expect(access.can_push_to_branch?(@branch.name)).to be_truthy
+ end
+
+ it 'returns true if user is a developer' do
+ project.team << [user, :developer]
+ expect(access.can_push_to_branch?(@branch.name)).to be_truthy
+ end
+
+ it 'returns false if user is a reporter' do
+ project.team << [user, :reporter]
+ expect(access.can_push_to_branch?(@branch.name)).to be_falsey
+ end
+ end
+
+ describe 'merge to protected branch if allowed for developers' do
+ before do
+ @branch = create :protected_branch, project: project, developers_can_merge: true
+ end
+
+ it 'returns true if user is a master' do
+ project.team << [user, :master]
+ expect(access.can_merge_to_branch?(@branch.name)).to be_truthy
+ end
+
+ it 'returns true if user is a developer' do
+ project.team << [user, :developer]
+ expect(access.can_merge_to_branch?(@branch.name)).to be_truthy
+ end
+
+ it 'returns false if user is a reporter' do
+ project.team << [user, :reporter]
+ expect(access.can_merge_to_branch?(@branch.name)).to be_falsey
+ end
+ end
+
+ end
+end
diff --git a/spec/models/build_spec.rb b/spec/models/build_spec.rb
index 355cb8fdfff..950580fdee3 100644
--- a/spec/models/build_spec.rb
+++ b/spec/models/build_spec.rb
@@ -6,7 +6,7 @@ describe Ci::Build, models: true do
let(:pipeline) do
create(:ci_pipeline, project: project,
sha: project.commit.id,
- ref: 'fix',
+ ref: project.default_branch,
status: 'success')
end
@@ -193,77 +193,185 @@ describe Ci::Build, models: true do
end
describe '#variables' do
+ let(:container_registry_enabled) { false }
+ let(:predefined_variables) do
+ [
+ { key: 'CI', value: 'true', public: true },
+ { key: 'GITLAB_CI', value: 'true', public: true },
+ { key: 'CI_BUILD_ID', value: build.id.to_s, public: true },
+ { key: 'CI_BUILD_TOKEN', value: build.token, public: false },
+ { key: 'CI_BUILD_REF', value: build.sha, public: true },
+ { key: 'CI_BUILD_BEFORE_SHA', value: build.before_sha, public: true },
+ { key: 'CI_BUILD_REF_NAME', value: 'master', public: true },
+ { key: 'CI_BUILD_NAME', value: 'test', public: true },
+ { key: 'CI_BUILD_STAGE', value: 'test', public: true },
+ { key: 'CI_SERVER_NAME', value: 'GitLab', public: true },
+ { key: 'CI_SERVER_VERSION', value: Gitlab::VERSION, public: true },
+ { key: 'CI_SERVER_REVISION', value: Gitlab::REVISION, public: true },
+ { key: 'CI_PROJECT_ID', value: project.id.to_s, public: true },
+ { key: 'CI_PROJECT_NAME', value: project.path, public: true },
+ { key: 'CI_PROJECT_PATH', value: project.path_with_namespace, public: true },
+ { key: 'CI_PROJECT_NAMESPACE', value: project.namespace.path, public: true },
+ { key: 'CI_PROJECT_URL', value: project.web_url, public: true },
+ { key: 'CI_PIPELINE_ID', value: pipeline.id.to_s, public: true }
+ ]
+ end
+
+ before do
+ stub_container_registry_config(enabled: container_registry_enabled, host_port: 'registry.example.com')
+ end
+
+ subject { build.variables }
+
context 'returns variables' do
- subject { build.variables }
+ before do
+ build.yaml_variables = []
+ end
- let(:predefined_variables) do
- [
- { key: :CI_BUILD_NAME, value: 'test', public: true },
- { key: :CI_BUILD_STAGE, value: 'stage', public: true },
- ]
+ it { is_expected.to eq(predefined_variables) }
+ end
+
+ context 'when build is for tag' do
+ let(:tag_variable) do
+ { key: 'CI_BUILD_TAG', value: 'master', public: true }
end
- let(:yaml_variables) do
- [
- { key: :DB_NAME, value: 'postgres', public: true }
- ]
+ before do
+ build.update_attributes(tag: true)
+ end
+
+ it { is_expected.to include(tag_variable) }
+ end
+
+ context 'when secure variable is defined' do
+ let(:secure_variable) do
+ { key: 'SECRET_KEY', value: 'secret_value', public: false }
end
before do
- build.update_attributes(stage: 'stage', yaml_variables: yaml_variables)
+ build.project.variables << Ci::Variable.new(key: 'SECRET_KEY', value: 'secret_value')
end
- it { is_expected.to eq(predefined_variables + yaml_variables) }
+ it { is_expected.to include(secure_variable) }
+ end
- context 'for tag' do
- let(:tag_variable) do
- [
- { key: :CI_BUILD_TAG, value: 'master', public: true }
- ]
- end
+ context 'when build is for triggers' do
+ let(:trigger) { create(:ci_trigger, project: project) }
+ let(:trigger_request) { create(:ci_trigger_request_with_variables, pipeline: pipeline, trigger: trigger) }
+ let(:user_trigger_variable) do
+ { key: :TRIGGER_KEY, value: 'TRIGGER_VALUE', public: false }
+ end
+ let(:predefined_trigger_variable) do
+ { key: 'CI_BUILD_TRIGGERED', value: 'true', public: true }
+ end
- before do
- build.update_attributes(tag: true)
- end
+ before do
+ build.trigger_request = trigger_request
+ end
- it { is_expected.to eq(tag_variable + predefined_variables + yaml_variables) }
+ it { is_expected.to include(user_trigger_variable) }
+ it { is_expected.to include(predefined_trigger_variable) }
+ end
+
+ context 'when yaml_variables are undefined' do
+ before do
+ build.yaml_variables = nil
end
- context 'and secure variables' do
- let(:secure_variables) do
- [
- { key: 'SECRET_KEY', value: 'secret_value', public: false }
- ]
+ context 'use from gitlab-ci.yml' do
+ before do
+ stub_ci_pipeline_yaml_file(config)
end
- before do
- build.project.variables << Ci::Variable.new(key: 'SECRET_KEY', value: 'secret_value')
+ context 'if config is not found' do
+ let(:config) { nil }
+
+ it { is_expected.to eq(predefined_variables) }
end
- it { is_expected.to eq(predefined_variables + yaml_variables + secure_variables) }
+ context 'if config does not have a questioned job' do
+ let(:config) do
+ YAML.dump({
+ test_other: {
+ script: 'Hello World'
+ }
+ })
+ end
- context 'and trigger variables' do
- let(:trigger) { create(:ci_trigger, project: project) }
- let(:trigger_request) { create(:ci_trigger_request_with_variables, pipeline: pipeline, trigger: trigger) }
- let(:trigger_variables) do
- [
- { key: :TRIGGER_KEY, value: 'TRIGGER_VALUE', public: false }
- ]
+ it { is_expected.to eq(predefined_variables) }
+ end
+
+ context 'if config has variables' do
+ let(:config) do
+ YAML.dump({
+ test: {
+ script: 'Hello World',
+ variables: {
+ KEY: 'value'
+ }
+ }
+ })
end
- let(:predefined_trigger_variable) do
- [
- { key: :CI_BUILD_TRIGGERED, value: 'true', public: true }
- ]
+ let(:variables) do
+ [{ key: :KEY, value: 'value', public: true }]
end
- before do
- build.trigger_request = trigger_request
- end
+ it { is_expected.to eq(predefined_variables + variables) }
+ end
+ end
+ end
+
+ context 'when container registry is enabled' do
+ let(:container_registry_enabled) { true }
+ let(:ci_registry) do
+ { key: 'CI_REGISTRY', value: 'registry.example.com', public: true }
+ end
+ let(:ci_registry_image) do
+ { key: 'CI_REGISTRY_IMAGE', value: project.container_registry_repository_url, public: true }
+ end
+
+ context 'and is disabled for project' do
+ before do
+ project.update(container_registry_enabled: false)
+ end
- it { is_expected.to eq(predefined_variables + predefined_trigger_variable + yaml_variables + secure_variables + trigger_variables) }
+ it { is_expected.to include(ci_registry) }
+ it { is_expected.not_to include(ci_registry_image) }
+ end
+
+ context 'and is enabled for project' do
+ before do
+ project.update(container_registry_enabled: true)
end
+
+ it { is_expected.to include(ci_registry) }
+ it { is_expected.to include(ci_registry_image) }
end
end
+
+ context 'when runner is assigned to build' do
+ let(:runner) { create(:ci_runner, description: 'description', tag_list: ['docker', 'linux']) }
+
+ before do
+ build.update(runner: runner)
+ end
+
+ it { is_expected.to include({ key: 'CI_RUNNER_ID', value: runner.id.to_s, public: true }) }
+ it { is_expected.to include({ key: 'CI_RUNNER_DESCRIPTION', value: 'description', public: true }) }
+ it { is_expected.to include({ key: 'CI_RUNNER_TAGS', value: 'docker, linux', public: true }) }
+ end
+
+ context 'returns variables in valid order' do
+ before do
+ allow(build).to receive(:predefined_variables) { ['predefined'] }
+ allow(project).to receive(:predefined_variables) { ['project'] }
+ allow(pipeline).to receive(:predefined_variables) { ['pipeline'] }
+ allow(build).to receive(:yaml_variables) { ['yaml'] }
+ allow(project).to receive(:secret_variables) { ['secret'] }
+ end
+
+ it { is_expected.to eq(%w[predefined project pipeline yaml secret]) }
+ end
end
describe '#has_tags?' do
@@ -662,6 +770,136 @@ describe Ci::Build, models: true do
build.run!
end
+ it { expect(build).not_to be_retryable }
+ end
+
+ context 'when build is finished' do
+ before do
+ build.success!
+ end
+
+ it { expect(build).to be_retryable }
+ end
+ end
+
+ describe '#manual?' do
+ before do
+ build.update(when: value)
+ end
+
+ subject { build.manual? }
+
+ context 'when is set to manual' do
+ let(:value) { 'manual' }
+
+ it { is_expected.to be_truthy }
+ end
+
+ context 'when set to something else' do
+ let(:value) { 'something else' }
+
+ it { is_expected.to be_falsey }
+ end
+ end
+
+ describe '#other_actions' do
+ let(:build) { create(:ci_build, :manual, pipeline: pipeline) }
+ let!(:other_build) { create(:ci_build, :manual, pipeline: pipeline, name: 'other action') }
+
+ subject { build.other_actions }
+
+ it 'returns other actions' do
+ is_expected.to contain_exactly(other_build)
+ end
+
+ context 'when build is retried' do
+ let!(:new_build) { Ci::Build.retry(build) }
+
+ it 'does not return any of them' do
+ is_expected.not_to include(build, new_build)
+ end
+ end
+
+ context 'when other build is retried' do
+ let!(:retried_build) { Ci::Build.retry(other_build) }
+
+ it 'returns a retried build' do
+ is_expected.to contain_exactly(retried_build)
+ end
+ end
+ end
+
+ describe '#play' do
+ let(:build) { create(:ci_build, :manual, pipeline: pipeline) }
+
+ subject { build.play }
+
+ it 'enques a build' do
+ is_expected.to be_pending
+ is_expected.to eq(build)
+ end
+
+ context 'for success build' do
+ before { build.queue }
+
+ it 'creates a new build' do
+ is_expected.to be_pending
+ is_expected.not_to eq(build)
+ end
+ end
+ end
+
+ describe '#when' do
+ subject { build.when }
+
+ context 'if is undefined' do
+ before do
+ build.when = nil
+ end
+
+ context 'use from gitlab-ci.yml' do
+ before do
+ stub_ci_pipeline_yaml_file(config)
+ end
+
+ context 'if config is not found' do
+ let(:config) { nil }
+
+ it { is_expected.to eq('on_success') }
+ end
+
+ context 'if config does not have a questioned job' do
+ let(:config) do
+ YAML.dump({
+ test_other: {
+ script: 'Hello World'
+ }
+ })
+ end
+
+ it { is_expected.to eq('on_success') }
+ end
+
+ context 'if config has when' do
+ let(:config) do
+ YAML.dump({
+ test: {
+ script: 'Hello World',
+ when: 'always'
+ }
+ })
+ end
+
+ it { is_expected.to eq('always') }
+ end
+ end
+ end
+ end
+
+ describe '#retryable?' do
+ context 'when build is running' do
+ before { build.run! }
+
it 'returns false' do
expect(build).not_to be_retryable
end
diff --git a/spec/models/ci/pipeline_spec.rb b/spec/models/ci/pipeline_spec.rb
index 10db79bd15f..a3bd8fdf30b 100644
--- a/spec/models/ci/pipeline_spec.rb
+++ b/spec/models/ci/pipeline_spec.rb
@@ -260,6 +260,70 @@ describe Ci::Pipeline, models: true do
expect(pipeline.reload.status).to eq('canceled')
end
end
+
+ context 'when listing manual actions' do
+ let(:yaml) do
+ {
+ stages: ["build", "test", "staging", "production", "cleanup"],
+ build: {
+ stage: "build",
+ script: "BUILD",
+ },
+ test: {
+ stage: "test",
+ script: "TEST",
+ },
+ staging: {
+ stage: "staging",
+ script: "PUBLISH",
+ },
+ production: {
+ stage: "production",
+ script: "PUBLISH",
+ when: "manual",
+ },
+ cleanup: {
+ stage: "cleanup",
+ script: "TIDY UP",
+ when: "always",
+ },
+ clear_cache: {
+ stage: "cleanup",
+ script: "CLEAR CACHE",
+ when: "manual",
+ }
+ }
+ end
+
+ it 'returns only for skipped builds' do
+ # currently all builds are created
+ expect(create_builds).to be_truthy
+ expect(manual_actions).to be_empty
+
+ # succeed stage build
+ pipeline.builds.running_or_pending.each(&:success)
+ expect(manual_actions).to be_empty
+
+ # succeed stage test
+ pipeline.builds.running_or_pending.each(&:success)
+ expect(manual_actions).to be_empty
+
+ # succeed stage staging and skip stage production
+ pipeline.builds.running_or_pending.each(&:success)
+ expect(manual_actions).to be_many # production and clear cache
+
+ # succeed stage cleanup
+ pipeline.builds.running_or_pending.each(&:success)
+
+ # after processing a pipeline we should have 6 builds, 5 succeeded
+ expect(pipeline.builds.count).to eq(6)
+ expect(pipeline.builds.success.count).to eq(4)
+ end
+
+ def manual_actions
+ pipeline.manual_actions
+ end
+ end
end
context 'when no builds created' do
@@ -416,4 +480,28 @@ describe Ci::Pipeline, models: true do
end
end
end
+
+ describe '#manual_actions' do
+ subject { pipeline.manual_actions }
+
+ it 'when none defined' do
+ is_expected.to be_empty
+ end
+
+ context 'when action defined' do
+ let!(:manual) { create(:ci_build, :manual, pipeline: pipeline, name: 'deploy') }
+
+ it 'returns one action' do
+ is_expected.to contain_exactly(manual)
+ end
+
+ context 'there are multiple of the same name' do
+ let!(:manual2) { create(:ci_build, :manual, pipeline: pipeline, name: 'deploy') }
+
+ it 'returns latest one' do
+ is_expected.to contain_exactly(manual2)
+ end
+ end
+ end
+ end
end
diff --git a/spec/models/deployment_spec.rb b/spec/models/deployment_spec.rb
index b273018707f..7df3df4bb9e 100644
--- a/spec/models/deployment_spec.rb
+++ b/spec/models/deployment_spec.rb
@@ -11,6 +11,7 @@ describe Deployment, models: true do
it { is_expected.to delegate_method(:name).to(:environment).with_prefix }
it { is_expected.to delegate_method(:commit).to(:project) }
it { is_expected.to delegate_method(:commit_title).to(:commit).as(:try) }
+ it { is_expected.to delegate_method(:manual_actions).to(:deployable).as(:try) }
it { is_expected.to validate_presence_of(:ref) }
it { is_expected.to validate_presence_of(:sha) }
diff --git a/spec/models/project_services/builds_email_service_spec.rb b/spec/models/project_services/builds_email_service_spec.rb
index 236df8f047d..ca2cd8aa551 100644
--- a/spec/models/project_services/builds_email_service_spec.rb
+++ b/spec/models/project_services/builds_email_service_spec.rb
@@ -23,6 +23,44 @@ describe BuildsEmailService do
end
end
+ describe '#test_data' do
+ let(:build) { create(:ci_build) }
+ let(:project) { build.project }
+ let(:user) { create(:user) }
+
+ before { project.team << [user, :developer] }
+
+ it 'builds test data' do
+ data = subject.test_data(project)
+
+ expect(data[:object_kind]).to eq("build")
+ end
+ end
+
+ describe '#test' do
+ it 'sends email' do
+ data = Gitlab::BuildDataBuilder.build(create(:ci_build))
+ subject.recipients = 'test@gitlab.com'
+
+ expect(BuildEmailWorker).to receive(:perform_async)
+
+ subject.test(data)
+ end
+
+ context 'notify only failed builds is true' do
+ it 'sends email' do
+ data = Gitlab::BuildDataBuilder.build(create(:ci_build))
+ data[:build_status] = "success"
+ subject.recipients = 'test@gitlab.com'
+
+ expect(subject).not_to receive(:notify_only_broken_builds)
+ expect(BuildEmailWorker).to receive(:perform_async)
+
+ subject.test(data)
+ end
+ end
+ end
+
describe '#execute' do
it 'sends email' do
subject.recipients = 'test@gitlab.com'
diff --git a/spec/models/project_services/slack_service_spec.rb b/spec/models/project_services/slack_service_spec.rb
index 155f3e74e0d..df511b1bc4c 100644
--- a/spec/models/project_services/slack_service_spec.rb
+++ b/spec/models/project_services/slack_service_spec.rb
@@ -124,6 +124,7 @@ describe SlackService, models: true do
and_return(
double(:slack_service).as_null_object
)
+
slack.execute(push_sample_data)
end
@@ -136,6 +137,76 @@ describe SlackService, models: true do
)
slack.execute(push_sample_data)
end
+
+ context "event channels" do
+ it "uses the right channel for push event" do
+ slack.update_attributes(push_channel: "random")
+
+ expect(Slack::Notifier).to receive(:new).
+ with(webhook_url, channel: "random").
+ and_return(
+ double(:slack_service).as_null_object
+ )
+
+ slack.execute(push_sample_data)
+ end
+
+ it "uses the right channel for merge request event" do
+ slack.update_attributes(merge_request_channel: "random")
+
+ expect(Slack::Notifier).to receive(:new).
+ with(webhook_url, channel: "random").
+ and_return(
+ double(:slack_service).as_null_object
+ )
+
+ slack.execute(@merge_sample_data)
+ end
+
+ it "uses the right channel for issue event" do
+ slack.update_attributes(issue_channel: "random")
+
+ expect(Slack::Notifier).to receive(:new).
+ with(webhook_url, channel: "random").
+ and_return(
+ double(:slack_service).as_null_object
+ )
+
+ slack.execute(@issues_sample_data)
+ end
+
+ it "uses the right channel for wiki event" do
+ slack.update_attributes(wiki_page_channel: "random")
+
+ expect(Slack::Notifier).to receive(:new).
+ with(webhook_url, channel: "random").
+ and_return(
+ double(:slack_service).as_null_object
+ )
+
+ slack.execute(@wiki_page_sample_data)
+ end
+
+ context "note event" do
+ let(:issue_note) do
+ create(:note_on_issue, project: project, note: "issue note")
+ end
+
+ it "uses the right channel" do
+ slack.update_attributes(note_channel: "random")
+
+ note_data = Gitlab::NoteDataBuilder.build(issue_note, user)
+
+ expect(Slack::Notifier).to receive(:new).
+ with(webhook_url, channel: "random").
+ and_return(
+ double(:slack_service).as_null_object
+ )
+
+ slack.execute(note_data)
+ end
+ end
+ end
end
describe "Note events" do
diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb
index 53b420d808f..5629c75665a 100644
--- a/spec/models/project_spec.rb
+++ b/spec/models/project_spec.rb
@@ -458,6 +458,47 @@ describe Project, models: true do
end
end
+ describe "#cache_has_external_wiki" do
+ let(:project) { create(:project) }
+
+ it "stores true if there is an external wiki" do
+ services = double(:service, external_wikis: [ExternalWikiService.new])
+ expect(project).to receive(:services).and_return(services)
+
+ expect do
+ project.cache_has_external_wiki
+ end.to change { project.has_external_wiki }.to(true)
+ end
+
+ it "stores false if there is no external wiki" do
+ services = double(:service, external_wikis: [])
+ expect(project).to receive(:services).and_return(services)
+
+ expect do
+ project.cache_has_external_wiki
+ end.to change { project.has_external_wiki }.to(false)
+ end
+
+ it "changes to true if an external wiki service is created later" do
+ expect do
+ project.cache_has_external_wiki
+ end.to change { project.has_external_wiki }.to(false)
+
+ expect do
+ create(:service, type: "ExternalWikiService", project: project)
+ end.to change { project.has_external_wiki }.to(true)
+ end
+
+ it "changes to false if an external wiki service is destroyed later" do
+ service = create(:service, type: "ExternalWikiService", project: project)
+ expect(project.has_external_wiki).to be_truthy
+
+ expect do
+ service.destroy
+ end.to change { project.has_external_wiki }.to(false)
+ end
+ end
+
describe '#open_branches' do
let(:project) { create(:project) }
@@ -1114,6 +1155,85 @@ describe Project, models: true do
end
end
+ describe '#latest_successful_builds_for' do
+ def create_pipeline(status = 'success')
+ create(:ci_pipeline, project: project,
+ sha: project.commit.sha,
+ ref: project.default_branch,
+ status: status)
+ end
+
+ def create_build(new_pipeline = pipeline, name = 'test')
+ create(:ci_build, :success, :artifacts,
+ pipeline: new_pipeline,
+ status: new_pipeline.status,
+ name: name)
+ end
+
+ let(:project) { create(:project) }
+ let(:pipeline) { create_pipeline }
+
+ context 'with many builds' do
+ it 'gives the latest builds from latest pipeline' do
+ pipeline1 = create_pipeline
+ pipeline2 = create_pipeline
+ build1_p2 = create_build(pipeline2, 'test')
+ create_build(pipeline1, 'test')
+ create_build(pipeline1, 'test2')
+ build2_p2 = create_build(pipeline2, 'test2')
+
+ latest_builds = project.latest_successful_builds_for
+
+ expect(latest_builds).to contain_exactly(build2_p2, build1_p2)
+ end
+ end
+
+ context 'with succeeded pipeline' do
+ let!(:build) { create_build }
+
+ context 'standalone pipeline' do
+ it 'returns builds for ref for default_branch' do
+ builds = project.latest_successful_builds_for
+
+ expect(builds).to contain_exactly(build)
+ end
+
+ it 'returns empty relation if the build cannot be found' do
+ builds = project.latest_successful_builds_for('TAIL')
+
+ expect(builds).to be_kind_of(ActiveRecord::Relation)
+ expect(builds).to be_empty
+ end
+ end
+
+ context 'with some pending pipeline' do
+ before do
+ create_build(create_pipeline('pending'))
+ end
+
+ it 'gives the latest build from latest pipeline' do
+ latest_build = project.latest_successful_builds_for
+
+ expect(latest_build).to contain_exactly(build)
+ end
+ end
+ end
+
+ context 'with pending pipeline' do
+ before do
+ pipeline.update(status: 'pending')
+ create_build(pipeline)
+ end
+
+ it 'returns empty relation' do
+ builds = project.latest_successful_builds_for
+
+ expect(builds).to be_kind_of(ActiveRecord::Relation)
+ expect(builds).to be_empty
+ end
+ end
+ end
+
describe '.where_paths_in' do
context 'without any paths' do
it 'returns an empty relation' do
diff --git a/spec/models/repository_spec.rb b/spec/models/repository_spec.rb
index b39b958450c..59c5732c075 100644
--- a/spec/models/repository_spec.rb
+++ b/spec/models/repository_spec.rb
@@ -4,16 +4,17 @@ describe Repository, models: true do
include RepoHelpers
TestBlob = Struct.new(:name)
- let(:repository) { create(:project).repository }
+ let(:project) { create(:project) }
+ let(:repository) { project.repository }
let(:user) { create(:user) }
let(:commit_options) do
author = repository.user_to_committer(user)
{ message: 'Test message', committer: author, author: author }
end
let(:merge_commit) do
- source_sha = repository.find_branch('feature').target
- merge_commit_sha = repository.merge(user, source_sha, 'master', commit_options)
- repository.commit(merge_commit_sha)
+ merge_request = create(:merge_request, source_branch: 'feature', target_branch: 'master', source_project: project)
+ merge_commit_id = repository.merge(user, merge_request, commit_options)
+ repository.commit(merge_commit_id)
end
describe '#branch_names_contains' do
@@ -129,6 +130,36 @@ describe Repository, models: true do
end
end
+ describe :commit_file do
+ it 'commits change to a file successfully' do
+ expect do
+ repository.commit_file(user, 'CHANGELOG', 'Changelog!',
+ 'Updates file content',
+ 'master', true)
+ end.to change { repository.commits('master').count }.by(1)
+
+ blob = repository.blob_at('master', 'CHANGELOG')
+
+ expect(blob.data).to eq('Changelog!')
+ end
+ end
+
+ describe :update_file do
+ it 'updates filename successfully' do
+ expect do
+ repository.update_file(user, 'NEWLICENSE', 'Copyright!',
+ branch: 'master',
+ previous_path: 'LICENSE',
+ message: 'Changes filename')
+ end.to change { repository.commits('master').count }.by(1)
+
+ files = repository.ls_files('master')
+
+ expect(files).not_to include('LICENSE')
+ expect(files).to include('NEWLICENSE')
+ end
+ end
+
describe "search_files" do
let(:results) { repository.search_files('feature', 'master') }
subject { results }
@@ -718,6 +749,30 @@ describe Repository, models: true do
repository.before_delete
end
+ it 'flushes the tags cache' do
+ expect(repository).to receive(:expire_tags_cache)
+
+ repository.before_delete
+ end
+
+ it 'flushes the tag count cache' do
+ expect(repository).to receive(:expire_tag_count_cache)
+
+ repository.before_delete
+ end
+
+ it 'flushes the branches cache' do
+ expect(repository).to receive(:expire_branches_cache)
+
+ repository.before_delete
+ end
+
+ it 'flushes the branch count cache' do
+ expect(repository).to receive(:expire_branch_count_cache)
+
+ repository.before_delete
+ end
+
it 'flushes the root ref cache' do
expect(repository).to receive(:expire_root_ref_cache)
@@ -748,6 +803,30 @@ describe Repository, models: true do
repository.before_delete
end
+ it 'flushes the tags cache' do
+ expect(repository).to receive(:expire_tags_cache)
+
+ repository.before_delete
+ end
+
+ it 'flushes the tag count cache' do
+ expect(repository).to receive(:expire_tag_count_cache)
+
+ repository.before_delete
+ end
+
+ it 'flushes the branches cache' do
+ expect(repository).to receive(:expire_branches_cache)
+
+ repository.before_delete
+ end
+
+ it 'flushes the branch count cache' do
+ expect(repository).to receive(:expire_branch_count_cache)
+
+ repository.before_delete
+ end
+
it 'flushes the root ref cache' do
expect(repository).to receive(:expire_root_ref_cache)
diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb
index fc74488ac0e..3bf82cf2668 100644
--- a/spec/models/user_spec.rb
+++ b/spec/models/user_spec.rb
@@ -887,16 +887,25 @@ describe User, models: true do
end
describe '#authorized_projects' do
- let!(:user) { create(:user) }
- let!(:private_project) { create(:project, :private) }
+ context 'with a minimum access level' do
+ it 'includes projects for which the user is an owner' do
+ user = create(:user)
+ project = create(:empty_project, :private, namespace: user.namespace)
- before do
- private_project.team << [user, Gitlab::Access::MASTER]
- end
+ expect(user.authorized_projects(Gitlab::Access::REPORTER))
+ .to contain_exactly(project)
+ end
- subject { user.authorized_projects }
+ it 'includes projects for which the user is a master' do
+ user = create(:user)
+ project = create(:empty_project, :private)
+
+ project.team << [user, Gitlab::Access::MASTER]
- it { is_expected.to eq([private_project]) }
+ expect(user.authorized_projects(Gitlab::Access::REPORTER))
+ .to contain_exactly(project)
+ end
+ end
end
describe '#ci_authorized_runners' do
diff --git a/spec/requests/api/api_helpers_spec.rb b/spec/requests/api/api_helpers_spec.rb
index 83025953889..831889afb6c 100644
--- a/spec/requests/api/api_helpers_spec.rb
+++ b/spec/requests/api/api_helpers_spec.rb
@@ -49,7 +49,7 @@ describe API::Helpers, api: true do
it "should return nil for a user without access" do
env[API::Helpers::PRIVATE_TOKEN_HEADER] = user.private_token
- allow(Gitlab::UserAccess).to receive(:allowed?).and_return(false)
+ allow_any_instance_of(Gitlab::UserAccess).to receive(:allowed?).and_return(false)
expect(current_user).to be_nil
end
@@ -73,7 +73,7 @@ describe API::Helpers, api: true do
it "should return nil for a user without access" do
env[API::Helpers::PRIVATE_TOKEN_HEADER] = personal_access_token.token
- allow(Gitlab::UserAccess).to receive(:allowed?).and_return(false)
+ allow_any_instance_of(Gitlab::UserAccess).to receive(:allowed?).and_return(false)
expect(current_user).to be_nil
end
@@ -211,4 +211,27 @@ describe API::Helpers, api: true do
expect(sudo_identifier).to eq(' 123')
end
end
+
+ describe '.to_boolean' do
+ it 'converts a valid string to a boolean' do
+ expect(to_boolean('true')).to be_truthy
+ expect(to_boolean('YeS')).to be_truthy
+ expect(to_boolean('t')).to be_truthy
+ expect(to_boolean('1')).to be_truthy
+ expect(to_boolean('ON')).to be_truthy
+ expect(to_boolean('FaLse')).to be_falsy
+ expect(to_boolean('F')).to be_falsy
+ expect(to_boolean('NO')).to be_falsy
+ expect(to_boolean('n')).to be_falsy
+ expect(to_boolean('0')).to be_falsy
+ expect(to_boolean('oFF')).to be_falsy
+ end
+
+ it 'converts an invalid string to nil' do
+ expect(to_boolean('fals')).to be_nil
+ expect(to_boolean('yeah')).to be_nil
+ expect(to_boolean('')).to be_nil
+ expect(to_boolean(nil)).to be_nil
+ end
+ end
end
diff --git a/spec/requests/api/branches_spec.rb b/spec/requests/api/branches_spec.rb
index b11ca26ee68..719da27f919 100644
--- a/spec/requests/api/branches_spec.rb
+++ b/spec/requests/api/branches_spec.rb
@@ -32,6 +32,8 @@ describe API::API, api: true do
expect(json_response['name']).to eq(branch_name)
expect(json_response['commit']['id']).to eq(branch_sha)
expect(json_response['protected']).to eq(false)
+ expect(json_response['developers_can_push']).to eq(false)
+ expect(json_response['developers_can_merge']).to eq(false)
end
it "should return a 403 error if guest" do
@@ -45,14 +47,95 @@ describe API::API, api: true do
end
end
- describe "PUT /projects/:id/repository/branches/:branch/protect" do
- it "should protect a single branch" do
+ describe 'PUT /projects/:id/repository/branches/:branch/protect' do
+ it 'protects a single branch' do
put api("/projects/#{project.id}/repository/branches/#{branch_name}/protect", user)
+
expect(response).to have_http_status(200)
+ expect(json_response['name']).to eq(branch_name)
+ expect(json_response['commit']['id']).to eq(branch_sha)
+ expect(json_response['protected']).to eq(true)
+ expect(json_response['developers_can_push']).to eq(false)
+ expect(json_response['developers_can_merge']).to eq(false)
+ end
+
+ it 'protects a single branch and developers can push' do
+ put api("/projects/#{project.id}/repository/branches/#{branch_name}/protect", user),
+ developers_can_push: true
+
+ expect(response).to have_http_status(200)
+ expect(json_response['name']).to eq(branch_name)
+ expect(json_response['commit']['id']).to eq(branch_sha)
+ expect(json_response['protected']).to eq(true)
+ expect(json_response['developers_can_push']).to eq(true)
+ expect(json_response['developers_can_merge']).to eq(false)
+ end
+ it 'protects a single branch and developers can merge' do
+ put api("/projects/#{project.id}/repository/branches/#{branch_name}/protect", user),
+ developers_can_merge: true
+
+ expect(response).to have_http_status(200)
expect(json_response['name']).to eq(branch_name)
expect(json_response['commit']['id']).to eq(branch_sha)
expect(json_response['protected']).to eq(true)
+ expect(json_response['developers_can_push']).to eq(false)
+ expect(json_response['developers_can_merge']).to eq(true)
+ end
+
+ it 'protects a single branch and developers can push and merge' do
+ put api("/projects/#{project.id}/repository/branches/#{branch_name}/protect", user),
+ developers_can_push: true, developers_can_merge: true
+
+ expect(response).to have_http_status(200)
+ expect(json_response['name']).to eq(branch_name)
+ expect(json_response['commit']['id']).to eq(branch_sha)
+ expect(json_response['protected']).to eq(true)
+ expect(json_response['developers_can_push']).to eq(true)
+ expect(json_response['developers_can_merge']).to eq(true)
+ end
+
+ it 'protects a single branch and developers cannot push and merge' do
+ put api("/projects/#{project.id}/repository/branches/#{branch_name}/protect", user),
+ developers_can_push: 'tru', developers_can_merge: 'tr'
+
+ expect(response).to have_http_status(200)
+ expect(json_response['name']).to eq(branch_name)
+ expect(json_response['commit']['id']).to eq(branch_sha)
+ expect(json_response['protected']).to eq(true)
+ expect(json_response['developers_can_push']).to eq(false)
+ expect(json_response['developers_can_merge']).to eq(false)
+ end
+
+ context 'on a protected branch' do
+ let(:protected_branch) { 'foo' }
+
+ before do
+ project.repository.add_branch(user, protected_branch, 'master')
+ create(:protected_branch, project: project, name: protected_branch, developers_can_push: true, developers_can_merge: true)
+ end
+
+ it 'updates that a developer can push' do
+ put api("/projects/#{project.id}/repository/branches/#{protected_branch}/protect", user),
+ developers_can_push: false, developers_can_merge: false
+
+ expect(response).to have_http_status(200)
+ expect(json_response['name']).to eq(protected_branch)
+ expect(json_response['protected']).to eq(true)
+ expect(json_response['developers_can_push']).to eq(false)
+ expect(json_response['developers_can_merge']).to eq(false)
+ end
+
+ it 'does not update that a developer can push' do
+ put api("/projects/#{project.id}/repository/branches/#{protected_branch}/protect", user),
+ developers_can_push: 'foobar', developers_can_merge: 'foo'
+
+ expect(response).to have_http_status(200)
+ expect(json_response['name']).to eq(protected_branch)
+ expect(json_response['protected']).to eq(true)
+ expect(json_response['developers_can_push']).to eq(true)
+ expect(json_response['developers_can_merge']).to eq(true)
+ end
end
it "should return a 404 error if branch not found" do
diff --git a/spec/requests/api/builds_spec.rb b/spec/requests/api/builds_spec.rb
index fb0f066498a..56eb9cd8f8d 100644
--- a/spec/requests/api/builds_spec.rb
+++ b/spec/requests/api/builds_spec.rb
@@ -6,12 +6,12 @@ describe API::API, api: true do
let(:user) { create(:user) }
let(:api_user) { user }
- let(:user2) { create(:user) }
- let(:project) { create(:project, creator_id: user.id) }
- let(:developer) { create(:project_member, :developer, user: user, project: project) }
- let(:reporter) { create(:project_member, :reporter, user: user2, project: project) }
- let(:pipeline) { create(:ci_pipeline, project: project, sha: project.commit.id) }
- let(:build) { create(:ci_build, pipeline: pipeline) }
+ let!(:project) { create(:project, creator_id: user.id) }
+ let!(:developer) { create(:project_member, :developer, user: user, project: project) }
+ let(:reporter) { create(:project_member, :reporter, project: project) }
+ let(:guest) { create(:project_member, :guest, project: project) }
+ let!(:pipeline) { create(:ci_pipeline, project: project, sha: project.commit.id, ref: project.default_branch) }
+ let!(:build) { create(:ci_build, pipeline: pipeline) }
describe 'GET /projects/:id/builds ' do
let(:query) { '' }
@@ -188,44 +188,94 @@ describe API::API, api: true do
end
describe 'GET /projects/:id/artifacts/:ref_name/download?job=name' do
- include_context 'artifacts from ref and build name'
+ let(:api_user) { reporter.user }
+ let(:build) { create(:ci_build, :success, :artifacts, pipeline: pipeline) }
- def path_from_ref(ref = pipeline.ref, job = build.name)
- api("/projects/#{project.id}/builds/artifacts/#{ref}/download?job=#{job}", user)
+ def path_for_ref(ref = pipeline.ref, job = build.name)
+ api("/projects/#{project.id}/builds/artifacts/#{ref}/download?job=#{job}", api_user)
end
- context '401' do
- let(:user) { nil }
+ context 'when not logged in' do
+ let(:api_user) { nil }
before do
- get path_from_ref
+ get path_for_ref
end
- it 'gives 401 for unauthorized user' do
+ it 'gives 401' do
expect(response).to have_http_status(401)
end
end
- context '404' do
- def verify
- expect(response).to have_http_status(404)
+ context 'when logging as guest' do
+ let(:api_user) { guest.user }
+
+ before do
+ get path_for_ref
+ end
+
+ it 'gives 403' do
+ expect(response).to have_http_status(403)
+ end
+ end
+
+ context 'non-existing build' do
+ shared_examples 'not found' do
+ it { expect(response).to have_http_status(:not_found) }
end
- it_behaves_like 'artifacts from ref with 404'
+ context 'has no such ref' do
+ before do
+ get path_for_ref('TAIL', build.name)
+ end
+
+ it_behaves_like 'not found'
+ end
+
+ context 'has no such build' do
+ before do
+ get path_for_ref(pipeline.ref, 'NOBUILD')
+ end
+
+ it_behaves_like 'not found'
+ end
end
- context '200' do
- def verify
- download_headers =
+ context 'find proper build' do
+ shared_examples 'a valid file' do
+ let(:download_headers) do
{ 'Content-Transfer-Encoding' => 'binary',
'Content-Disposition' =>
"attachment; filename=#{build.artifacts_file.filename}" }
+ end
- expect(response).to have_http_status(200)
- expect(response.headers).to include(download_headers)
+ it { expect(response).to have_http_status(200) }
+ it { expect(response.headers).to include(download_headers) }
+ end
+
+ context 'with regular branch' do
+ before do
+ pipeline.update(ref: 'master',
+ sha: project.commit('master').sha)
+
+ get path_for_ref('master')
+ end
+
+ it_behaves_like 'a valid file'
end
- it_behaves_like 'artifacts from ref successfully'
+ context 'with branch name containing slash' do
+ before do
+ pipeline.update(ref: 'improve/awesome',
+ sha: project.commit('improve/awesome').sha)
+ end
+
+ before do
+ get path_for_ref('improve/awesome')
+ end
+
+ it_behaves_like 'a valid file'
+ end
end
end
@@ -233,8 +283,6 @@ describe API::API, api: true do
let(:build) { create(:ci_build, :trace, pipeline: pipeline) }
before do
- developer
-
get api("/projects/#{project.id}/builds/#{build.id}/trace", api_user)
end
@@ -271,7 +319,7 @@ describe API::API, api: true do
end
context 'user without :update_build permission' do
- let(:api_user) { user2 }
+ let(:api_user) { reporter.user }
it 'should not cancel build' do
expect(response).to have_http_status(403)
@@ -308,7 +356,7 @@ describe API::API, api: true do
end
context 'user without :update_build permission' do
- let(:api_user) { user2 }
+ let(:api_user) { reporter.user }
it 'should not retry build' do
expect(response).to have_http_status(403)
diff --git a/spec/requests/api/todos_spec.rb b/spec/requests/api/todos_spec.rb
index 92a4fa216cd..3ccd0af652f 100644
--- a/spec/requests/api/todos_spec.rb
+++ b/spec/requests/api/todos_spec.rb
@@ -134,8 +134,7 @@ describe API::Todos, api: true do
delete api('/todos', john_doe)
expect(response.status).to eq(200)
- expect(json_response).to be_an Array
- expect(json_response.length).to eq(3)
+ expect(response.body).to eq('3')
expect(pending_1.reload).to be_done
expect(pending_2.reload).to be_done
expect(pending_3.reload).to be_done
diff --git a/spec/requests/ci/api/builds_spec.rb b/spec/requests/ci/api/builds_spec.rb
index e7cbc3dd3a7..1c7c60ec644 100644
--- a/spec/requests/ci/api/builds_spec.rb
+++ b/spec/requests/ci/api/builds_spec.rb
@@ -73,12 +73,12 @@ describe Ci::API::API do
post ci_api("/builds/register"), token: runner.token, info: { platform: :darwin }
expect(response).to have_http_status(201)
- expect(json_response["variables"]).to eq([
+ expect(json_response["variables"]).to include(
{ "key" => "CI_BUILD_NAME", "value" => "spinach", "public" => true },
{ "key" => "CI_BUILD_STAGE", "value" => "test", "public" => true },
{ "key" => "DB_NAME", "value" => "postgres", "public" => true },
{ "key" => "SECRET_KEY", "value" => "secret_value", "public" => false }
- ])
+ )
end
it "returns variables for triggers" do
@@ -92,14 +92,14 @@ describe Ci::API::API do
post ci_api("/builds/register"), token: runner.token, info: { platform: :darwin }
expect(response).to have_http_status(201)
- expect(json_response["variables"]).to eq([
+ expect(json_response["variables"]).to include(
{ "key" => "CI_BUILD_NAME", "value" => "spinach", "public" => true },
{ "key" => "CI_BUILD_STAGE", "value" => "test", "public" => true },
{ "key" => "CI_BUILD_TRIGGERED", "value" => "true", "public" => true },
{ "key" => "DB_NAME", "value" => "postgres", "public" => true },
{ "key" => "SECRET_KEY", "value" => "secret_value", "public" => false },
- { "key" => "TRIGGER_KEY", "value" => "TRIGGER_VALUE", "public" => false },
- ])
+ { "key" => "TRIGGER_KEY", "value" => "TRIGGER_VALUE", "public" => false }
+ )
end
it "returns dependent builds" do
diff --git a/spec/routing/routing_spec.rb b/spec/routing/routing_spec.rb
index 2c755919456..0a52c1ab933 100644
--- a/spec/routing/routing_spec.rb
+++ b/spec/routing/routing_spec.rb
@@ -116,12 +116,9 @@ describe HelpController, "routing" do
expect(get(path)).to route_to('help#show',
path: 'workflow/protected_branches/protected_branches1',
format: 'png')
- path = '/help/shortcuts'
- expect(get(path)).to route_to('help#show',
- path: 'shortcuts')
+
path = '/help/ui'
- expect(get(path)).to route_to('help#show',
- path: 'ui')
+ expect(get(path)).to route_to('help#ui')
end
end
diff --git a/spec/services/git_push_service_spec.rb b/spec/services/git_push_service_spec.rb
index afabeed4a80..47c0580e0f0 100644
--- a/spec/services/git_push_service_spec.rb
+++ b/spec/services/git_push_service_spec.rb
@@ -224,7 +224,7 @@ describe GitPushService, services: true do
it "when pushing a branch for the first time" do
expect(project).to receive(:execute_hooks)
expect(project.default_branch).to eq("master")
- expect(project.protected_branches).to receive(:create).with({ name: "master", developers_can_push: false })
+ expect(project.protected_branches).to receive(:create).with({ name: "master", developers_can_push: false, developers_can_merge: false })
execute_service(project, user, @blankrev, 'newrev', 'refs/heads/master' )
end
@@ -242,7 +242,17 @@ describe GitPushService, services: true do
expect(project).to receive(:execute_hooks)
expect(project.default_branch).to eq("master")
- expect(project.protected_branches).to receive(:create).with({ name: "master", developers_can_push: true })
+ expect(project.protected_branches).to receive(:create).with({ name: "master", developers_can_push: true, developers_can_merge: false })
+
+ execute_service(project, user, @blankrev, 'newrev', 'refs/heads/master')
+ end
+
+ it "when pushing a branch for the first time with default branch protection set to 'developers can merge'" do
+ stub_application_setting(default_branch_protection: Gitlab::Access::PROTECTION_DEV_CAN_MERGE)
+
+ expect(project).to receive(:execute_hooks)
+ expect(project.default_branch).to eq("master")
+ expect(project.protected_branches).to receive(:create).with({ name: "master", developers_can_push: false, developers_can_merge: true })
execute_service(project, user, @blankrev, 'newrev', 'refs/heads/master' )
end
diff --git a/spec/services/issues/bulk_update_service_spec.rb b/spec/services/issues/bulk_update_service_spec.rb
index 4a689e64dc5..ba3a4dfc048 100644
--- a/spec/services/issues/bulk_update_service_spec.rb
+++ b/spec/services/issues/bulk_update_service_spec.rb
@@ -262,4 +262,42 @@ describe Issues::BulkUpdateService, services: true do
end
end
end
+
+ describe :subscribe_issues do
+ let(:issues) { create_list(:issue, 5, project: project) }
+ let(:params) do
+ {
+ subscription_event: 'subscribe',
+ issues_ids: issues.map(&:id).join(',')
+ }
+ end
+
+ it 'subscribes the given user' do
+ issues.each do |issue|
+ expect(issue.subscribed?(user)).to be_truthy
+ end
+ end
+ end
+
+ describe :unsubscribe_issues do
+ let(:issues) { create_list(:closed_issue, 5, project: project) }
+ let(:params) do
+ {
+ subscription_event: 'unsubscribe',
+ issues_ids: issues.map(&:id).join(',')
+ }
+ end
+
+ before do
+ issues.each do |issue|
+ issue.subscriptions.create(user: user, subscribed: true)
+ end
+ end
+
+ it 'unsubscribes the given user' do
+ issues.each do |issue|
+ expect(issue.subscribed?(user)).to be_falsey
+ end
+ end
+ end
end
diff --git a/spec/services/merge_requests/refresh_service_spec.rb b/spec/services/merge_requests/refresh_service_spec.rb
index 06f56d85aa8..ce643b3f860 100644
--- a/spec/services/merge_requests/refresh_service_spec.rb
+++ b/spec/services/merge_requests/refresh_service_spec.rb
@@ -88,8 +88,7 @@ describe MergeRequests::RefreshService, services: true do
# Merge master -> feature branch
author = { email: 'test@gitlab.com', time: Time.now, name: "Me" }
commit_options = { message: 'Test message', committer: author, author: author }
- master_commit = @project.repository.commit('master')
- @project.repository.merge(@user, master_commit.id, 'feature', commit_options)
+ @project.repository.merge(@user, @merge_request, commit_options)
commit = @project.repository.commit('feature')
service.new(@project, @user).execute(@oldrev, commit.id, 'refs/heads/feature')
reload_mrs
diff --git a/spec/support/api_helpers.rb b/spec/support/api_helpers.rb
index 1b3cafb497c..68b196d9033 100644
--- a/spec/support/api_helpers.rb
+++ b/spec/support/api_helpers.rb
@@ -24,8 +24,11 @@ module ApiHelpers
(path.index('?') ? '' : '?') +
# Append private_token if given a User object
- (user.respond_to?(:private_token) ?
- "&private_token=#{user.private_token}" : "")
+ if user.respond_to?(:private_token)
+ "&private_token=#{user.private_token}"
+ else
+ ''
+ end
end
def ci_api(path, user = nil)
@@ -35,8 +38,11 @@ module ApiHelpers
(path.index('?') ? '' : '?') +
# Append private_token if given a User object
- (user.respond_to?(:private_token) ?
- "&private_token=#{user.private_token}" : "")
+ if user.respond_to?(:private_token)
+ "&private_token=#{user.private_token}"
+ else
+ ''
+ end
end
def json_response
diff --git a/spec/support/test_env.rb b/spec/support/test_env.rb
index bb6c84262f6..83f2ad96fd8 100644
--- a/spec/support/test_env.rb
+++ b/spec/support/test_env.rb
@@ -18,7 +18,9 @@ module TestEnv
'orphaned-branch' => '45127a9',
'binary-encoding' => '7b1cf43',
'gitattributes' => '5a62481',
- 'expand-collapse-diffs' => '4842455'
+ 'expand-collapse-diffs' => '4842455',
+ 'expand-collapse-files' => '025db92',
+ 'expand-collapse-lines' => '238e82d'
}
# gitlab-test-fork is a fork of gitlab-fork, but we don't necessarily
diff --git a/spec/views/projects/builds/show.html.haml_spec.rb b/spec/views/projects/builds/show.html.haml_spec.rb
index cd18d19ef5e..42220a20c75 100644
--- a/spec/views/projects/builds/show.html.haml_spec.rb
+++ b/spec/views/projects/builds/show.html.haml_spec.rb
@@ -3,8 +3,12 @@ require 'spec_helper'
describe 'projects/builds/show' do
include Devise::TestHelpers
- let(:build) { create(:ci_build) }
- let(:project) { build.project }
+ let(:project) { create(:project) }
+ let(:pipeline) do
+ create(:ci_pipeline, project: project,
+ sha: project.commit.id)
+ end
+ let(:build) { create(:ci_build, pipeline: pipeline) }
before do
assign(:build, build)
@@ -34,4 +38,15 @@ describe 'projects/builds/show' do
expect(rendered).to have_link('Retry')
end
end
+
+ describe 'commit title in sidebar' do
+ let(:commit_title) { project.commit.title }
+
+ it 'shows commit title and not show commit message' do
+ render
+
+ expect(rendered).to have_css('p.build-light-text.append-bottom-0',
+ text: /\A\n#{Regexp.escape(commit_title)}\n\Z/)
+ end
+ end
end