summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKamil Trzcinski <ayufan@ayufan.eu>2016-08-12 12:03:30 +0200
committerKamil Trzcinski <ayufan@ayufan.eu>2016-08-12 12:03:30 +0200
commitca162699ebaf592f66a3fc5ae78ad94d3c87af3b (patch)
treed3e3e0ac968951cb132e7ff2ccd84c0db8e0d731
parent2c06cf98a6dc982caf81c2e4faba195ece9a3b77 (diff)
parentad3e1edcfce1e24fb9889d5d73852680cf4facf9 (diff)
downloadgitlab-ce-ca162699ebaf592f66a3fc5ae78ad94d3c87af3b.tar.gz
Merge branch 'improve-pipeline-processing' into pipeline-hooks-without-slack
# Conflicts: # app/models/ci/pipeline.rb # app/models/commit_status.rb # app/services/ci/create_pipeline_service.rb # spec/models/ci/pipeline_spec.rb
-rw-r--r--.gitlab-ci.yml80
-rw-r--r--.ruby-version2
-rw-r--r--CHANGELOG4
-rw-r--r--GITLAB_SHELL_VERSION2
-rw-r--r--Gemfile2
-rw-r--r--Gemfile.lock62
-rw-r--r--app/assets/javascripts/dropzone_input.js2
-rw-r--r--app/assets/javascripts/preview_markdown.js (renamed from app/assets/javascripts/markdown_preview.js)4
-rw-r--r--app/controllers/projects/wikis_controller.rb2
-rw-r--r--app/controllers/projects_controller.rb2
-rw-r--r--app/helpers/members_helper.rb6
-rw-r--r--app/models/ci/build.rb37
-rw-r--r--app/models/ci/pipeline.rb85
-rw-r--r--app/models/commit_status.rb22
-rw-r--r--app/models/merge_request.rb1
-rw-r--r--app/services/ci/create_pipeline_service.rb8
-rw-r--r--app/services/merge_requests/get_urls_service.rb52
-rw-r--r--app/views/layouts/project.html.haml6
-rw-r--r--app/views/projects/pipelines/new.html.haml2
-rw-r--r--app/views/shared/members/_member.html.haml2
-rw-r--r--config/routes.rb4
-rw-r--r--doc/install/installation.md13
-rw-r--r--doc/legal/corporate_contributor_license_agreement.md14
-rw-r--r--doc/update/8.10-to-8.11.md2
-rw-r--r--features/explore/groups.feature25
-rw-r--r--features/steps/explore/groups.rb4
-rw-r--r--features/steps/shared/builds.rb4
-rw-r--r--lib/api/internal.rb4
-rw-r--r--lib/gitlab/changes_list.rb25
-rw-r--r--lib/gitlab/checks/change_access.rb24
-rw-r--r--lib/gitlab/git.rb18
-rw-r--r--lib/gitlab/git_access.rb4
-rw-r--r--spec/features/projects/pipelines_spec.rb (renamed from spec/features/pipelines_spec.rb)45
-rw-r--r--spec/helpers/members_helper_spec.rb48
-rw-r--r--spec/lib/ci/charts_spec.rb17
-rw-r--r--spec/lib/gitlab/changes_list_spec.rb30
-rw-r--r--spec/models/ci/pipeline_spec.rb70
-rw-r--r--spec/requests/api/builds_spec.rb12
-rw-r--r--spec/requests/api/internal_spec.rb18
-rw-r--r--spec/routing/project_routing_spec.rb8
-rw-r--r--spec/services/ci/image_for_build_service_spec.rb2
-rw-r--r--spec/services/merge_requests/get_urls_service_spec.rb100
42 files changed, 545 insertions, 329 deletions
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 8450d43fc0f..2a63ee15af0 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -1,7 +1,7 @@
-image: "ruby:2.1"
+image: "ruby:2.3"
cache:
- key: "ruby21"
+ key: "ruby-23"
paths:
- vendor/apt
- vendor/ruby
@@ -138,57 +138,57 @@ spinach 7 10: *spinach-knapsack
spinach 8 10: *spinach-knapsack
spinach 9 10: *spinach-knapsack
-# Execute all testing suites against Ruby 2.3
-.ruby-23: &ruby-23
- image: "ruby:2.3"
+# Execute all testing suites against Ruby 2.1
+.ruby-21: &ruby-21
+ image: "ruby:2.1"
<<: *use-db
only:
- master
cache:
- key: "ruby-23"
+ key: "ruby21"
paths:
- vendor/apt
- vendor/ruby
-.rspec-knapsack-ruby23: &rspec-knapsack-ruby23
+.rspec-knapsack-ruby21: &rspec-knapsack-ruby21
<<: *rspec-knapsack
- <<: *ruby-23
+ <<: *ruby-21
-.spinach-knapsack-ruby23: &spinach-knapsack-ruby23
+.spinach-knapsack-ruby21: &spinach-knapsack-ruby21
<<: *spinach-knapsack
- <<: *ruby-23
+ <<: *ruby-21
-rspec 0 20 ruby23: *rspec-knapsack-ruby23
-rspec 1 20 ruby23: *rspec-knapsack-ruby23
-rspec 2 20 ruby23: *rspec-knapsack-ruby23
-rspec 3 20 ruby23: *rspec-knapsack-ruby23
-rspec 4 20 ruby23: *rspec-knapsack-ruby23
-rspec 5 20 ruby23: *rspec-knapsack-ruby23
-rspec 6 20 ruby23: *rspec-knapsack-ruby23
-rspec 7 20 ruby23: *rspec-knapsack-ruby23
-rspec 8 20 ruby23: *rspec-knapsack-ruby23
-rspec 9 20 ruby23: *rspec-knapsack-ruby23
-rspec 10 20 ruby23: *rspec-knapsack-ruby23
-rspec 11 20 ruby23: *rspec-knapsack-ruby23
-rspec 12 20 ruby23: *rspec-knapsack-ruby23
-rspec 13 20 ruby23: *rspec-knapsack-ruby23
-rspec 14 20 ruby23: *rspec-knapsack-ruby23
-rspec 15 20 ruby23: *rspec-knapsack-ruby23
-rspec 16 20 ruby23: *rspec-knapsack-ruby23
-rspec 17 20 ruby23: *rspec-knapsack-ruby23
-rspec 18 20 ruby23: *rspec-knapsack-ruby23
-rspec 19 20 ruby23: *rspec-knapsack-ruby23
+rspec 0 20 ruby21: *rspec-knapsack-ruby21
+rspec 1 20 ruby21: *rspec-knapsack-ruby21
+rspec 2 20 ruby21: *rspec-knapsack-ruby21
+rspec 3 20 ruby21: *rspec-knapsack-ruby21
+rspec 4 20 ruby21: *rspec-knapsack-ruby21
+rspec 5 20 ruby21: *rspec-knapsack-ruby21
+rspec 6 20 ruby21: *rspec-knapsack-ruby21
+rspec 7 20 ruby21: *rspec-knapsack-ruby21
+rspec 8 20 ruby21: *rspec-knapsack-ruby21
+rspec 9 20 ruby21: *rspec-knapsack-ruby21
+rspec 10 20 ruby21: *rspec-knapsack-ruby21
+rspec 11 20 ruby21: *rspec-knapsack-ruby21
+rspec 12 20 ruby21: *rspec-knapsack-ruby21
+rspec 13 20 ruby21: *rspec-knapsack-ruby21
+rspec 14 20 ruby21: *rspec-knapsack-ruby21
+rspec 15 20 ruby21: *rspec-knapsack-ruby21
+rspec 16 20 ruby21: *rspec-knapsack-ruby21
+rspec 17 20 ruby21: *rspec-knapsack-ruby21
+rspec 18 20 ruby21: *rspec-knapsack-ruby21
+rspec 19 20 ruby21: *rspec-knapsack-ruby21
-spinach 0 10 ruby23: *spinach-knapsack-ruby23
-spinach 1 10 ruby23: *spinach-knapsack-ruby23
-spinach 2 10 ruby23: *spinach-knapsack-ruby23
-spinach 3 10 ruby23: *spinach-knapsack-ruby23
-spinach 4 10 ruby23: *spinach-knapsack-ruby23
-spinach 5 10 ruby23: *spinach-knapsack-ruby23
-spinach 6 10 ruby23: *spinach-knapsack-ruby23
-spinach 7 10 ruby23: *spinach-knapsack-ruby23
-spinach 8 10 ruby23: *spinach-knapsack-ruby23
-spinach 9 10 ruby23: *spinach-knapsack-ruby23
+spinach 0 10 ruby21: *spinach-knapsack-ruby21
+spinach 1 10 ruby21: *spinach-knapsack-ruby21
+spinach 2 10 ruby21: *spinach-knapsack-ruby21
+spinach 3 10 ruby21: *spinach-knapsack-ruby21
+spinach 4 10 ruby21: *spinach-knapsack-ruby21
+spinach 5 10 ruby21: *spinach-knapsack-ruby21
+spinach 6 10 ruby21: *spinach-knapsack-ruby21
+spinach 7 10 ruby21: *spinach-knapsack-ruby21
+spinach 8 10 ruby21: *spinach-knapsack-ruby21
+spinach 9 10 ruby21: *spinach-knapsack-ruby21
# Other generic tests
diff --git a/.ruby-version b/.ruby-version
index ebf14b46981..2bf1c1ccf36 100644
--- a/.ruby-version
+++ b/.ruby-version
@@ -1 +1 @@
-2.1.8
+2.3.1
diff --git a/CHANGELOG b/CHANGELOG
index fb87415bf53..21beb3a488b 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -5,6 +5,8 @@ v 8.11.0 (unreleased)
- Fix don't pass a local variable called `i` to a partial. !20510 (herminiotorres)
- Fix rename `add_users_into_project` and `projects_ids`. !20512 (herminiotorres)
- Fix the title of the toggle dropdown button. !5515 (herminiotorres)
+ - Rename `markdown_preview` routes to `preview_markdown`. (Christopher Bartz)
+ - Update to Ruby 2.3.1. !4948
- Improve diff performance by eliminating redundant checks for text blobs
- Ensure that branch names containing escapable characters (e.g. %20) aren't unescaped indiscriminately. !5770 (ewiltshi)
- Convert switch icon into icon font (ClemMakesApps)
@@ -22,6 +24,7 @@ v 8.11.0 (unreleased)
- Cache highlighted diff lines for merge requests
- Pre-create all builds for a Pipeline when the new Pipeline is created !5295
- Fix of 'Commits being passed to custom hooks are already reachable when using the UI'
+ - Show member roles to all users on members page
- Fix awardable button mutuality loading spinners (ClemMakesApps)
- Add support for using RequestStore within Sidekiq tasks via SIDEKIQ_REQUEST_STORE env variable
- Optimize maximum user access level lookup in loading of notes
@@ -102,6 +105,7 @@ v 8.11.0 (unreleased)
- Fix importing GitLab projects with an invalid MR source project
- Sort folders with submodules in Files view !5521
- Each `File::exists?` replaced to `File::exist?` because of deprecate since ruby version 2.2.0
+ - Add auto-completition in pipeline (Katarzyna Kobierska Ula Budziszewska)
v 8.10.5
- Add a data migration to fix some missing timestamps in the members table. !5670
diff --git a/GITLAB_SHELL_VERSION b/GITLAB_SHELL_VERSION
index e4604e3afd0..619b5376684 100644
--- a/GITLAB_SHELL_VERSION
+++ b/GITLAB_SHELL_VERSION
@@ -1 +1 @@
-3.2.1
+3.3.3
diff --git a/Gemfile b/Gemfile
index 2809fca3438..8b44b54e22c 100644
--- a/Gemfile
+++ b/Gemfile
@@ -1,6 +1,6 @@
source 'https://rubygems.org'
-gem 'rails', '4.2.7'
+gem 'rails', '4.2.7.1'
gem 'rails-deprecated_sanitizer', '~> 1.0.3'
# Responders respond_to and respond_with
diff --git a/Gemfile.lock b/Gemfile.lock
index 3f39bbd754d..3ba6048143c 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -3,34 +3,34 @@ GEM
specs:
RedCloth (4.3.2)
ace-rails-ap (4.0.2)
- actionmailer (4.2.7)
- actionpack (= 4.2.7)
- actionview (= 4.2.7)
- activejob (= 4.2.7)
+ actionmailer (4.2.7.1)
+ actionpack (= 4.2.7.1)
+ actionview (= 4.2.7.1)
+ activejob (= 4.2.7.1)
mail (~> 2.5, >= 2.5.4)
rails-dom-testing (~> 1.0, >= 1.0.5)
- actionpack (4.2.7)
- actionview (= 4.2.7)
- activesupport (= 4.2.7)
+ actionpack (4.2.7.1)
+ actionview (= 4.2.7.1)
+ activesupport (= 4.2.7.1)
rack (~> 1.6)
rack-test (~> 0.6.2)
rails-dom-testing (~> 1.0, >= 1.0.5)
rails-html-sanitizer (~> 1.0, >= 1.0.2)
- actionview (4.2.7)
- activesupport (= 4.2.7)
+ actionview (4.2.7.1)
+ activesupport (= 4.2.7.1)
builder (~> 3.1)
erubis (~> 2.7.0)
rails-dom-testing (~> 1.0, >= 1.0.5)
rails-html-sanitizer (~> 1.0, >= 1.0.2)
- activejob (4.2.7)
- activesupport (= 4.2.7)
+ activejob (4.2.7.1)
+ activesupport (= 4.2.7.1)
globalid (>= 0.3.0)
- activemodel (4.2.7)
- activesupport (= 4.2.7)
+ activemodel (4.2.7.1)
+ activesupport (= 4.2.7.1)
builder (~> 3.1)
- activerecord (4.2.7)
- activemodel (= 4.2.7)
- activesupport (= 4.2.7)
+ activerecord (4.2.7.1)
+ activemodel (= 4.2.7.1)
+ activesupport (= 4.2.7.1)
arel (~> 6.0)
activerecord-session_store (1.0.0)
actionpack (>= 4.0, < 5.1)
@@ -38,7 +38,7 @@ GEM
multi_json (~> 1.11, >= 1.11.2)
rack (>= 1.5.2, < 3)
railties (>= 4.0, < 5.1)
- activesupport (4.2.7)
+ activesupport (4.2.7.1)
i18n (~> 0.7)
json (~> 1.7, >= 1.7.7)
minitest (~> 5.1)
@@ -289,7 +289,7 @@ GEM
omniauth (~> 1.0)
pyu-ruby-sasl (~> 0.0.3.1)
rubyntlm (~> 0.3)
- globalid (0.3.6)
+ globalid (0.3.7)
activesupport (>= 4.1.0)
gollum-grit_adapter (1.0.1)
gitlab-grit (~> 2.7, >= 2.7.1)
@@ -518,16 +518,16 @@ GEM
rack
rack-test (0.6.3)
rack (>= 1.0)
- rails (4.2.7)
- actionmailer (= 4.2.7)
- actionpack (= 4.2.7)
- actionview (= 4.2.7)
- activejob (= 4.2.7)
- activemodel (= 4.2.7)
- activerecord (= 4.2.7)
- activesupport (= 4.2.7)
+ rails (4.2.7.1)
+ actionmailer (= 4.2.7.1)
+ actionpack (= 4.2.7.1)
+ actionview (= 4.2.7.1)
+ activejob (= 4.2.7.1)
+ activemodel (= 4.2.7.1)
+ activerecord (= 4.2.7.1)
+ activesupport (= 4.2.7.1)
bundler (>= 1.3.0, < 2.0)
- railties (= 4.2.7)
+ railties (= 4.2.7.1)
sprockets-rails
rails-deprecated_sanitizer (1.0.3)
activesupport (>= 4.2.0.alpha)
@@ -537,9 +537,9 @@ GEM
rails-deprecated_sanitizer (>= 1.0.1)
rails-html-sanitizer (1.0.3)
loofah (~> 2.0)
- railties (4.2.7)
- actionpack (= 4.2.7)
- activesupport (= 4.2.7)
+ railties (4.2.7.1)
+ actionpack (= 4.2.7.1)
+ activesupport (= 4.2.7.1)
rake (>= 0.8.7)
thor (>= 0.18.1, < 2.0)
rainbow (2.1.0)
@@ -914,7 +914,7 @@ DEPENDENCIES
rack-attack (~> 4.3.1)
rack-cors (~> 0.4.0)
rack-oauth2 (~> 1.2.1)
- rails (= 4.2.7)
+ rails (= 4.2.7.1)
rails-deprecated_sanitizer (~> 1.0.3)
rainbow (~> 2.1.0)
rblineprof (~> 0.3.6)
diff --git a/app/assets/javascripts/dropzone_input.js b/app/assets/javascripts/dropzone_input.js
index 288cce04f87..4a6fea929c7 100644
--- a/app/assets/javascripts/dropzone_input.js
+++ b/app/assets/javascripts/dropzone_input.js
@@ -1,5 +1,5 @@
-/*= require markdown_preview */
+/*= require preview_markdown */
(function() {
this.DropzoneInput = (function() {
diff --git a/app/assets/javascripts/markdown_preview.js b/app/assets/javascripts/preview_markdown.js
index 18fc7bae09a..5fd75799640 100644
--- a/app/assets/javascripts/markdown_preview.js
+++ b/app/assets/javascripts/preview_markdown.js
@@ -28,7 +28,7 @@
};
MarkdownPreview.prototype.renderMarkdown = function(text, success) {
- if (!window.markdown_preview_path) {
+ if (!window.preview_markdown_path) {
return;
}
if (text === this.ajaxCache.text) {
@@ -36,7 +36,7 @@
}
return $.ajax({
type: 'POST',
- url: window.markdown_preview_path,
+ url: window.preview_markdown_path,
data: {
text: text
},
diff --git a/app/controllers/projects/wikis_controller.rb b/app/controllers/projects/wikis_controller.rb
index 607fe9c7fed..177ccf5eec9 100644
--- a/app/controllers/projects/wikis_controller.rb
+++ b/app/controllers/projects/wikis_controller.rb
@@ -91,7 +91,7 @@ class Projects::WikisController < Projects::ApplicationController
)
end
- def markdown_preview
+ def preview_markdown
text = params[:text]
ext = Gitlab::ReferenceExtractor.new(@project, current_user)
diff --git a/app/controllers/projects_controller.rb b/app/controllers/projects_controller.rb
index 207f9d6a77f..47efbd4a939 100644
--- a/app/controllers/projects_controller.rb
+++ b/app/controllers/projects_controller.rb
@@ -238,7 +238,7 @@ class ProjectsController < Projects::ApplicationController
}
end
- def markdown_preview
+ def preview_markdown
text = params[:text]
ext = Gitlab::ReferenceExtractor.new(@project, current_user)
diff --git a/app/helpers/members_helper.rb b/app/helpers/members_helper.rb
index ec106418f2d..877c77050be 100644
--- a/app/helpers/members_helper.rb
+++ b/app/helpers/members_helper.rb
@@ -6,12 +6,6 @@ module MembersHelper
"#{action}_#{member.type.underscore}".to_sym
end
- def default_show_roles(member)
- can?(current_user, action_member_permission(:update, member), member) ||
- can?(current_user, action_member_permission(:destroy, member), member) ||
- can?(current_user, action_member_permission(:admin, member), member.source)
- end
-
def remove_member_message(member, user: nil)
user = current_user if defined?(current_user)
diff --git a/app/models/ci/build.rb b/app/models/ci/build.rb
index e2b0b996b6f..ca2fd4f7409 100644
--- a/app/models/ci/build.rb
+++ b/app/models/ci/build.rb
@@ -42,24 +42,25 @@ module Ci
end
def retry(build, user = nil)
- new_build = Ci::Build.new(status: 'pending')
- new_build.ref = build.ref
- new_build.tag = build.tag
- new_build.options = build.options
- new_build.commands = build.commands
- new_build.tag_list = build.tag_list
- new_build.project = build.project
- new_build.pipeline = build.pipeline
- new_build.name = build.name
- new_build.allow_failure = build.allow_failure
- new_build.stage = build.stage
- new_build.stage_idx = build.stage_idx
- new_build.trigger_request = build.trigger_request
- new_build.yaml_variables = build.yaml_variables
- new_build.when = build.when
- new_build.user = user
- new_build.environment = build.environment
- new_build.save
+ new_build = Ci::Build.create(
+ ref: build.ref,
+ tag: build.tag,
+ options: build.options,
+ commands: build.commands,
+ tag_list: build.tag_list,
+ project: build.project,
+ pipeline: build.pipeline,
+ name: build.name,
+ allow_failure: build.allow_failure,
+ stage: build.stage,
+ stage_idx: build.stage_idx,
+ trigger_request: build.trigger_request,
+ yaml_variables: build.yaml_variables,
+ when: build.when,
+ user: user,
+ environment: build.environment,
+ status_event: 'queue'
+ )
MergeRequests::AddTodoWhenBuildFailsService.new(build.project, nil).close(new_build)
new_build
end
diff --git a/app/models/ci/pipeline.rb b/app/models/ci/pipeline.rb
index 2bfe8aa5ddd..40615097804 100644
--- a/app/models/ci/pipeline.rb
+++ b/app/models/ci/pipeline.rb
@@ -21,6 +21,49 @@ module Ci
delegate :stages, to: :statuses
+ state_machine :status, initial: :created do
+ event :queue do
+ transition :created => :pending
+ transition any - [:created, :pending] => :running
+ end
+
+ event :run do
+ transition any => :running
+ end
+
+ event :skip do
+ transition any => :skipped
+ end
+
+ event :drop do
+ transition any => :failed
+ end
+
+ event :succeed do
+ transition any => :success
+ end
+
+ event :cancel do
+ transition any => :canceled
+ end
+
+ before_transition [:created, :pending] => :running do |pipeline|
+ pipeline.started_at = Time.now
+ end
+
+ before_transition any => [:success, :failed, :canceled] do |pipeline|
+ pipeline.finished_at = Time.now
+ end
+
+ before_transition do |pipeline|
+ pipeline.update_duration
+ end
+
+ after_transition do |pipeline, transition|
+ pipeline.execute_hooks unless transition.loopback?
+ end
+ end
+
# ref can't be HEAD or SHA, can only be branch/tag name
scope :latest_successful_for, ->(ref = default_branch) do
where(ref: ref).success.order(id: :desc).limit(1)
@@ -91,16 +134,12 @@ module Ci
def cancel_running
builds.running_or_pending.each(&:cancel)
-
- reload_status!
end
def retry_failed(user)
builds.latest.failed.select(&:retryable?).each do |build|
Ci::Build.retry(build, user)
end
-
- reload_status!
end
def latest?
@@ -187,8 +226,23 @@ module Ci
def process!
Ci::ProcessPipelineService.new(project, user).execute(self)
+ end
- reload_status!
+ def build_updated
+ case latest_builds_status
+ when 'pending'
+ queue
+ when 'running'
+ run
+ when 'success'
+ succeed
+ when 'failed'
+ drop
+ when 'canceled'
+ cancel
+ when 'skipped'
+ skip
+ end
end
def predefined_variables
@@ -197,21 +251,8 @@ module Ci
]
end
- def reload_status!
- reload
- self.status =
- if yaml_errors.blank?
- statuses.latest.status || 'skipped'
- else
- 'failed'
- end
- self.started_at = statuses.started_at
- self.finished_at = statuses.finished_at
+ def update_duration
self.duration = statuses.latest.duration
-
- should_execute_hooks = status_changed?
- save
- execute_hooks if should_execute_hooks
end
private
@@ -225,6 +266,12 @@ module Ci
Gitlab::DataBuilder::Pipeline.build(self)
end
+ def latest_builds_status
+ return 'failed' unless yaml_errors.blank?
+
+ statuses.latest.status || 'skipped'
+ end
+
def keep_around_commits
return unless project
diff --git a/app/models/commit_status.rb b/app/models/commit_status.rb
index 3ab44461179..c21c8ce18db 100644
--- a/app/models/commit_status.rb
+++ b/app/models/commit_status.rb
@@ -62,25 +62,23 @@ class CommitStatus < ActiveRecord::Base
commit_status.update_attributes finished_at: Time.now
end
- after_transition [:created, :pending, :running] => :success do |commit_status|
- MergeRequests::MergeWhenBuildSucceedsService.new(commit_status.pipeline.project, nil).trigger(commit_status)
- end
-
- after_transition any => :failed do |commit_status|
- MergeRequests::AddTodoWhenBuildFailsService.new(commit_status.pipeline.project, nil).execute(commit_status)
- end
-
# We use around_transition to process pipeline on next stages as soon as possible, before the `after_*` is executed
around_transition any => [:success, :failed, :canceled] do |commit_status, block|
block.call
- commit_status.pipeline.process! if commit_status.pipeline
+ commit_status.pipeline.try(:process!)
end
- around_transition any => [:pending, :running] do |commit_status, block|
- block.call
+ after_transition do |commit_status, transition|
+ commit_status.pipeline.try(:build_updated) unless transition.loopback?
+ end
+
+ after_transition [:created, :pending, :running] => :success do |commit_status|
+ MergeRequests::MergeWhenBuildSucceedsService.new(commit_status.pipeline.project, nil).trigger(commit_status)
+ end
- commit_status.pipeline.reload_status! if commit_status.pipeline
+ after_transition any => :failed do |commit_status|
+ MergeRequests::AddTodoWhenBuildFailsService.new(commit_status.pipeline.project, nil).execute(commit_status)
end
end
diff --git a/app/models/merge_request.rb b/app/models/merge_request.rb
index b1fb3ce5d69..f6d0d0c98f5 100644
--- a/app/models/merge_request.rb
+++ b/app/models/merge_request.rb
@@ -104,6 +104,7 @@ class MergeRequest < ActiveRecord::Base
scope :from_project, ->(project) { where(source_project_id: project.id) }
scope :merged, -> { with_state(:merged) }
scope :closed_and_merged, -> { with_states(:closed, :merged) }
+ scope :from_source_branches, ->(branches) { where(source_branch: branches) }
scope :join_project, -> { joins(:target_project) }
scope :references_project, -> { references(:target_project) }
diff --git a/app/services/ci/create_pipeline_service.rb b/app/services/ci/create_pipeline_service.rb
index dabf94fe4c4..cde856b0186 100644
--- a/app/services/ci/create_pipeline_service.rb
+++ b/app/services/ci/create_pipeline_service.rb
@@ -37,7 +37,8 @@ module Ci
end
if !ignore_skip_ci && skip_ci?
- return error('Creation of pipeline is skipped', save: save_on_errors)
+ pipeline.skip if save_on_errors
+ return pipeline
end
unless pipeline.config_builds_attributes.present?
@@ -93,10 +94,7 @@ module Ci
def error(message, save: false)
pipeline.errors.add(:base, message)
- if save
- pipeline.save
- pipeline.reload_status!
- end
+ pipeline.drop if save
pipeline
end
end
diff --git a/app/services/merge_requests/get_urls_service.rb b/app/services/merge_requests/get_urls_service.rb
new file mode 100644
index 00000000000..501fd135e16
--- /dev/null
+++ b/app/services/merge_requests/get_urls_service.rb
@@ -0,0 +1,52 @@
+module MergeRequests
+ class GetUrlsService < BaseService
+ attr_reader :project
+
+ def initialize(project)
+ @project = project
+ end
+
+ def execute(changes)
+ branches = get_branches(changes)
+ merge_requests_map = opened_merge_requests_from_source_branches(branches)
+ branches.map do |branch|
+ existing_merge_request = merge_requests_map[branch]
+ if existing_merge_request
+ url_for_existing_merge_request(existing_merge_request)
+ else
+ url_for_new_merge_request(branch)
+ end
+ end
+ end
+
+ private
+
+ def opened_merge_requests_from_source_branches(branches)
+ merge_requests = MergeRequest.from_project(project).opened.from_source_branches(branches)
+ merge_requests.inject({}) do |hash, mr|
+ hash[mr.source_branch] = mr
+ hash
+ end
+ end
+
+ def get_branches(changes)
+ changes_list = Gitlab::ChangesList.new(changes)
+ changes_list.map do |change|
+ next unless Gitlab::Git.branch_ref?(change[:ref])
+ Gitlab::Git.branch_name(change[:ref])
+ end.compact
+ end
+
+ def url_for_new_merge_request(branch_name)
+ merge_request_params = { source_branch: branch_name }
+ url = Gitlab::Routing.url_helpers.new_namespace_project_merge_request_url(project.namespace, project, merge_request: merge_request_params)
+ { branch_name: branch_name, url: url, new_merge_request: true }
+ end
+
+ def url_for_existing_merge_request(merge_request)
+ target_project = merge_request.target_project
+ url = Gitlab::Routing.url_helpers.namespace_project_merge_request_url(target_project.namespace, target_project, merge_request)
+ { branch_name: merge_request.source_branch, url: url, new_merge_request: false }
+ end
+ end
+end
diff --git a/app/views/layouts/project.html.haml b/app/views/layouts/project.html.haml
index ee9c0366f2b..9fe94291db7 100644
--- a/app/views/layouts/project.html.haml
+++ b/app/views/layouts/project.html.haml
@@ -6,13 +6,13 @@
- content_for :scripts_body_top do
- project = @target_project || @project
- if @project_wiki && @page
- - markdown_preview_path = namespace_project_wiki_markdown_preview_path(project.namespace, project, @page.slug)
+ - preview_markdown_path = namespace_project_wiki_preview_markdown_path(project.namespace, project, @page.slug)
- else
- - markdown_preview_path = markdown_preview_namespace_project_path(project.namespace, project)
+ - preview_markdown_path = preview_markdown_namespace_project_path(project.namespace, project)
- if current_user
:javascript
window.project_uploads_path = "#{namespace_project_uploads_path project.namespace,project}";
- window.markdown_preview_path = "#{markdown_preview_path}";
+ window.preview_markdown_path = "#{preview_markdown_path}";
- content_for :scripts_body do
= render "layouts/init_auto_complete" if current_user
diff --git a/app/views/projects/pipelines/new.html.haml b/app/views/projects/pipelines/new.html.haml
index 5f4ec2e40c8..55202725b9e 100644
--- a/app/views/projects/pipelines/new.html.haml
+++ b/app/views/projects/pipelines/new.html.haml
@@ -9,7 +9,7 @@
.form-group
= f.label :ref, 'Create for', class: 'control-label'
.col-sm-10
- = f.text_field :ref, required: true, tabindex: 2, class: 'form-control'
+ = f.text_field :ref, required: true, tabindex: 2, class: 'form-control js-branch-name ui-autocomplete-input', autocomplete: :false, id: :ref
.help-block Existing branch name, tag
.form-actions
= f.submit 'Create pipeline', class: 'btn btn-create', tabindex: 3
diff --git a/app/views/shared/members/_member.html.haml b/app/views/shared/members/_member.html.haml
index 5ae485f36ba..fc6e206d082 100644
--- a/app/views/shared/members/_member.html.haml
+++ b/app/views/shared/members/_member.html.haml
@@ -1,4 +1,4 @@
-- show_roles = local_assigns.fetch(:show_roles, default_show_roles(member))
+- show_roles = local_assigns.fetch(:show_roles, true)
- show_controls = local_assigns.fetch(:show_controls, true)
- user = member.user
diff --git a/config/routes.rb b/config/routes.rb
index 99a2cd884fe..9a98fab15a3 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -468,7 +468,7 @@ Rails.application.routes.draw do
post :unarchive
post :housekeeping
post :toggle_star
- post :markdown_preview
+ post :preview_markdown
post :export
post :remove_export
post :generate_new_export
@@ -672,7 +672,7 @@ Rails.application.routes.draw do
get '/wikis/*id', to: 'wikis#show', as: 'wiki', constraints: WIKI_SLUG_ID
delete '/wikis/*id', to: 'wikis#destroy', constraints: WIKI_SLUG_ID
put '/wikis/*id', to: 'wikis#update', constraints: WIKI_SLUG_ID
- post '/wikis/*id/markdown_preview', to: 'wikis#markdown_preview', constraints: WIKI_SLUG_ID, as: 'wiki_markdown_preview'
+ post '/wikis/*id/preview_markdown', to: 'wikis#preview_markdown', constraints: WIKI_SLUG_ID, as: 'wiki_preview_markdown'
end
resource :repository, only: [:create] do
diff --git a/doc/install/installation.md b/doc/install/installation.md
index c044d0880d3..eb9606934cd 100644
--- a/doc/install/installation.md
+++ b/doc/install/installation.md
@@ -108,8 +108,7 @@ Then select 'Internet Site' and press enter to confirm the hostname.
## 2. Ruby
-_**Note:** The current supported Ruby version is 2.1.x. Ruby 2.2 and 2.3 are
-currently not supported._
+_**Note:** The current supported Ruby versions are 2.1.x and 2.3.x. 2.3.x is preferred, and support for 2.1.x will be dropped in the future.
The use of Ruby version managers such as [RVM], [rbenv] or [chruby] with GitLab
in production, frequently leads to hard to diagnose problems. For example,
@@ -124,9 +123,9 @@ Remove the old Ruby 1.8 if present:
Download Ruby and compile it:
mkdir /tmp/ruby && cd /tmp/ruby
- curl --remote-name --progress https://cache.ruby-lang.org/pub/ruby/2.1/ruby-2.1.8.tar.gz
- echo 'c7e50159357afd87b13dc5eaf4ac486a70011149 ruby-2.1.8.tar.gz' | shasum -c - && tar xzf ruby-2.1.8.tar.gz
- cd ruby-2.1.8
+ curl --remote-name --progress https://cache.ruby-lang.org/pub/ruby/2.3/ruby-2.3.1.tar.gz
+ echo 'c39b4001f7acb4e334cb60a0f4df72d434bef711 ruby-2.3.1.tar.gz' | shasum -c - && tar xzf ruby-2.3.1.tar.gz
+ cd ruby-2.3.1
./configure --disable-install-rdoc
make
sudo make install
@@ -591,13 +590,13 @@ for the changes to take effect.
If you'd like to connect to a Redis server on a non-standard port or on a different host, you can configure its connection string via the `config/resque.yml` file.
# example
- production:
+ production:
url: redis://redis.example.tld:6379
If you want to connect the Redis server via socket, then use the "unix:" URL scheme and the path to the Redis socket file in the `config/resque.yml` file.
# example
- production:
+ production:
url: unix:/path/to/redis/socket
### Custom SSH Connection
diff --git a/doc/legal/corporate_contributor_license_agreement.md b/doc/legal/corporate_contributor_license_agreement.md
index 7b94506c297..edd6c59138f 100644
--- a/doc/legal/corporate_contributor_license_agreement.md
+++ b/doc/legal/corporate_contributor_license_agreement.md
@@ -6,13 +6,17 @@ You accept and agree to the following terms and conditions for Your present and
"You" (or "Your") shall mean the copyright owner or legal entity authorized by the copyright owner that is making this Agreement with GitLab B.V.. For legal entities, the entity making a Contribution and all other entities that control, are controlled by, or are under common control with that entity are considered to be a single Contributor. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity.
- "Contribution" shall mean the code, documentation or other original works of authorship expressly identified in Schedule B, as well as any original work of authorship, including any modifications or additions to an existing work, that is intentionally submitted by You to GitLab B.V. for inclusion in, or documentation of, any of the products owned or managed by GitLab B.V. (the "Work"). For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to GitLab B.V. or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, GitLab B.V. for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by You as "Not a Contribution."
+ "Contribution" shall mean the code, documentation or other original works of authorship, including any modifications or additions to an existing work, that is submitted by You to GitLab B.V. for inclusion in, or documentation of, any of the products owned or managed by GitLab B.V. (the "Work"). For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to GitLab B.V. or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, GitLab B.V. for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by You as "Not a Contribution."
-2. Grant of Copyright License. Subject to the terms and conditions of this Agreement, You hereby grant to GitLab B.V. and to recipients of software distributed by GitLab B.V. a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare derivative works of, publicly display, publicly perform, sublicense, and distribute Your Contributions and such derivative works.
+2. Grant of Copyright License.
-3. Grant of Patent License. Subject to the terms and conditions of this Agreement, You hereby grant to GitLab B.V. and to recipients of software distributed by GitLab B.V. a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by You that are necessarily infringed by Your Contribution(s) alone or by combination of Your Contribution(s) with the Work to which such Contribution(s) was submitted. If any entity institutes patent litigation against You or any other entity (including a cross-claim or counterclaim in a lawsuit) alleging that your Contribution, or the Work to which you have contributed, constitutes direct or contributory patent infringement, then any patent licenses granted to that entity under this Agreement for that Contribution or Work shall terminate as of the date such litigation is filed.
+Subject to the terms and conditions of this Agreement, You hereby grant to GitLab B.V. and to recipients of software distributed by GitLab B.V. a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare derivative works of, publicly display, publicly perform, sublicense, and distribute Your Contributions and such derivative works.
-4. You represent that You are legally entitled to grant the above license. You represent further that each employee of the Corporation designated on Schedule A below (or in a subsequent written modification to that Schedule) is authorized to submit Contributions on behalf of the Corporation.
+3. Grant of Patent License.
+
+Subject to the terms and conditions of this Agreement, You hereby grant to GitLab B.V. and to recipients of software distributed by GitLab B.V. a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by You that are necessarily infringed by Your Contribution(s) alone or by combination of Your Contribution(s) with the Work to which such Contribution(s) was submitted. If any entity institutes patent litigation against You or any other entity (including a cross-claim or counterclaim in a lawsuit) alleging that your Contribution, or the Work to which you have contributed, constitutes direct or contributory patent infringement, then any patent licenses granted to that entity under this Agreement for that Contribution or Work shall terminate as of the date such litigation is filed.
+
+4. You represent that You are legally entitled to grant the above license. You represent further that each employee of the Corporation is authorized to submit Contributions on behalf of the Corporation, but excluding employees that are designated in writing by You as "Not authorized to submit Contributions on behalf of [name of corporation here]."
5. You represent that each of Your Contributions is Your original creation (see section 7 for submissions on behalf of others).
@@ -20,6 +24,6 @@ You accept and agree to the following terms and conditions for Your present and
7. Should You wish to submit work that is not Your original creation, You may submit it to GitLab B.V. separately from any Contribution, identifying the complete details of its source and of any license or other restriction (including, but not limited to, related patents, trademarks, and license agreements) of which you are personally aware, and conspicuously marking the work as "Submitted on behalf of a third-party: [named here]".
-8. It is your responsibility to notify GitLab B.V. when any change is required to the list of designated employees authorized to submit Contributions on behalf of the Corporation, or to the Corporation's Point of Contact with GitLab B.V..
+8. It is your responsibility to notify GitLab B.V. when any change is required to the designation of employees not authorized to submit Contributions on behalf of the Corporation, or to the Corporation's Point of Contact with GitLab B.V..
This text is licensed under the [Creative Commons Attribution 3.0 License](https://creativecommons.org/licenses/by/3.0/) and the original source is the Google Open Source Programs Office.
diff --git a/doc/update/8.10-to-8.11.md b/doc/update/8.10-to-8.11.md
index 25343d484ba..84c624cbcb7 100644
--- a/doc/update/8.10-to-8.11.md
+++ b/doc/update/8.10-to-8.11.md
@@ -46,7 +46,7 @@ sudo -u git -H git checkout 8-11-stable-ee
```bash
cd /home/git/gitlab-shell
sudo -u git -H git fetch --all --tags
-sudo -u git -H git checkout v3.2.1
+sudo -u git -H git checkout v3.3.3
```
### 5. Update gitlab-workhorse
diff --git a/features/explore/groups.feature b/features/explore/groups.feature
index 5fc9b135601..9eacbe0b25e 100644
--- a/features/explore/groups.feature
+++ b/features/explore/groups.feature
@@ -24,14 +24,6 @@ Feature: Explore Groups
Then I should see project "Internal" items
And I should not see project "Enterprise" items
- Scenario: I should see group's members as user
- Given group "TestGroup" has internal project "Internal"
- And "John Doe" is owner of group "TestGroup"
- When I sign in as a user
- And I visit group "TestGroup" members page
- Then I should see group member "John Doe"
- And I should not see member roles
-
Scenario: I should see group with private, internal and public projects as visitor
Given group "TestGroup" has internal project "Internal"
Given group "TestGroup" has public project "Community"
@@ -56,14 +48,6 @@ Feature: Explore Groups
And I should not see project "Internal" items
And I should not see project "Enterprise" items
- Scenario: I should see group's members as visitor
- Given group "TestGroup" has internal project "Internal"
- Given group "TestGroup" has public project "Community"
- And "John Doe" is owner of group "TestGroup"
- When I visit group "TestGroup" members page
- Then I should see group member "John Doe"
- And I should not see member roles
-
Scenario: I should see group with private, internal and public projects as user
Given group "TestGroup" has internal project "Internal"
Given group "TestGroup" has public project "Community"
@@ -91,15 +75,6 @@ Feature: Explore Groups
And I should see project "Internal" items
And I should not see project "Enterprise" items
- Scenario: I should see group's members as user
- Given group "TestGroup" has internal project "Internal"
- Given group "TestGroup" has public project "Community"
- And "John Doe" is owner of group "TestGroup"
- When I sign in as a user
- And I visit group "TestGroup" members page
- Then I should see group member "John Doe"
- And I should not see member roles
-
Scenario: I should see group with public project in public groups area
Given group "TestGroup" has public project "Community"
When I visit the public groups area
diff --git a/features/steps/explore/groups.rb b/features/steps/explore/groups.rb
index 87f32e70d59..409bf0cb416 100644
--- a/features/steps/explore/groups.rb
+++ b/features/steps/explore/groups.rb
@@ -62,10 +62,6 @@ class Spinach::Features::ExploreGroups < Spinach::FeatureSteps
expect(page).to have_content "John Doe"
end
- step 'I should not see member roles' do
- expect(body).not_to match(%r{owner|developer|reporter|guest}i)
- end
-
protected
def group_has_project(groupname, projectname, visibility_level)
diff --git a/features/steps/shared/builds.rb b/features/steps/shared/builds.rb
index c7f61da05fa..70e6d4836b2 100644
--- a/features/steps/shared/builds.rb
+++ b/features/steps/shared/builds.rb
@@ -12,7 +12,6 @@ module SharedBuilds
step 'project has a recent build' do
@pipeline = create(:ci_empty_pipeline, project: @project, sha: @project.commit.sha, ref: 'master')
@build = create(:ci_build_with_coverage, pipeline: @pipeline)
- @pipeline.reload_status!
end
step 'recent build is successful' do
@@ -24,8 +23,7 @@ module SharedBuilds
end
step 'project has another build that is running' do
- create(:ci_build, pipeline: @pipeline, name: 'second build', status: 'running')
- @pipeline.reload_status!
+ create(:ci_build, pipeline: @pipeline, name: 'second build', status_event: 'run')
end
step 'I visit recent build details page' do
diff --git a/lib/api/internal.rb b/lib/api/internal.rb
index 959b700de78..d8e9ac406c4 100644
--- a/lib/api/internal.rb
+++ b/lib/api/internal.rb
@@ -74,6 +74,10 @@ module API
response
end
+ get "/merge_request_urls" do
+ ::MergeRequests::GetUrlsService.new(project).execute(params[:changes])
+ end
+
#
# Discover user by ssh key
#
diff --git a/lib/gitlab/changes_list.rb b/lib/gitlab/changes_list.rb
new file mode 100644
index 00000000000..95308aca95f
--- /dev/null
+++ b/lib/gitlab/changes_list.rb
@@ -0,0 +1,25 @@
+module Gitlab
+ class ChangesList
+ include Enumerable
+
+ attr_reader :raw_changes
+
+ def initialize(changes)
+ @raw_changes = changes.kind_of?(String) ? changes.lines : changes
+ end
+
+ def each(&block)
+ changes.each(&block)
+ end
+
+ def changes
+ @changes ||= begin
+ @raw_changes.map do |change|
+ next if change.blank?
+ oldrev, newrev, ref = change.strip.split(' ')
+ { oldrev: oldrev, newrev: newrev, ref: ref }
+ end.compact
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/checks/change_access.rb b/lib/gitlab/checks/change_access.rb
index 5551fac4b8b..52f117e963b 100644
--- a/lib/gitlab/checks/change_access.rb
+++ b/lib/gitlab/checks/change_access.rb
@@ -4,8 +4,8 @@ module Gitlab
attr_reader :user_access, :project
def initialize(change, user_access:, project:)
- @oldrev, @newrev, @ref = change.split(' ')
- @branch_name = branch_name(@ref)
+ @oldrev, @newrev, @ref = change.values_at(:oldrev, :newrev, :ref)
+ @branch_name = Gitlab::Git.branch_name(@ref)
@user_access = user_access
@project = project
end
@@ -47,7 +47,7 @@ module Gitlab
end
def tag_checks
- tag_ref = tag_name(@ref)
+ tag_ref = Gitlab::Git.tag_name(@ref)
if tag_ref && protected_tag?(tag_ref) && user_access.cannot_do_action?(:admin_project)
"You are not allowed to change existing tags on this project."
@@ -73,24 +73,6 @@ module Gitlab
def matching_merge_request?
Checks::MatchingMergeRequest.new(@newrev, @branch_name, @project).match?
end
-
- def branch_name(ref)
- ref = @ref.to_s
- if Gitlab::Git.branch_ref?(ref)
- Gitlab::Git.ref_name(ref)
- else
- nil
- end
- end
-
- def tag_name(ref)
- ref = @ref.to_s
- if Gitlab::Git.tag_ref?(ref)
- Gitlab::Git.ref_name(ref)
- else
- nil
- end
- end
end
end
end
diff --git a/lib/gitlab/git.rb b/lib/gitlab/git.rb
index 191bea86ac3..7584efe4fa8 100644
--- a/lib/gitlab/git.rb
+++ b/lib/gitlab/git.rb
@@ -9,6 +9,24 @@ module Gitlab
ref.gsub(/\Arefs\/(tags|heads)\//, '')
end
+ def branch_name(ref)
+ ref = ref.to_s
+ if self.branch_ref?(ref)
+ self.ref_name(ref)
+ else
+ nil
+ end
+ end
+
+ def tag_name(ref)
+ ref = ref.to_s
+ if self.tag_ref?(ref)
+ self.ref_name(ref)
+ else
+ nil
+ end
+ end
+
def tag_ref?(ref)
ref.start_with?(TAG_REF_PREFIX)
end
diff --git a/lib/gitlab/git_access.rb b/lib/gitlab/git_access.rb
index 5bc70f530d2..1882eb8d050 100644
--- a/lib/gitlab/git_access.rb
+++ b/lib/gitlab/git_access.rb
@@ -76,10 +76,10 @@ module Gitlab
return build_status_object(false, "A repository for this project does not exist yet.")
end
- changes = changes.lines if changes.kind_of?(String)
+ changes_list = Gitlab::ChangesList.new(changes)
# Iterate over all changes to find if user allowed all of them to be applied
- changes.map(&:strip).reject(&:blank?).each do |change|
+ changes_list.each do |change|
status = change_access_check(change)
unless status.allowed?
# If user does not have access to make at least one change - cancel all push
diff --git a/spec/features/pipelines_spec.rb b/spec/features/projects/pipelines_spec.rb
index f88b8f8e60b..b57652b3ea2 100644
--- a/spec/features/pipelines_spec.rb
+++ b/spec/features/projects/pipelines_spec.rb
@@ -12,7 +12,7 @@ describe "Pipelines" do
end
describe 'GET /:project/pipelines' do
- let!(:pipeline) { create(:ci_pipeline, project: project, ref: 'master', status: 'running') }
+ let!(:pipeline) { create(:ci_empty_pipeline, project: project, ref: 'master', status: 'running') }
[:all, :running, :branches].each do |scope|
context "displaying #{scope}" do
@@ -31,10 +31,10 @@ describe "Pipelines" do
end
context 'cancelable pipeline' do
- let!(:running) { create(:ci_build, :running, pipeline: pipeline, stage: 'test', commands: 'test') }
+ let!(:build) { create(:ci_build, pipeline: pipeline, stage: 'test', commands: 'test') }
before do
- pipeline.reload_status!
+ build.run
visit namespace_project_pipelines_path(project.namespace, project)
end
@@ -50,10 +50,10 @@ describe "Pipelines" do
end
context 'retryable pipelines' do
- let!(:failed) { create(:ci_build, :failed, pipeline: pipeline, stage: 'test', commands: 'test') }
+ let!(:build) { create(:ci_build, pipeline: pipeline, stage: 'test', commands: 'test') }
before do
- pipeline.reload_status!
+ build.drop
visit namespace_project_pipelines_path(project.namespace, project)
end
@@ -87,7 +87,6 @@ describe "Pipelines" do
let!(:running) { create(:generic_commit_status, status: 'running', pipeline: pipeline, stage: 'test') }
before do
- pipeline.reload_status!
visit namespace_project_pipelines_path(project.namespace, project)
end
@@ -101,10 +100,10 @@ describe "Pipelines" do
end
context 'when failed' do
- let!(:failed) { create(:generic_commit_status, status: 'failed', pipeline: pipeline, stage: 'test') }
+ let!(:status) { create(:generic_commit_status, :pending, pipeline: pipeline, stage: 'test') }
before do
- pipeline.reload_status!
+ status.drop
visit namespace_project_pipelines_path(project.namespace, project)
end
@@ -206,7 +205,7 @@ describe "Pipelines" do
before { visit new_namespace_project_pipeline_path(project.namespace, project) }
context 'for valid commit' do
- before { fill_in('Create for', with: 'master') }
+ before { fill_in('pipeline[ref]', with: 'master') }
context 'with gitlab-ci.yml' do
before { stub_ci_pipeline_to_return_yaml_file }
@@ -223,11 +222,37 @@ describe "Pipelines" do
context 'for invalid commit' do
before do
- fill_in('Create for', with: 'invalid-reference')
+ fill_in('pipeline[ref]', with: 'invalid-reference')
click_on 'Create pipeline'
end
it { expect(page).to have_content('Reference not found') }
end
end
+
+ describe 'Create pipelines', feature: true do
+ let(:project) { create(:project) }
+
+ before do
+ visit new_namespace_project_pipeline_path(project.namespace, project)
+ end
+
+ describe 'new pipeline page' do
+ it 'has field to add a new pipeline' do
+ expect(page).to have_field('pipeline[ref]')
+ expect(page).to have_content('Create for')
+ end
+ end
+
+ describe 'find pipelines' do
+ it 'shows filtered pipelines', js: true do
+ fill_in('pipeline[ref]', with: 'fix')
+ find('input#ref').native.send_keys(:keydown)
+
+ within('.ui-autocomplete') do
+ expect(page).to have_selector('li', text: 'fix')
+ end
+ end
+ end
+ end
end
diff --git a/spec/helpers/members_helper_spec.rb b/spec/helpers/members_helper_spec.rb
index f75fdb739f6..7998209b7b0 100644
--- a/spec/helpers/members_helper_spec.rb
+++ b/spec/helpers/members_helper_spec.rb
@@ -9,54 +9,6 @@ describe MembersHelper do
it { expect(action_member_permission(:admin, group_member)).to eq :admin_group_member }
end
- describe '#default_show_roles' do
- let(:user) { double }
- let(:member) { build(:project_member) }
-
- before do
- allow(helper).to receive(:current_user).and_return(user)
- allow(helper).to receive(:can?).with(user, :update_project_member, member).and_return(false)
- allow(helper).to receive(:can?).with(user, :destroy_project_member, member).and_return(false)
- allow(helper).to receive(:can?).with(user, :admin_project_member, member.source).and_return(false)
- end
-
- context 'when the current cannot update, destroy or admin the passed member' do
- it 'returns false' do
- expect(helper.default_show_roles(member)).to be_falsy
- end
- end
-
- context 'when the current can update the passed member' do
- before do
- allow(helper).to receive(:can?).with(user, :update_project_member, member).and_return(true)
- end
-
- it 'returns true' do
- expect(helper.default_show_roles(member)).to be_truthy
- end
- end
-
- context 'when the current can destroy the passed member' do
- before do
- allow(helper).to receive(:can?).with(user, :destroy_project_member, member).and_return(true)
- end
-
- it 'returns true' do
- expect(helper.default_show_roles(member)).to be_truthy
- end
- end
-
- context 'when the current can admin the passed member source' do
- before do
- allow(helper).to receive(:can?).with(user, :admin_project_member, member.source).and_return(true)
- end
-
- it 'returns true' do
- expect(helper.default_show_roles(member)).to be_truthy
- end
- end
- end
-
describe '#remove_member_message' do
let(:requester) { build(:user) }
let(:project) { create(:project) }
diff --git a/spec/lib/ci/charts_spec.rb b/spec/lib/ci/charts_spec.rb
index 2cd6b00dad6..fb6cc398307 100644
--- a/spec/lib/ci/charts_spec.rb
+++ b/spec/lib/ci/charts_spec.rb
@@ -2,22 +2,23 @@ require 'spec_helper'
describe Ci::Charts, lib: true do
context "build_times" do
+ let(:project) { create(:empty_project) }
+ let(:chart) { Ci::Charts::BuildTime.new(project) }
+
+ subject { chart.build_times }
+
before do
- @pipeline = FactoryGirl.create(:ci_pipeline)
- FactoryGirl.create(:ci_build, pipeline: @pipeline)
- @pipeline.reload_status!
+ create(:ci_empty_pipeline, project: project, duration: 120)
end
it 'returns build times in minutes' do
- chart = Ci::Charts::BuildTime.new(@pipeline.project)
- expect(chart.build_times).to eq([2])
+ is_expected.to contain_exactly(2)
end
it 'handles nil build times' do
- create(:ci_pipeline, duration: nil, project: @pipeline.project)
+ create(:ci_empty_pipeline, project: project, duration: nil)
- chart = Ci::Charts::BuildTime.new(@pipeline.project)
- expect(chart.build_times).to eq([2, 0])
+ is_expected.to contain_exactly(2, 0)
end
end
end
diff --git a/spec/lib/gitlab/changes_list_spec.rb b/spec/lib/gitlab/changes_list_spec.rb
new file mode 100644
index 00000000000..69d86144e32
--- /dev/null
+++ b/spec/lib/gitlab/changes_list_spec.rb
@@ -0,0 +1,30 @@
+require "spec_helper"
+
+describe Gitlab::ChangesList do
+ let(:valid_changes_string) { "\n000000 570e7b2 refs/heads/my_branch\nd14d6c 6fd24d refs/heads/master" }
+ let(:invalid_changes) { 1 }
+
+ context 'when changes is a valid string' do
+ let(:changes_list) { Gitlab::ChangesList.new(valid_changes_string) }
+
+ it 'splits elements by newline character' do
+ expect(changes_list).to contain_exactly({
+ oldrev: "000000",
+ newrev: "570e7b2",
+ ref: "refs/heads/my_branch"
+ }, {
+ oldrev: "d14d6c",
+ newrev: "6fd24d",
+ ref: "refs/heads/master"
+ })
+ end
+
+ it 'behaves like a list' do
+ expect(changes_list.first).to eq({
+ oldrev: "000000",
+ newrev: "570e7b2",
+ ref: "refs/heads/my_branch"
+ })
+ end
+ end
+end
diff --git a/spec/models/ci/pipeline_spec.rb b/spec/models/ci/pipeline_spec.rb
index 2266b954aeb..9c5d56fe5bb 100644
--- a/spec/models/ci/pipeline_spec.rb
+++ b/spec/models/ci/pipeline_spec.rb
@@ -2,7 +2,7 @@ require 'spec_helper'
describe Ci::Pipeline, models: true do
let(:project) { FactoryGirl.create :empty_project }
- let(:pipeline) { FactoryGirl.create :ci_empty_pipeline, status: 'created', project: project }
+ let(:pipeline) { FactoryGirl.create :ci_empty_pipeline, project: project }
it { is_expected.to belong_to(:project) }
it { is_expected.to belong_to(:user) }
@@ -53,25 +53,6 @@ describe Ci::Pipeline, models: true do
end
end
- describe "#finished_at" do
- let(:pipeline) { FactoryGirl.create :ci_pipeline }
-
- it "returns finished_at of latest build" do
- build = FactoryGirl.create :ci_build, pipeline: pipeline, finished_at: Time.now - 60
- FactoryGirl.create :ci_build, pipeline: pipeline, finished_at: Time.now - 120
- pipeline.reload_status!
-
- expect(pipeline.finished_at.to_i).to eq(build.finished_at.to_i)
- end
-
- it "returns nil if there is no finished build" do
- FactoryGirl.create :ci_not_started_build, pipeline: pipeline
- pipeline.reload_status!
-
- expect(pipeline.finished_at).to be_nil
- end
- end
-
describe "coverage" do
let(:project) { FactoryGirl.create :empty_project, build_coverage_regex: "/.*/" }
let(:pipeline) { FactoryGirl.create :ci_empty_pipeline, project: project }
@@ -141,32 +122,47 @@ describe Ci::Pipeline, models: true do
end
end
- describe '#reload_status!' do
- let(:pipeline) { create :ci_empty_pipeline, project: project }
+ describe 'state machine' do
+ let(:current) { Time.now.change(usec: 0) }
+ let(:build) { create :ci_build, name: 'build1', pipeline: pipeline, started_at: current - 60, finished_at: current }
+ let(:build2) { create :ci_build, name: 'build2', pipeline: pipeline, started_at: current - 60, finished_at: current }
- context 'dependent objects' do
- let(:commit_status) { create :commit_status, :pending, pipeline: pipeline }
+ describe '#duration' do
+ before do
+ build.skip
+ build2.skip
+ end
- it 'executes reload_status! after succeeding dependent object' do
- expect(pipeline).to receive(:reload_status!).and_return(true)
+ it 'matches sum of builds duration' do
+ expect(pipeline.reload.duration).to eq(build.duration + build2.duration)
+ end
+ end
- commit_status.success
+ describe '#started_at' do
+ it 'updates on transitioning to running' do
+ build.run
+
+ expect(pipeline.reload.started_at).not_to be_nil
+ end
+
+ it 'do not update on transitioning to success' do
+ build.success
+
+ expect(pipeline.reload.started_at).to be_nil
end
end
- context 'updates' do
- let(:current) { Time.now.change(usec: 0) }
- let(:build) { FactoryGirl.create :ci_build, pipeline: pipeline, started_at: current - 120, finished_at: current - 60 }
+ describe '#finished_at' do
+ it 'updates on transitioning to success' do
+ build.success
- before do
- build
- pipeline.reload_status!
+ expect(pipeline.reload.finished_at).not_to be_nil
end
- [:status, :started_at, :finished_at, :duration].each do |param|
- it "#{param}" do
- expect(pipeline.send(param)).to eq(build.send(param))
- end
+ it 'do not update on transitioning to running' do
+ build.run
+
+ expect(pipeline.reload.finished_at).to be_nil
end
end
end
diff --git a/spec/requests/api/builds_spec.rb b/spec/requests/api/builds_spec.rb
index a4cdd8f3140..41503885dd9 100644
--- a/spec/requests/api/builds_spec.rb
+++ b/spec/requests/api/builds_spec.rb
@@ -9,7 +9,7 @@ describe API::API, api: true do
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!(:pipeline) { create(:ci_empty_pipeline, project: project, sha: project.commit.id, ref: project.default_branch) }
let!(:build) { create(:ci_build, pipeline: pipeline) }
describe 'GET /projects/:id/builds ' do
@@ -174,7 +174,11 @@ describe API::API, api: true do
describe 'GET /projects/:id/artifacts/:ref_name/download?job=name' do
let(:api_user) { reporter.user }
- let(:build) { create(:ci_build, :success, :artifacts, pipeline: pipeline) }
+ let(:build) { create(:ci_build, :artifacts, pipeline: pipeline) }
+
+ before do
+ build.success
+ end
def path_for_ref(ref = pipeline.ref, job = build.name)
api("/projects/#{project.id}/builds/artifacts/#{ref}/download?job=#{job}", api_user)
@@ -238,10 +242,6 @@ describe API::API, api: true do
it { expect(response.headers).to include(download_headers) }
end
- before do
- pipeline.reload_status!
- end
-
context 'with regular branch' do
before do
pipeline.update(ref: 'master',
diff --git a/spec/requests/api/internal_spec.rb b/spec/requests/api/internal_spec.rb
index f6f85d6e95e..be52f88831f 100644
--- a/spec/requests/api/internal_spec.rb
+++ b/spec/requests/api/internal_spec.rb
@@ -275,6 +275,24 @@ describe API::API, api: true do
end
end
+ describe 'GET /internal/merge_request_urls' do
+ let(:repo_name) { "#{project.namespace.name}/#{project.path}" }
+ let(:changes) { URI.escape("#{Gitlab::Git::BLANK_SHA} 570e7b2abdd848b95f2f578043fc23bd6f6fd24d refs/heads/new_branch") }
+
+ before do
+ project.team << [user, :developer]
+ get api("/internal/merge_request_urls?project=#{repo_name}&changes=#{changes}"), secret_token: secret_token
+ end
+
+ it 'returns link to create new merge request' do
+ expect(json_response).to match [{
+ "branch_name" => "new_branch",
+ "url" => "http://localhost/#{project.namespace.name}/#{project.path}/merge_requests/new?merge_request%5Bsource_branch%5D=new_branch",
+ "new_merge_request" => true
+ }]
+ end
+ end
+
def pull(key, project, protocol = 'ssh')
post(
api("/internal/allowed"),
diff --git a/spec/routing/project_routing_spec.rb b/spec/routing/project_routing_spec.rb
index b941e78f983..77842057a10 100644
--- a/spec/routing/project_routing_spec.rb
+++ b/spec/routing/project_routing_spec.rb
@@ -60,7 +60,7 @@ end
# project GET /:id(.:format) projects#show
# PUT /:id(.:format) projects#update
# DELETE /:id(.:format) projects#destroy
-# markdown_preview_project POST /:id/markdown_preview(.:format) projects#markdown_preview
+# preview_markdown_project POST /:id/preview_markdown(.:format) projects#preview_markdown
describe ProjectsController, 'routing' do
it 'to #create' do
expect(post('/projects')).to route_to('projects#create')
@@ -91,9 +91,9 @@ describe ProjectsController, 'routing' do
expect(delete('/gitlab/gitlabhq')).to route_to('projects#destroy', namespace_id: 'gitlab', id: 'gitlabhq')
end
- it 'to #markdown_preview' do
- expect(post('/gitlab/gitlabhq/markdown_preview')).to(
- route_to('projects#markdown_preview', namespace_id: 'gitlab', id: 'gitlabhq')
+ it 'to #preview_markdown' do
+ expect(post('/gitlab/gitlabhq/preview_markdown')).to(
+ route_to('projects#preview_markdown', namespace_id: 'gitlab', id: 'gitlabhq')
)
end
end
diff --git a/spec/services/ci/image_for_build_service_spec.rb b/spec/services/ci/image_for_build_service_spec.rb
index 259062406c7..c931c3e4829 100644
--- a/spec/services/ci/image_for_build_service_spec.rb
+++ b/spec/services/ci/image_for_build_service_spec.rb
@@ -14,7 +14,6 @@ module Ci
context 'branch name' do
before { allow(project).to receive(:commit).and_return(OpenStruct.new(sha: commit_sha)) }
before { build.run! }
- before { pipeline.reload_status! }
let(:image) { service.execute(project, ref: 'master') }
it { expect(image).to be_kind_of(OpenStruct) }
@@ -32,7 +31,6 @@ module Ci
context 'commit sha' do
before { build.run! }
- before { pipeline.reload_status! }
let(:image) { service.execute(project, sha: build.sha) }
it { expect(image).to be_kind_of(OpenStruct) }
diff --git a/spec/services/merge_requests/get_urls_service_spec.rb b/spec/services/merge_requests/get_urls_service_spec.rb
new file mode 100644
index 00000000000..ec26770c3eb
--- /dev/null
+++ b/spec/services/merge_requests/get_urls_service_spec.rb
@@ -0,0 +1,100 @@
+require "spec_helper"
+
+describe MergeRequests::GetUrlsService do
+ let(:project) { create(:project, :public) }
+ let(:service) { MergeRequests::GetUrlsService.new(project) }
+ let(:source_branch) { "my_branch" }
+ let(:new_merge_request_url) { "http://localhost/#{project.namespace.name}/#{project.path}/merge_requests/new?merge_request%5Bsource_branch%5D=#{source_branch}" }
+ let(:show_merge_request_url) { "http://localhost/#{project.namespace.name}/#{project.path}/merge_requests/#{merge_request.iid}" }
+ let(:new_branch_changes) { "#{Gitlab::Git::BLANK_SHA} 570e7b2abdd848b95f2f578043fc23bd6f6fd24d refs/heads/#{source_branch}" }
+ let(:existing_branch_changes) { "d14d6c0abdd253381df51a723d58691b2ee1ab08 570e7b2abdd848b95f2f578043fc23bd6f6fd24d refs/heads/#{source_branch}" }
+
+ describe "#execute" do
+ shared_examples 'new_merge_request_link' do
+ it 'returns url to create new merge request' do
+ result = service.execute(changes)
+ expect(result).to match([{
+ branch_name: source_branch,
+ url: new_merge_request_url,
+ new_merge_request: true
+ }])
+ end
+ end
+
+ shared_examples 'show_merge_request_url' do
+ it 'returns url to view merge request' do
+ result = service.execute(changes)
+ expect(result).to match([{
+ branch_name: source_branch,
+ url: show_merge_request_url,
+ new_merge_request: false
+ }])
+ end
+ end
+
+ context 'pushing one completely new branch' do
+ let(:changes) { new_branch_changes }
+ it_behaves_like 'new_merge_request_link'
+ end
+
+ context 'pushing to existing branch but no merge request' do
+ let(:changes) { existing_branch_changes }
+ it_behaves_like 'new_merge_request_link'
+ end
+
+ context 'pushing to existing branch and merge request opened' do
+ let!(:merge_request) { create(:merge_request, source_project: project, source_branch: source_branch) }
+ let(:changes) { existing_branch_changes }
+ it_behaves_like 'show_merge_request_url'
+ end
+
+ context 'pushing to existing branch and merge request is reopened' do
+ let!(:merge_request) { create(:merge_request, :reopened, source_project: project, source_branch: source_branch) }
+ let(:changes) { existing_branch_changes }
+ it_behaves_like 'show_merge_request_url'
+ end
+
+ context 'pushing to existing branch from forked project' do
+ let(:user) { create(:user) }
+ let!(:forked_project) { Projects::ForkService.new(project, user).execute }
+ let!(:merge_request) { create(:merge_request, source_project: forked_project, target_project: project, source_branch: source_branch) }
+ let(:changes) { existing_branch_changes }
+ # Source project is now the forked one
+ let(:service) { MergeRequests::GetUrlsService.new(forked_project) }
+ it_behaves_like 'show_merge_request_url'
+ end
+
+ context 'pushing to existing branch and merge request is closed' do
+ let!(:merge_request) { create(:merge_request, :closed, source_project: project, source_branch: source_branch) }
+ let(:changes) { existing_branch_changes }
+ it_behaves_like 'new_merge_request_link'
+ end
+
+ context 'pushing to existing branch and merge request is merged' do
+ let!(:merge_request) { create(:merge_request, :merged, source_project: project, source_branch: source_branch) }
+ let(:changes) { existing_branch_changes }
+ it_behaves_like 'new_merge_request_link'
+ end
+
+ context 'pushing new branch and existing branch (with merge request created) at once' do
+ let!(:merge_request) { create(:merge_request, source_project: project, source_branch: "existing_branch") }
+ let(:new_branch_changes) { "#{Gitlab::Git::BLANK_SHA} 570e7b2abdd848b95f2f578043fc23bd6f6fd24d refs/heads/new_branch" }
+ let(:existing_branch_changes) { "d14d6c0abdd253381df51a723d58691b2ee1ab08 570e7b2abdd848b95f2f578043fc23bd6f6fd24d refs/heads/existing_branch" }
+ let(:changes) { "#{new_branch_changes}\n#{existing_branch_changes}" }
+ let(:new_merge_request_url) { "http://localhost/#{project.namespace.name}/#{project.path}/merge_requests/new?merge_request%5Bsource_branch%5D=new_branch" }
+
+ it 'returns 2 urls for both creating new and showing merge request' do
+ result = service.execute(changes)
+ expect(result).to match([{
+ branch_name: "new_branch",
+ url: new_merge_request_url,
+ new_merge_request: true
+ }, {
+ branch_name: "existing_branch",
+ url: show_merge_request_url,
+ new_merge_request: false
+ }])
+ end
+ end
+ end
+end