Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJames Lopez <james@jameslopez.es>2016-02-12 14:21:04 +0300
committerJames Lopez <james@jameslopez.es>2016-02-12 14:21:04 +0300
commita5b011c9d8586453d37852856822dab692f6613b (patch)
treef3400cff867007d9962e6fd31e0a94d460db1b88
parent3753c1e03edb516033b4ef856aed63668de59cf3 (diff)
parentb1dda8145433f15fcea683451c9c79927b19352e (diff)
Merge branch 'master' of gitlab.com:gitlab-org/gitlab-ce into fix/cross-reference-notes-forks
-rw-r--r--.gitlab-ci.yml46
-rw-r--r--CHANGELOG8
-rw-r--r--CONTRIBUTING.md1
-rw-r--r--GITLAB_WORKHORSE_VERSION2
-rw-r--r--app/controllers/ci/projects_controller.rb6
-rw-r--r--app/controllers/projects/badges_controller.rb11
-rw-r--r--app/controllers/projects/builds_controller.rb15
-rw-r--r--app/controllers/projects/commits_controller.rb3
-rw-r--r--app/controllers/projects/compare_controller.rb23
-rw-r--r--app/controllers/projects/milestones_controller.rb11
-rw-r--r--app/helpers/issues_helper.rb6
-rw-r--r--app/helpers/projects_helper.rb4
-rw-r--r--app/models/application_setting.rb4
-rw-r--r--app/models/concerns/issuable.rb5
-rw-r--r--app/models/email.rb2
-rw-r--r--app/models/member.rb1
-rw-r--r--app/models/merge_request.rb1
-rw-r--r--app/models/repository.rb3
-rw-r--r--app/models/user.rb7
-rw-r--r--app/services/ci/image_for_build_service.rb19
-rw-r--r--app/validators/email_validator.rb15
-rw-r--r--app/views/projects/commits/show.html.haml5
-rw-r--r--app/views/projects/compare/_form.html.haml5
-rw-r--r--app/views/projects/forks/index.html.haml17
-rw-r--r--config/routes.rb8
-rw-r--r--db/fixtures/development/14_builds.rb39
-rw-r--r--doc/api/builds.md68
-rw-r--r--doc/api/merge_requests.md64
-rw-r--r--doc/ci/docker/using_docker_images.md2
-rw-r--r--doc/ci/quick_start/README.md8
-rw-r--r--doc/install/installation.md2
-rw-r--r--doc/markdown/img/logo.pngbin0 -> 11097 bytes
-rw-r--r--doc/markdown/markdown.md8
-rw-r--r--doc/update/8.4-to-8.5.md16
-rw-r--r--doc/web_hooks/web_hooks.md26
-rw-r--r--features/project/badges/build.feature22
-rw-r--r--features/project/commits/commits.feature36
-rw-r--r--features/steps/project/badges/build.rb28
-rw-r--r--features/steps/project/commits/commits.rb57
-rw-r--r--features/steps/shared/builds.rb16
-rw-r--r--lib/api/merge_requests.rb19
-rw-r--r--lib/gitlab/blame.rb1
-rw-r--r--lib/tasks/gitlab/check.rake18
-rwxr-xr-xscripts/prepare_build.sh12
-rw-r--r--spec/models/application_setting_spec.rb4
-rw-r--r--spec/models/concerns/issuable_spec.rb10
-rw-r--r--spec/models/email_spec.rb22
-rw-r--r--spec/models/member_spec.rb6
-rw-r--r--spec/models/repository_spec.rb6
-rw-r--r--spec/models/user_spec.rb36
-rw-r--r--spec/requests/api/merge_requests_spec.rb37
-rw-r--r--spec/support/email_format_shared_examples.rb44
52 files changed, 622 insertions, 213 deletions
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 5dfeb8a1f90..1c4d98ea3f6 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -5,6 +5,11 @@ services:
- postgres:latest
- redis:latest
+cache:
+ key: "ruby22"
+ paths:
+ - vendor
+
variables:
MYSQL_ALLOW_EMPTY_PASSWORD: "1"
@@ -144,6 +149,10 @@ spec:feature:ruby21:
script:
- RAILS_ENV=test bundle exec rake assets:precompile 2>/dev/null
- RAILS_ENV=test SIMPLECOV=true bundle exec rake spec:feature
+ cache:
+ key: "ruby21"
+ paths:
+ - vendor
tags:
- ruby
- mysql
@@ -154,6 +163,10 @@ spec:api:ruby21:
- master
script:
- RAILS_ENV=test SIMPLECOV=true bundle exec rake spec:api
+ cache:
+ key: "ruby21"
+ paths:
+ - vendor
tags:
- ruby
- mysql
@@ -164,6 +177,10 @@ spec:models:ruby21:
- master
script:
- RAILS_ENV=test SIMPLECOV=true bundle exec rake spec:models
+ cache:
+ key: "ruby21"
+ paths:
+ - vendor
tags:
- ruby
- mysql
@@ -174,6 +191,10 @@ spec:lib:ruby21:
- master
script:
- RAILS_ENV=test SIMPLECOV=true bundle exec rake spec:lib
+ cache:
+ key: "ruby21"
+ paths:
+ - vendor
tags:
- ruby
- mysql
@@ -184,6 +205,10 @@ spec:services:ruby21:
- master
script:
- RAILS_ENV=test SIMPLECOV=true bundle exec rake spec:services
+ cache:
+ key: "ruby21"
+ paths:
+ - vendor
tags:
- ruby
- mysql
@@ -194,6 +219,10 @@ spec:benchmark:ruby21:
- master
script:
- RAILS_ENV=test bundle exec rake spec:benchmark
+ cache:
+ key: "ruby21"
+ paths:
+ - vendor
tags:
- ruby
- mysql
@@ -205,6 +234,10 @@ spec:other:ruby21:
- master
script:
- RAILS_ENV=test SIMPLECOV=true bundle exec rake spec:other
+ cache:
+ key: "ruby21"
+ paths:
+ - vendor
tags:
- ruby
- mysql
@@ -215,6 +248,10 @@ spinach:project:half:ruby21:
- master
script:
- RAILS_ENV=test SIMPLECOV=true bundle exec rake spinach:project:half
+ cache:
+ key: "ruby21"
+ paths:
+ - vendor
tags:
- ruby
- mysql
@@ -225,6 +262,10 @@ spinach:project:rest:ruby21:
- master
script:
- RAILS_ENV=test SIMPLECOV=true bundle exec rake spinach:project:rest
+ cache:
+ key: "ruby21"
+ paths:
+ - vendor
tags:
- ruby
- mysql
@@ -235,6 +276,11 @@ spinach:other:ruby21:
- master
script:
- RAILS_ENV=test SIMPLECOV=true bundle exec rake spinach:other
+ cache:
+ key: "ruby21"
+ paths:
+ - vendor
tags:
- ruby
- mysql
+
diff --git a/CHANGELOG b/CHANGELOG
index c39588e978e..164e9c4d82e 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -14,11 +14,13 @@ v 8.5.0 (unreleased)
- New UI for pagination
- Don't prevent sign out when 2FA enforcement is enabled and user hasn't yet
set it up
+ - API: Added "merge_requests/:merge_request_id/closes_issues" (Gal Schlezinger)
- Fix diff comments loaded by AJAX to load comment with diff in discussion tab
- Whitelist raw "abbr" elements when parsing Markdown (Benedict Etzel)
- Fix label links for a merge request pointing to issues list
- Don't vendor minified JS
- Increase project import timeout to 15 minutes
+ - Be more permissive with email address validation: it only has to contain a single '@'
- Display 404 error on group not found
- Track project import failure
- Support Two-factor Authentication for LDAP users
@@ -31,12 +33,14 @@ v 8.5.0 (unreleased)
- Optimized performance of finding issues to be closed by a merge request
- API: Expose MergeRequest#merge_status (Andrei Dziahel)
- Revert "Add IP check against DNSBLs at account sign-up"
+ - Actually use the `skip_merges` option in Repository#commits (Tony Chu)
- Fix API to keep request parameters in Link header (Michael Potthoff)
- Deprecate API "merge_request/:merge_request_id/comments". Use "merge_requests/:merge_request_id/notes" instead
- Deprecate API "merge_request/:merge_request_id/...". Use "merge_requests/:merge_request_id/..." instead
- Prevent parse error when name of project ends with .atom and prevent path issues
- Mark inline difference between old and new paths when a file is renamed
- Support Akismet spam checking for creation of issues via API (Stan Hu)
+ - API: Allow to set or update a merge-request's milestone (Kirill Skachkov)
- Improve UI consistency between projects and groups lists
- Add sort dropdown to dashboard projects page
- Fixed logo animation on Safari (Roman Rott)
@@ -47,11 +51,14 @@ v 8.5.0 (unreleased)
- Faster snippet search
- Title for milestones should be unique (Zeger-Jan van de Weg)
- Validate correctness of maximum attachment size application setting
+ - Replaces "Create merge request" link with one to the "Merge Request" when one exists
+ - Fix CI builds badge, add a new link to builds badge, deprecate the old one
v 8.4.4
- Update omniauth-saml gem to 1.4.2
- Prevent long-running backup tasks from timing out the database connection
- Add a Project setting to allow guests to view build logs (defaults to true)
+ - Sort project milestones by due date including issue editor (Oliver Rogers / Orih)
v 8.4.3
- Increase lfs_objects size column to 8-byte integer to allow files larger
@@ -387,6 +394,7 @@ v 8.1.0
- Improved performance of the trending projects page
- Remove CI migration task
- Improved performance of finding projects by their namespace
+ - Add assignee data to Issuables' hook_data (Bram Daams)
- Fix bug where transferring a project would result in stale commit links (Stan Hu)
- Fix build trace updating
- Include full path of source and target branch names in New Merge Request page (Stan Hu)
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 263f98b1e57..c4522998f42 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -364,6 +364,7 @@ corresponding merge request should be updated to have the following:
This makes it easier for release managers to keep track of what still has to be
merged and where changes have to be merged into.
+Like all merge requests the target should be master so all bugfixes are in master.
## Definition of done
diff --git a/GITLAB_WORKHORSE_VERSION b/GITLAB_WORKHORSE_VERSION
index 844f6a91acb..d2b13eb644d 100644
--- a/GITLAB_WORKHORSE_VERSION
+++ b/GITLAB_WORKHORSE_VERSION
@@ -1 +1 @@
-0.6.3
+0.6.4
diff --git a/app/controllers/ci/projects_controller.rb b/app/controllers/ci/projects_controller.rb
index 711c2847d5e..d1824b481d7 100644
--- a/app/controllers/ci/projects_controller.rb
+++ b/app/controllers/ci/projects_controller.rb
@@ -12,9 +12,13 @@ module Ci
# Project status badge
# Image with build status for sha or ref
+ #
+ # This action in DEPRECATED, this is here only for backwards compatibility
+ # with projects migrated from GitLab CI.
+ #
def badge
+ return render_404 unless @project
image = Ci::ImageForBuildService.new.execute(@project, params)
-
send_file image.path, filename: image.name, disposition: 'inline', type:"image/svg+xml"
end
diff --git a/app/controllers/projects/badges_controller.rb b/app/controllers/projects/badges_controller.rb
new file mode 100644
index 00000000000..a4dd94b941c
--- /dev/null
+++ b/app/controllers/projects/badges_controller.rb
@@ -0,0 +1,11 @@
+class Projects::BadgesController < Projects::ApplicationController
+ def build
+ respond_to do |format|
+ format.html { render_404 }
+ format.svg do
+ image = Ci::ImageForBuildService.new.execute(project, ref: params[:ref])
+ send_file(image.path, filename: image.name, disposition: 'inline', type: 'image/svg+xml')
+ end
+ end
+ end
+end
diff --git a/app/controllers/projects/builds_controller.rb b/app/controllers/projects/builds_controller.rb
index 9e89296e71d..ec379c53b8f 100644
--- a/app/controllers/projects/builds_controller.rb
+++ b/app/controllers/projects/builds_controller.rb
@@ -1,10 +1,8 @@
class Projects::BuildsController < Projects::ApplicationController
before_action :build, except: [:index, :cancel_all]
-
before_action :authorize_read_build!, except: [:cancel, :cancel_all, :retry]
before_action :authorize_update_build!, except: [:index, :show, :status]
-
- layout "project"
+ layout 'project'
def index
@scope = params[:scope]
@@ -24,7 +22,6 @@ class Projects::BuildsController < Projects::ApplicationController
def cancel_all
@project.builds.running_or_pending.each(&:cancel)
-
redirect_to namespace_project_builds_path(project.namespace, project)
end
@@ -47,20 +44,18 @@ class Projects::BuildsController < Projects::ApplicationController
end
build = Ci::Build.retry(@build)
-
redirect_to build_path(build)
end
- def status
- render json: @build.to_json(only: [:status, :id, :sha, :coverage], methods: :sha)
- end
-
def cancel
@build.cancel
-
redirect_to build_path(@build)
end
+ def status
+ render json: @build.to_json(only: [:status, :id, :sha, :coverage], methods: :sha)
+ end
+
private
def build
diff --git a/app/controllers/projects/commits_controller.rb b/app/controllers/projects/commits_controller.rb
index bf5b54c8cb7..1420b96840c 100644
--- a/app/controllers/projects/commits_controller.rb
+++ b/app/controllers/projects/commits_controller.rb
@@ -21,6 +21,9 @@ class Projects::CommitsController < Projects::ApplicationController
@note_counts = project.notes.where(commit_id: @commits.map(&:id)).
group(:commit_id).count
+ @merge_request = @project.merge_requests.opened.
+ find_by(source_project: @project, source_branch: @ref, target_branch: @repository.root_ref)
+
respond_to do |format|
format.html
format.json { pager_json("projects/commits/_commits", @commits.size) }
diff --git a/app/controllers/projects/compare_controller.rb b/app/controllers/projects/compare_controller.rb
index 7bbe75b3974..dc5d217f3e4 100644
--- a/app/controllers/projects/compare_controller.rb
+++ b/app/controllers/projects/compare_controller.rb
@@ -4,24 +4,23 @@ class Projects::CompareController < Projects::ApplicationController
# Authorize
before_action :require_non_empty_project
before_action :authorize_download_code!
+ before_action :assign_ref_vars, only: [:index, :show]
+ before_action :merge_request, only: [:index, :show]
def index
- @ref = Addressable::URI.unescape(params[:to])
end
def show
- base_ref = Addressable::URI.unescape(params[:from])
- @ref = head_ref = Addressable::URI.unescape(params[:to])
diff_options = { ignore_whitespace_change: true } if params[:w] == '1'
compare_result = CompareService.new.
- execute(@project, head_ref, @project, base_ref, diff_options)
+ execute(@project, @head_ref, @project, @base_ref, diff_options)
if compare_result
@commits = Commit.decorate(compare_result.commits, @project)
@diffs = compare_result.diffs
- @commit = @project.commit(head_ref)
- @base_commit = @project.merge_base_commit(base_ref, head_ref)
+ @commit = @project.commit(@head_ref)
+ @base_commit = @project.merge_base_commit(@base_ref, @head_ref)
@diff_refs = [@base_commit, @commit]
@line_notes = []
end
@@ -31,4 +30,16 @@ class Projects::CompareController < Projects::ApplicationController
redirect_to namespace_project_compare_path(@project.namespace, @project,
params[:from], params[:to])
end
+
+ private
+
+ def assign_ref_vars
+ @base_ref = Addressable::URI.unescape(params[:from])
+ @ref = @head_ref = Addressable::URI.unescape(params[:to])
+ end
+
+ def merge_request
+ @merge_request ||= @project.merge_requests.opened.
+ find_by(source_project: @project, source_branch: @head_ref, target_branch: @base_ref)
+ end
end
diff --git a/app/controllers/projects/milestones_controller.rb b/app/controllers/projects/milestones_controller.rb
index 15506bd677a..a5c4ef1c7c7 100644
--- a/app/controllers/projects/milestones_controller.rb
+++ b/app/controllers/projects/milestones_controller.rb
@@ -11,11 +11,12 @@ class Projects::MilestonesController < Projects::ApplicationController
respond_to :html
def index
- @milestones = case params[:state]
- when 'all'; @project.milestones.order("state, due_date DESC")
- when 'closed'; @project.milestones.closed.order("due_date DESC")
- else @project.milestones.active.order("due_date ASC")
- end
+ @milestones =
+ case params[:state]
+ when 'all' then @project.milestones.reorder(due_date: :desc, title: :asc)
+ when 'closed' then @project.milestones.closed.reorder(due_date: :desc, title: :asc)
+ else @project.milestones.active.reorder(due_date: :asc, title: :asc)
+ end
@milestones = @milestones.includes(:project)
@milestones = @milestones.page(params[:page]).per(PER_PAGE)
diff --git a/app/helpers/issues_helper.rb b/app/helpers/issues_helper.rb
index 43262d579e9..ae4ebc0854a 100644
--- a/app/helpers/issues_helper.rb
+++ b/app/helpers/issues_helper.rb
@@ -44,14 +44,14 @@ module IssuesHelper
end
def bulk_update_milestone_options
- milestones = project_active_milestones.to_a
+ milestones = @project.milestones.active.reorder(due_date: :asc, title: :asc).to_a
milestones.unshift(Milestone::None)
options_from_collection_for_select(milestones, 'id', 'title', params[:milestone_id])
end
def milestone_options(object)
- milestones = object.project.milestones.active.to_a
+ milestones = object.project.milestones.active.reorder(due_date: :asc, title: :asc).to_a
milestones.unshift(Milestone::None)
options_from_collection_for_select(milestones, 'id', 'title', object.milestone_id)
@@ -69,7 +69,7 @@ module IssuesHelper
end
end
- def issue_button_visibility(issue, closed)
+ def issue_button_visibility(issue, closed)
return 'hidden' if issue.closed? == closed
end
diff --git a/app/helpers/projects_helper.rb b/app/helpers/projects_helper.rb
index cc1c61e9ec0..d6fb629b0c2 100644
--- a/app/helpers/projects_helper.rb
+++ b/app/helpers/projects_helper.rb
@@ -98,10 +98,6 @@ module ProjectsHelper
project_nav_tabs.include? name
end
- def project_active_milestones
- @project.milestones.active.order("due_date, title ASC")
- end
-
def project_for_deploy_key(deploy_key)
if deploy_key.projects.include?(@project)
@project
diff --git a/app/models/application_setting.rb b/app/models/application_setting.rb
index fa48fe5b9e4..269056e0e77 100644
--- a/app/models/application_setting.rb
+++ b/app/models/application_setting.rb
@@ -71,8 +71,8 @@ class ApplicationSetting < ActiveRecord::Base
url: true
validates :admin_notification_email,
- allow_blank: true,
- email: true
+ email: true,
+ allow_blank: true
validates :two_factor_grace_period,
numericality: { greater_than_or_equal_to: 0 }
diff --git a/app/models/concerns/issuable.rb b/app/models/concerns/issuable.rb
index 04650a9e67a..cf6aa592e2a 100644
--- a/app/models/concerns/issuable.rb
+++ b/app/models/concerns/issuable.rb
@@ -126,7 +126,7 @@ module Issuable
end
def to_hook_data(user)
- {
+ hook_data = {
object_kind: self.class.name.underscore,
user: user.hook_attrs,
repository: {
@@ -137,6 +137,9 @@ module Issuable
},
object_attributes: hook_attrs
}
+ hook_data.merge!(assignee: assignee.hook_attrs) if assignee
+
+ hook_data
end
def label_names
diff --git a/app/models/email.rb b/app/models/email.rb
index 935705e2ed4..b323d1edd10 100644
--- a/app/models/email.rb
+++ b/app/models/email.rb
@@ -15,7 +15,7 @@ class Email < ActiveRecord::Base
belongs_to :user
validates :user_id, presence: true
- validates :email, presence: true, email: { strict_mode: true }, uniqueness: true
+ validates :email, presence: true, uniqueness: true, email: true
validate :unique_email, if: ->(email) { email.email_changed? }
before_validation :cleanup_email
diff --git a/app/models/member.rb b/app/models/member.rb
index 34efcd0088d..ca08007b7eb 100644
--- a/app/models/member.rb
+++ b/app/models/member.rb
@@ -39,7 +39,6 @@ class Member < ActiveRecord::Base
if: :invite?
},
email: {
- strict_mode: true,
allow_nil: true
},
uniqueness: {
diff --git a/app/models/merge_request.rb b/app/models/merge_request.rb
index ddc476447ca..345b9a26d4e 100644
--- a/app/models/merge_request.rb
+++ b/app/models/merge_request.rb
@@ -137,6 +137,7 @@ class MergeRequest < ActiveRecord::Base
scope :by_milestone, ->(milestone) { where(milestone_id: milestone) }
scope :in_projects, ->(project_ids) { where("source_project_id in (:project_ids) OR target_project_id in (:project_ids)", project_ids: project_ids) }
scope :of_projects, ->(ids) { where(target_project_id: ids) }
+ scope :opened, -> { with_state(:opened) }
scope :merged, -> { with_state(:merged) }
scope :closed, -> { with_state(:closed) }
scope :closed_and_merged, -> { with_states(:closed, :merged) }
diff --git a/app/models/repository.rb b/app/models/repository.rb
index 0e17d2b669a..7f0047a002e 100644
--- a/app/models/repository.rb
+++ b/app/models/repository.rb
@@ -84,7 +84,8 @@ class Repository
offset: offset,
# --follow doesn't play well with --skip. See:
# https://gitlab.com/gitlab-org/gitlab-ce/issues/3574#note_3040520
- follow: false
+ follow: false,
+ skip_merges: skip_merges
}
commits = Gitlab::Git::Commit.where(options)
diff --git a/app/models/user.rb b/app/models/user.rb
index 234c1cd89f9..9fe94b13e52 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -146,11 +146,8 @@ class User < ActiveRecord::Base
# Validations
#
validates :name, presence: true
- # Note that a 'uniqueness' and presence check is provided by devise :validatable for email. We do not need to
- # duplicate that here as the validation framework will have duplicate errors in the event of a failure.
- validates :email, presence: true, email: { strict_mode: true }
- validates :notification_email, presence: true, email: { strict_mode: true }
- validates :public_email, presence: true, email: { strict_mode: true }, allow_blank: true, uniqueness: true
+ validates :notification_email, presence: true, email: true
+ validates :public_email, presence: true, uniqueness: true, email: true, allow_blank: true
validates :bio, length: { maximum: 255 }, allow_blank: true
validates :projects_limit, presence: true, numericality: { greater_than_or_equal_to: 0 }
validates :username,
diff --git a/app/services/ci/image_for_build_service.rb b/app/services/ci/image_for_build_service.rb
index f469b13e902..005a5c4661c 100644
--- a/app/services/ci/image_for_build_service.rb
+++ b/app/services/ci/image_for_build_service.rb
@@ -1,28 +1,23 @@
module Ci
class ImageForBuildService
- def execute(project, params)
- sha = params[:sha]
- sha ||=
- if params[:ref]
- project.commit(params[:ref]).try(:sha)
- end
+ def execute(project, opts)
+ sha = opts[:sha] || ref_sha(project, opts[:ref])
commit = project.ci_commits.ordered.find_by(sha: sha)
image_name = image_for_commit(commit)
image_path = Rails.root.join('public/ci', image_name)
-
- OpenStruct.new(
- path: image_path,
- name: image_name
- )
+ OpenStruct.new(path: image_path, name: image_name)
end
private
+ def ref_sha(project, ref)
+ project.commit(ref).try(:sha) if ref
+ end
+
def image_for_commit(commit)
return 'build-unknown.svg' unless commit
-
'build-' + commit.status + ".svg"
end
end
diff --git a/app/validators/email_validator.rb b/app/validators/email_validator.rb
index b35af100803..aab07a7ece4 100644
--- a/app/validators/email_validator.rb
+++ b/app/validators/email_validator.rb
@@ -1,18 +1,5 @@
-# EmailValidator
-#
-# Based on https://github.com/balexand/email_validator
-#
-# Extended to use only strict mode with following allowed characters:
-# ' - apostrophe
-#
-# See http://www.remote.org/jochen/mail/info/chars.html
-#
class EmailValidator < ActiveModel::EachValidator
- PATTERN = /\A\s*([-a-z0-9+._']{1,64})@((?:[-a-z0-9]+\.)+[a-z]{2,})\s*\z/i.freeze
-
def validate_each(record, attribute, value)
- unless value =~ PATTERN
- record.errors.add(attribute, options[:message] || :invalid)
- end
+ record.errors.add(attribute, :invalid) unless value =~ Devise.email_regexp
end
end
diff --git a/app/views/projects/commits/show.html.haml b/app/views/projects/commits/show.html.haml
index ede64d47ab3..c52cf25d40a 100644
--- a/app/views/projects/commits/show.html.haml
+++ b/app/views/projects/commits/show.html.haml
@@ -11,7 +11,10 @@
= render 'shared/ref_switcher', destination: 'commits'
.block-controls.hidden-xs.hidden-sm
- - if create_mr_button?(@repository.root_ref, @ref)
+ - if @merge_request.present?
+ .control
+ = link_to "View Open Merge Request", namespace_project_merge_request_path(@project.namespace, @project, @merge_request), class: 'btn'
+ - elsif create_mr_button?(@repository.root_ref, @ref)
.control
= link_to create_mr_path(@repository.root_ref, @ref), class: 'btn btn-success' do
= icon('plus')
diff --git a/app/views/projects/compare/_form.html.haml b/app/views/projects/compare/_form.html.haml
index efc25eda26b..4ab81f3635c 100644
--- a/app/views/projects/compare/_form.html.haml
+++ b/app/views/projects/compare/_form.html.haml
@@ -13,12 +13,13 @@
= text_field_tag :to, params[:to], class: "form-control", required: true
&nbsp;
= button_tag "Compare", class: "btn btn-create commits-compare-btn"
- - if create_mr_button?
+ - if @merge_request.present?
+ = link_to "View Open Merge Request", namespace_project_merge_request_path(@project.namespace, @project, @merge_request), class: 'prepend-left-10 btn'
+ - elsif create_mr_button?
= link_to create_mr_path, class: 'prepend-left-10 btn' do
= icon("plus")
Create Merge Request
-
:javascript
var availableTags = #{@project.repository.ref_names.to_json};
diff --git a/app/views/projects/forks/index.html.haml b/app/views/projects/forks/index.html.haml
index c834bf63b28..42fa6fdb782 100644
--- a/app/views/projects/forks/index.html.haml
+++ b/app/views/projects/forks/index.html.haml
@@ -29,14 +29,15 @@
= link_to page_filter_path(sort: sort_value_oldest_updated, without: excluded_filters) do
= sort_title_oldest_updated
- - if current_user.already_forked?(@project) && current_user.manageable_namespaces.size < 2
- = link_to namespace_project_path(current_user, current_user.fork_of(@project)), title: 'Go to your fork', class: 'btn btn-new' do
- = icon('code-fork fw')
- Fork
- - else
- = link_to new_namespace_project_fork_path(@project.namespace, @project), title: "Fork project", class: 'btn btn-new' do
- = icon('code-fork fw')
- Fork
+ - if current_user && can?(current_user, :fork_project, @project)
+ - if current_user.already_forked?(@project) && current_user.manageable_namespaces.size < 2
+ = link_to namespace_project_path(current_user, current_user.fork_of(@project)), title: 'Go to your fork', class: 'btn btn-new' do
+ = icon('code-fork fw')
+ Fork
+ - else
+ = link_to new_namespace_project_fork_path(@project.namespace, @project), title: "Fork project", class: 'btn btn-new' do
+ = icon('code-fork fw')
+ Fork
.projects-list-holder
diff --git a/config/routes.rb b/config/routes.rb
index 3f6561a1fe0..507bcbc53d7 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -608,7 +608,7 @@ Rails.application.routes.draw do
resource :variables, only: [:show, :update]
resources :triggers, only: [:index, :create, :destroy]
- resources :builds, only: [:index, :show] do
+ resources :builds, only: [:index, :show], constraints: { id: /\d+/ } do
collection do
post :cancel_all
end
@@ -697,6 +697,12 @@ Rails.application.routes.draw do
end
resources :runner_projects, only: [:create, :destroy]
+ resources :badges, only: [], path: 'badges/*ref',
+ constraints: { ref: Gitlab::Regex.git_reference_regex } do
+ collection do
+ get :build, constraints: { format: /svg/ }
+ end
+ end
end
end
end
diff --git a/db/fixtures/development/14_builds.rb b/db/fixtures/development/14_builds.rb
index 03a12323845..e3ca2b4eea3 100644
--- a/db/fixtures/development/14_builds.rb
+++ b/db/fixtures/development/14_builds.rb
@@ -1,24 +1,13 @@
class Gitlab::Seeder::Builds
- BUILD_STATUSES = %w(running pending success failed canceled)
-
def initialize(project)
@project = project
end
def seed!
ci_commits.each do |ci_commit|
- build = Ci::Build.new(build_attributes_for(ci_commit))
-
- artifacts_cache_file(artifacts_archive_path) do |file|
- build.artifacts_file = file
- end
-
- artifacts_cache_file(artifacts_metadata_path) do |file|
- build.artifacts_metadata = file
- end
-
begin
- build.save!
+ build_create!(ci_commit, name: 'test build 1')
+ build_create!(ci_commit, status: 'success', name: 'test build 2')
print '.'
rescue ActiveRecord::RecordInvalid
print 'F'
@@ -36,6 +25,28 @@ class Gitlab::Seeder::Builds
[]
end
+ def build_create!(ci_commit, opts = {})
+ attributes = build_attributes_for(ci_commit).merge(opts)
+ build = Ci::Build.new(attributes)
+
+ if %w(success failed).include?(build.status)
+ artifacts_cache_file(artifacts_archive_path) do |file|
+ build.artifacts_file = file
+ end
+
+ artifacts_cache_file(artifacts_metadata_path) do |file|
+ build.artifacts_metadata = file
+ end
+ end
+
+ build.save!
+
+ if %w(running success failed).include?(build.status)
+ # We need to set build trace after saving a build (id required)
+ build.trace = FFaker::Lorem.paragraphs(6).join("\n\n")
+ end
+ end
+
def build_attributes_for(ci_commit)
{ name: 'test build', commands: "$ build command",
stage: 'test', stage_idx: 1, ref: 'master',
@@ -49,7 +60,7 @@ class Gitlab::Seeder::Builds
end
def build_status
- BUILD_STATUSES.sample
+ Ci::Build::AVAILABLE_STATUSES.sample
end
def artifacts_archive_path
diff --git a/doc/api/builds.md b/doc/api/builds.md
index 6e64d096644..43edb40e911 100644
--- a/doc/api/builds.md
+++ b/doc/api/builds.md
@@ -8,20 +8,16 @@ Get a list of builds in a project.
GET /projects/:id/builds
```
-### Parameters
-
-| Attribute | Type | required | Description |
+| Attribute | Type | Required | Description |
|-----------|---------|----------|---------------------|
-| id | integer | yes | The ID of a project |
-| scope | string|array of strings | no | The scope of builds to show, one or array of: `pending`, `running`, `failed`, `success`, `canceled`; showing all builds if none provided |
-
-### Example of request
+| `id` | integer | yes | The ID of a project |
+| `scope` | string **or** array of strings | no | The scope of builds to show, one or array of: `pending`, `running`, `failed`, `success`, `canceled`; showing all builds if none provided |
```
curl -H "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v3/projects/1/builds"
```
-### Example of response
+Example of response
```json
[
@@ -112,21 +108,17 @@ Get a list of builds for specific commit in a project.
GET /projects/:id/repository/commits/:sha/builds
```
-### Parameters
-
-| Attribute | Type | required | Description |
+| Attribute | Type | Required | Description |
|-----------|---------|----------|---------------------|
-| id | integer | yes | The ID of a project |
-| sha | string | yes | The SHA id of a commit |
-| scope | string|array of strings | no | The scope of builds to show, one or array of: `pending`, `running`, `failed`, `success`, `canceled`; showing all builds if none provided |
-
-### Example of request
+| `id` | integer | yes | The ID of a project |
+| `sha` | string | yes | The SHA id of a commit |
+| `scope` | string **or** array of strings | no | The scope of builds to show, one or array of: `pending`, `running`, `failed`, `success`, `canceled`; showing all builds if none provided |
```
curl -H "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v3/projects/1/repository/commits/0ff3ae198f8601a285adcf5c0fff204ee6fba5fd/builds"
```
-### Example of response
+Example of response
```json
[
@@ -203,20 +195,16 @@ Get a single build of a project
GET /projects/:id/builds/:build_id
```
-### Parameters
-
-| Attribute | Type | required | Description |
-|-----------|---------|----------|---------------------|
-| id | integer | yes | The ID of a project |
-| build\_id | integer | yes | The ID of a build |
-
-### Example of request
+| Attribute | Type | Required | Description |
+|------------|---------|----------|---------------------|
+| `id` | integer | yes | The ID of a project |
+| `build_id` | integer | yes | The ID of a build |
```
curl -H "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v3/projects/1/builds/8"
```
-### Example of response
+Example of response
```json
{
@@ -267,20 +255,16 @@ Cancel a single build of a project
POST /projects/:id/builds/:build_id/cancel
```
-### Parameters
-
-| Attribute | Type | required | Description |
-|-----------|---------|----------|---------------------|
-| id | integer | yes | The ID of a project |
-| build\_id | integer | yes | The ID of a build |
-
-### Example of request
+| Attribute | Type | Required | Description |
+|------------|---------|----------|---------------------|
+| `id` | integer | yes | The ID of a project |
+| `build_id` | integer | yes | The ID of a build |
```
curl -X POST -H "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v3/projects/1/builds/1/cancel"
```
-### Example of response
+Example of response
```json
{
@@ -317,20 +301,16 @@ Retry a single build of a project
POST /projects/:id/builds/:build_id/retry
```
-### Parameters
-
-| Attribute | Type | required | Description |
-|-----------|---------|----------|---------------------|
-| id | integer | yes | The ID of a project |
-| build\_id | integer | yes | The ID of a build |
-
-### Example of request
+| Attribute | Type | Required | Description |
+|------------|---------|----------|---------------------|
+| `id` | integer | yes | The ID of a project |
+| `build_id` | integer | yes | The ID of a build |
```
curl -X POST -H "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v3/projects/1/builds/1/retry"
```
-### Example of response
+Example of response
```json
{
diff --git a/doc/api/merge_requests.md b/doc/api/merge_requests.md
index b4dca6dd35e..009532b50c1 100644
--- a/doc/api/merge_requests.md
+++ b/doc/api/merge_requests.md
@@ -259,6 +259,7 @@ Parameters:
- `description` (optional) - Description of MR
- `target_project_id` (optional) - The target project (numeric id)
- `labels` (optional) - Labels for MR as a comma-separated list
+- `milestone_id` (optional) - Milestone ID
```json
{
@@ -328,6 +329,7 @@ Parameters:
- `description` - Description of MR
- `state_event` - New state (close|reopen|merge)
- `labels` (optional) - Labels for MR as a comma-separated list
+- `milestone_id` (optional) - Milestone ID
```json
{
@@ -516,3 +518,65 @@ Parameters:
## Comments on merge requets
Comments are done via the [notes](notes.md) resource.
+
+## List issues that will close on merge
+
+Get all the issues that would be closed by merging the provided merge request.
+
+```
+GET /projects/:id/merge_requests/:merge_request_id/closes_issues
+```
+
+| Attribute | Type | Required | Description |
+| --------- | ---- | -------- | ----------- |
+| `id` | integer | yes | The ID of a project |
+| `merge_request_id` | integer | yes | The ID of the merge request |
+
+```bash
+curl -H "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v3/projects/76/merge_requests/1/closes_issues
+```
+
+Example response:
+
+```json
+[
+ {
+ "state" : "opened",
+ "description" : "Ratione dolores corrupti mollitia soluta quia.",
+ "author" : {
+ "state" : "active",
+ "id" : 18,
+ "web_url" : "https://gitlab.example.com/u/eileen.lowe",
+ "name" : "Alexandra Bashirian",
+ "avatar_url" : null,
+ "username" : "eileen.lowe"
+ },
+ "milestone" : {
+ "project_id" : 1,
+ "description" : "Ducimus nam enim ex consequatur cumque ratione.",
+ "state" : "closed",
+ "due_date" : null,
+ "iid" : 2,
+ "created_at" : "2016-01-04T15:31:39.996Z",
+ "title" : "v4.0",
+ "id" : 17,
+ "updated_at" : "2016-01-04T15:31:39.996Z"
+ },
+ "project_id" : 1,
+ "assignee" : {
+ "state" : "active",
+ "id" : 1,
+ "name" : "Administrator",
+ "web_url" : "https://gitlab.example.com/u/root",
+ "avatar_url" : null,
+ "username" : "root"
+ },
+ "updated_at" : "2016-01-04T15:31:51.081Z",
+ "id" : 76,
+ "title" : "Consequatur vero maxime deserunt laboriosam est voluptas dolorem.",
+ "created_at" : "2016-01-04T15:31:51.081Z",
+ "iid" : 6,
+ "labels" : []
+ },
+]
+```
diff --git a/doc/ci/docker/using_docker_images.md b/doc/ci/docker/using_docker_images.md
index 63fe840b369..bd748f1b986 100644
--- a/doc/ci/docker/using_docker_images.md
+++ b/doc/ci/docker/using_docker_images.md
@@ -270,7 +270,7 @@ This will forcefully (`-f`) remove the `build` container, the two service
containers as well as all volumes (`-v`) that were created with the container
creation.
-[Docker Fundamentals]: https://docs.docker.com/engine/introduction/understanding-docker/
+[Docker Fundamentals]: https://docs.docker.com/engine/understanding-docker/
[hub]: https://hub.docker.com/
[linking-containers]: https://docs.docker.com/engine/userguide/networking/default_network/dockerlinks/
[tutum/wordpress]: https://registry.hub.docker.com/u/tutum/wordpress/
diff --git a/doc/ci/quick_start/README.md b/doc/ci/quick_start/README.md
index a9b36139de9..ae7b760fa67 100644
--- a/doc/ci/quick_start/README.md
+++ b/doc/ci/quick_start/README.md
@@ -184,6 +184,14 @@ you expected.
You are also able to view the status of any commit in the various pages in
GitLab, such as **Commits** and **Merge Requests**.
+## Builds badge
+
+You can access a builds badge image using following link:
+
+```
+http://example.gitlab.com/namespace/project/badges/branch/build.svg
+```
+
## Next steps
Awesome! You started using CI in GitLab!
diff --git a/doc/install/installation.md b/doc/install/installation.md
index fe614df91fd..7d3f9d0a2ed 100644
--- a/doc/install/installation.md
+++ b/doc/install/installation.md
@@ -358,7 +358,7 @@ GitLab Shell is an SSH access and repository management software developed speci
cd /home/git
sudo -u git -H git clone https://gitlab.com/gitlab-org/gitlab-workhorse.git
cd gitlab-workhorse
- sudo -u git -H git checkout 0.6.3
+ sudo -u git -H git checkout 0.6.4
sudo -u git -H make
### Initialize Database and Activate Advanced Features
diff --git a/doc/markdown/img/logo.png b/doc/markdown/img/logo.png
new file mode 100644
index 00000000000..7da5f23ed9b
--- /dev/null
+++ b/doc/markdown/img/logo.png
Binary files differ
diff --git a/doc/markdown/markdown.md b/doc/markdown/markdown.md
index f6bffba9fdb..c400cdac64d 100644
--- a/doc/markdown/markdown.md
+++ b/doc/markdown/markdown.md
@@ -424,24 +424,24 @@ will point the link to `wikis/style` when the link is inside of a wiki markdown
Here's our logo (hover to see the title text):
Inline-style:
- ![alt text](assets/logo.svg)
+ ![alt text](img/logo.png)
Reference-style:
![alt text1][logo]
- [logo]: assets/logo.svg
+ [logo]: img/logo.png
Here's our logo:
Inline-style:
-![alt text](/assets/logo.svg)
+![alt text](img/logo.png)
Reference-style:
![alt text][logo]
-[logo]: /assets/logo.svg
+[logo]: img/logo.png
## Blockquotes
diff --git a/doc/update/8.4-to-8.5.md b/doc/update/8.4-to-8.5.md
index 6e035047b24..42b26439848 100644
--- a/doc/update/8.4-to-8.5.md
+++ b/doc/update/8.4-to-8.5.md
@@ -49,7 +49,7 @@ GitLab 8.1.
```bash
cd /home/git/gitlab-workhorse
sudo -u git -H git fetch --all
-sudo -u git -H git checkout 0.6.3
+sudo -u git -H git checkout 0.6.4
sudo -u git -H make
```
@@ -72,12 +72,22 @@ sudo -u git -H bundle exec rake assets:clean assets:precompile cache:clear RAILS
```
-### 7. Start application
+### 7. Update configuration files
+
+#### New configuration options for `gitlab.yml`
+
+There are new configuration options available for [`gitlab.yml`](config/gitlab.yml.example). View them with the command below and apply them manually to your current `gitlab.yml`:
+
+```sh
+git diff origin/8-4-stable:config/gitlab.yml.example origin/8-5-stable:config/gitlab.yml.example
+```
+
+### 8. Start application
sudo service gitlab start
sudo service nginx restart
-### 8. Check application status
+### 9. Check application status
Check if GitLab and its environment are configured correctly:
diff --git a/doc/web_hooks/web_hooks.md b/doc/web_hooks/web_hooks.md
index c29037e89c2..c556597225c 100644
--- a/doc/web_hooks/web_hooks.md
+++ b/doc/web_hooks/web_hooks.md
@@ -8,8 +8,8 @@ Web hooks can be used to update an external issue tracker, trigger CI builds, up
## SSL Verification
-By default, the SSL certificate of the webhook endpoint is verified based on
-an internal list of Certificate Authorities,
+By default, the SSL certificate of the webhook endpoint is verified based on
+an internal list of Certificate Authorities,
which means the certificate cannot be self-signed.
You can turn this off in the web hook settings in your GitLab projects.
@@ -76,7 +76,6 @@ X-Gitlab-Event: Push Hook
}
],
"total_commits_count": 4
-
}
```
@@ -158,6 +157,11 @@ X-Gitlab-Event: Issue Hook
"iid": 23,
"url": "http://example.com/diaspora/issues/23",
"action": "open"
+ },
+ "assignee": {
+ "name": "User1",
+ "username": "user1",
+ "avatar_url": "http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=40\u0026d=identicon"
}
}
```
@@ -322,7 +326,12 @@ X-Gitlab-Event: Note Hook
"email": "john@example.com"
}
},
- "work_in_progress": false
+ "work_in_progress": false,
+ "assignee": {
+ "name": "User1",
+ "username": "user1",
+ "avatar_url": "http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=40\u0026d=identicon"
+ }
}
}
```
@@ -397,7 +406,7 @@ X-Gitlab-Event: Note Hook
**Request body:**
-```
+```json
{
"object_kind": "note",
"user": {
@@ -510,7 +519,12 @@ X-Gitlab-Event: Merge Request Hook
},
"work_in_progress": false,
"url": "http://example.com/diaspora/merge_requests/1",
- "action": "open"
+ "action": "open",
+ "assignee": {
+ "name": "User1",
+ "username": "user1",
+ "avatar_url": "http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=40\u0026d=identicon"
+ }
}
}
```
diff --git a/features/project/badges/build.feature b/features/project/badges/build.feature
new file mode 100644
index 00000000000..9417f62d680
--- /dev/null
+++ b/features/project/badges/build.feature
@@ -0,0 +1,22 @@
+Feature: Project Badges Build
+ Background:
+ Given I sign in as a user
+ And I own a project
+ And project has CI enabled
+ And project has a recent build
+
+ Scenario: I want to see a badge for successfully built project
+ Given recent build is successful
+ When I display builds badge for a master branch
+ Then I should see a build success badge
+
+ Scenario: I want to see a badge for project with failed builds
+ Given recent build failed
+ When I display builds badge for a master branch
+ Then I should see a build failed badge
+
+ Scenario: I want to see a badge for project with running builds
+ Given recent build is successful
+ And project has another build that is running
+ When I display builds badge for a master branch
+ Then I should see a build running badge
diff --git a/features/project/commits/commits.feature b/features/project/commits/commits.feature
index 01c10721312..a95df038357 100644
--- a/features/project/commits/commits.feature
+++ b/features/project/commits/commits.feature
@@ -7,6 +7,26 @@ Feature: Project Commits
Scenario: I browse commits list for master branch
Then I see project commits
+ And I should not see button to create a new merge request
+ Then I click the "Compare" tab
+ And I should not see button to create a new merge request
+
+ Scenario: I browse commits list for feature branch without a merge request
+ Given I visit commits list page for feature branch
+ Then I see feature branch commits
+ And I see button to create a new merge request
+ Then I click the "Compare" tab
+ And I see button to create a new merge request
+
+ Scenario: I browse commits list for feature branch with an open merge request
+ Given project have an open merge request
+ And I visit commits list page for feature branch
+ Then I see feature branch commits
+ And I should not see button to create a new merge request
+ And I should see button to the merge request
+ Then I click the "Compare" tab
+ And I should not see button to create a new merge request
+ And I should see button to the merge request
Scenario: I browse atom feed of commits list for master branch
Given I click atom feed link
@@ -31,6 +51,22 @@ Feature: Project Commits
Then I see inline diff button
@javascript
+ Scenario: I compare branches without a merge request
+ Given I visit compare refs page
+ And I fill compare fields with branches
+ Then I see compared branches
+ And I see button to create a new merge request
+
+ @javascript
+ Scenario: I compare branches with an open merge request
+ Given project have an open merge request
+ And I visit compare refs page
+ And I fill compare fields with branches
+ Then I see compared branches
+ And I should not see button to create a new merge request
+ And I should see button to the merge request
+
+ @javascript
Scenario: I compare refs
Given I visit compare refs page
And I fill compare fields with refs
diff --git a/features/steps/project/badges/build.rb b/features/steps/project/badges/build.rb
new file mode 100644
index 00000000000..cbfc35bed65
--- /dev/null
+++ b/features/steps/project/badges/build.rb
@@ -0,0 +1,28 @@
+class Spinach::Features::ProjectBadgesBuild < Spinach::FeatureSteps
+ include SharedAuthentication
+ include SharedProject
+ include SharedBuilds
+ include RepoHelpers
+
+ step 'I display builds badge for a master branch' do
+ visit build_namespace_project_badges_path(@project.namespace, @project, ref: :master, format: :svg)
+ end
+
+ step 'I should see a build success badge' do
+ expect_badge('success')
+ end
+
+ step 'I should see a build failed badge' do
+ expect_badge('failed')
+ end
+
+ step 'I should see a build running badge' do
+ expect_badge('running')
+ end
+
+ def expect_badge(status)
+ svg = Nokogiri::XML.parse(page.body)
+ expect(page.response_headers).to include('Content-Type' => 'image/svg+xml')
+ expect(svg.at(%Q{text:contains("#{status}")})).to be_truthy
+ end
+end
diff --git a/features/steps/project/commits/commits.rb b/features/steps/project/commits/commits.rb
index daf6cdaaac8..f9fd7332464 100644
--- a/features/steps/project/commits/commits.rb
+++ b/features/steps/project/commits/commits.rb
@@ -33,6 +33,13 @@ class Spinach::Features::ProjectCommits < Spinach::FeatureSteps
expect(page).to have_content "Showing #{sample_commit.files_changed_count} changed files"
end
+ step 'I fill compare fields with branches' do
+ fill_in 'from', with: 'feature'
+ fill_in 'to', with: 'master'
+
+ click_button 'Compare'
+ end
+
step 'I fill compare fields with refs' do
fill_in "from", with: sample_commit.parent_id
fill_in "to", with: sample_commit.id
@@ -56,6 +63,56 @@ class Spinach::Features::ProjectCommits < Spinach::FeatureSteps
expect(page).to have_content "Showing 2 changed files"
end
+ step 'I visit commits list page for feature branch' do
+ visit namespace_project_commits_path(@project.namespace, @project, 'feature', { limit: 5 })
+ end
+
+ step 'I see feature branch commits' do
+ commit = @project.repository.commit('0b4bc9a')
+ expect(page).to have_content(@project.name)
+ expect(page).to have_content(commit.message[0..12])
+ expect(page).to have_content(commit.short_id)
+ end
+
+ step 'project have an open merge request' do
+ create(:merge_request,
+ title: 'Feature',
+ source_project: @project,
+ source_branch: 'feature',
+ target_branch: 'master',
+ author: @project.users.first
+ )
+ end
+
+ step 'I click the "Compare" tab' do
+ click_link('Compare')
+ end
+
+ step 'I fill compare fields with branches' do
+ fill_in 'from', with: 'master'
+ fill_in 'to', with: 'feature'
+
+ click_button 'Compare'
+ end
+
+ step 'I see compared branches' do
+ expect(page).to have_content 'Commits (1)'
+ expect(page).to have_content 'Showing 1 changed file with 5 additions and 0 deletions'
+ end
+
+ step 'I see button to create a new merge request' do
+ expect(page).to have_link 'Create Merge Request'
+ end
+
+ step 'I should not see button to create a new merge request' do
+ expect(page).to_not have_link 'Create Merge Request'
+ end
+
+ step 'I should see button to the merge request' do
+ merge_request = MergeRequest.find_by(title: 'Feature')
+ expect(page).to have_link "View Open Merge Request", href: namespace_project_merge_request_path(@project.namespace, @project, merge_request)
+ end
+
step 'I see breadcrumb links' do
expect(page).to have_selector('ul.breadcrumb')
expect(page).to have_selector('ul.breadcrumb a', count: 4)
diff --git a/features/steps/shared/builds.rb b/features/steps/shared/builds.rb
index 726e2e814ad..fa54c93df0f 100644
--- a/features/steps/shared/builds.rb
+++ b/features/steps/shared/builds.rb
@@ -6,8 +6,20 @@ module SharedBuilds
end
step 'project has a recent build' do
- ci_commit = create :ci_commit, project: @project, sha: sample_commit.id
- @build = create :ci_build, commit: ci_commit
+ @ci_commit = create(:ci_commit, project: @project, sha: @project.commit.sha)
+ @build = create(:ci_build, commit: @ci_commit)
+ end
+
+ step 'recent build is successful' do
+ @build.update_column(:status, 'success')
+ end
+
+ step 'recent build failed' do
+ @build.update_column(:status, 'failed')
+ end
+
+ step 'project has another build that is running' do
+ create(:ci_build, commit: @ci_commit, name: 'second build', status: 'running')
end
step 'I visit recent build details page' do
diff --git a/lib/api/merge_requests.rb b/lib/api/merge_requests.rb
index dd7f24f3279..c5e5d57ed4d 100644
--- a/lib/api/merge_requests.rb
+++ b/lib/api/merge_requests.rb
@@ -71,6 +71,7 @@ module API
# title (required) - Title of MR
# description - Description of MR
# labels (optional) - Labels for MR as a comma-separated list
+ # milestone_id (optional) - Milestone ID
#
# Example:
# POST /projects/:id/merge_requests
@@ -78,7 +79,7 @@ module API
post ":id/merge_requests" do
authorize! :create_merge_request, user_project
required_attributes! [:source_branch, :target_branch, :title]
- attrs = attributes_for_keys [:source_branch, :target_branch, :assignee_id, :title, :target_project_id, :description]
+ attrs = attributes_for_keys [:source_branch, :target_branch, :assignee_id, :title, :target_project_id, :description, :milestone_id]
# Validate label names in advance
if (errors = validate_label_params(params)).any?
@@ -163,11 +164,12 @@ module API
# state_event - Status of MR. (close|reopen|merge)
# description - Description of MR
# labels (optional) - Labels for a MR as a comma-separated list
+ # milestone_id (optional) - Milestone ID
# Example:
# PUT /projects/:id/merge_requests/:merge_request_id
#
put path do
- attrs = attributes_for_keys [:target_branch, :assignee_id, :title, :state_event, :description]
+ attrs = attributes_for_keys [:target_branch, :assignee_id, :title, :state_event, :description, :milestone_id]
merge_request = user_project.merge_requests.find(params[:merge_request_id])
authorize! :update_merge_request, merge_request
@@ -300,6 +302,19 @@ module API
render_api_error!("Failed to save note #{note.errors.messages}", 400)
end
end
+
+ # List issues that will close on merge
+ #
+ # Parameters:
+ # id (required) - The ID of a project
+ # merge_request_id (required) - ID of MR
+ # Examples:
+ # GET /projects/:id/merge_requests/:merge_request_id/closes_issues
+ get "#{path}/closes_issues" do
+ merge_request = user_project.merge_requests.find(params[:merge_request_id])
+ issues = ::Kaminari.paginate_array(merge_request.closes_issues(current_user))
+ present paginate(issues), with: Entities::Issue
+ end
end
end
end
diff --git a/lib/gitlab/blame.rb b/lib/gitlab/blame.rb
index 313e6b9fc03..997a22779a0 100644
--- a/lib/gitlab/blame.rb
+++ b/lib/gitlab/blame.rb
@@ -40,6 +40,7 @@ module Gitlab
end
def highlighted_lines
+ @blob.load_all_data!(repository)
@highlighted_lines ||= Gitlab::Highlight.highlight(@blob.name, @blob.data).lines
end
diff --git a/lib/tasks/gitlab/check.rake b/lib/tasks/gitlab/check.rake
index 2dc2953e328..54d95cd62a5 100644
--- a/lib/tasks/gitlab/check.rake
+++ b/lib/tasks/gitlab/check.rake
@@ -90,24 +90,6 @@ namespace :gitlab do
end
end
- def check_database_is_not_sqlite
- print "Database is SQLite ... "
-
- database_config_file = Rails.root.join("config", "database.yml")
-
- unless File.read(database_config_file) =~ /adapter:\s+sqlite/
- puts "no".green
- else
- puts "yes".red
- puts "Please fix this by removing the SQLite entry from the database.yml".blue
- for_more_information(
- "https://github.com/gitlabhq/gitlabhq/wiki/Migrate-from-SQLite-to-MySQL",
- see_database_guide
- )
- fix_and_rerun
- end
- end
-
def check_gitlab_config_exists
print "GitLab config exists? ... "
diff --git a/scripts/prepare_build.sh b/scripts/prepare_build.sh
index 5987988dc8e..b6f076a90c3 100755
--- a/scripts/prepare_build.sh
+++ b/scripts/prepare_build.sh
@@ -1,15 +1,15 @@
#!/bin/bash
if [ -f /.dockerinit ]; then
- # Docker runners use `/cache` folder which is persisted every build
- if [ ! -e /cache/phantomjs_1.9.8-0jessie_amd64.deb ]; then
+ mkdir -p vendor
+ if [ ! -e vendor/phantomjs_1.9.8-0jessie_amd64.deb ]; then
wget -q https://gitlab.com/axil/phantomjs-debian/raw/master/phantomjs_1.9.8-0jessie_amd64.deb
- mv phantomjs_1.9.8-0jessie_amd64.deb /cache
+ mv phantomjs_1.9.8-0jessie_amd64.deb vendor/
fi
- dpkg -i /cache/phantomjs_1.9.8-0jessie_amd64.deb
+ dpkg -i vendor/phantomjs_1.9.8-0jessie_amd64.deb
apt-get update -qq
- apt-get -o dir::cache::archives="/cache/apt" install -y -qq --force-yes \
+ apt-get -o dir::cache::archives="vendor/apt" install -y -qq --force-yes \
libicu-dev libkrb5-dev cmake nodejs postgresql-client mysql-client unzip
cp config/database.yml.mysql config/database.yml
@@ -20,7 +20,7 @@ if [ -f /.dockerinit ]; then
cp config/resque.yml.example config/resque.yml
sed -i 's/localhost/redis/g' config/resque.yml
- export FLAGS=(--path /cache)
+ export FLAGS=(--path vendor)
else
export PATH=$HOME/bin:/usr/local/bin:/usr/bin:/bin
cp config/database.yml.mysql config/database.yml
diff --git a/spec/models/application_setting_spec.rb b/spec/models/application_setting_spec.rb
index 161a32c51e6..b1764d7ac09 100644
--- a/spec/models/application_setting_spec.rb
+++ b/spec/models/application_setting_spec.rb
@@ -74,6 +74,10 @@ describe ApplicationSetting, models: true do
.only_integer
.is_greater_than(0)
end
+
+ it_behaves_like 'an object with email-formated attributes', :admin_notification_email do
+ subject { setting }
+ end
end
context 'restricted signup domains' do
diff --git a/spec/models/concerns/issuable_spec.rb b/spec/models/concerns/issuable_spec.rb
index 021d62cdf0c..8f09ff03a78 100644
--- a/spec/models/concerns/issuable_spec.rb
+++ b/spec/models/concerns/issuable_spec.rb
@@ -79,6 +79,16 @@ describe Issue, "Issuable" do
expect(hook_data[:repository][:description]).to eq(issue.project.description)
expect(hook_data[:repository][:homepage]).to eq(issue.project.web_url)
expect(hook_data[:object_attributes]).to eq(issue.hook_attrs)
+ expect(hook_data).to_not have_key(:assignee)
+ end
+
+ context "issue is assigned" do
+ before { issue.update_attribute(:assignee, user) }
+
+ it "returns correct hook data" do
+ expect(hook_data[:object_attributes]['assignee_id']).to eq(user.id)
+ expect(hook_data[:assignee]).to eq(user.hook_attrs)
+ end
end
end
diff --git a/spec/models/email_spec.rb b/spec/models/email_spec.rb
new file mode 100644
index 00000000000..a20a6149649
--- /dev/null
+++ b/spec/models/email_spec.rb
@@ -0,0 +1,22 @@
+# == Schema Information
+#
+# Table name: emails
+#
+# id :integer not null, primary key
+# user_id :integer not null
+# email :string(255) not null
+# created_at :datetime
+# updated_at :datetime
+#
+
+require 'spec_helper'
+
+describe Email, models: true do
+
+ describe 'validations' do
+ it_behaves_like 'an object with email-formated attributes', :email do
+ subject { build(:email) }
+ end
+ end
+
+end
diff --git a/spec/models/member_spec.rb b/spec/models/member_spec.rb
index 2aedca20df2..2d8f1cc1ad3 100644
--- a/spec/models/member_spec.rb
+++ b/spec/models/member_spec.rb
@@ -31,6 +31,10 @@ describe Member, models: true do
it { is_expected.to validate_presence_of(:source) }
it { is_expected.to validate_inclusion_of(:access_level).in_array(Gitlab::Access.values) }
+ it_behaves_like 'an object with email-formated attributes', :invite_email do
+ subject { build(:project_member) }
+ end
+
context "when an invite email is provided" do
let(:member) { build(:project_member, invite_email: "user@example.com", user: nil) }
@@ -159,7 +163,7 @@ describe Member, models: true do
describe "#generate_invite_token" do
let!(:member) { create(:project_member, invite_email: "user@example.com", user: nil) }
-
+
it "sets the invite token" do
expect { member.generate_invite_token }.to change { member.invite_token}
end
diff --git a/spec/models/repository_spec.rb b/spec/models/repository_spec.rb
index 72b4ac6d660..e1ee43e64db 100644
--- a/spec/models/repository_spec.rb
+++ b/spec/models/repository_spec.rb
@@ -354,4 +354,10 @@ describe Repository, models: true do
repository.expire_branch_cache('foo')
end
end
+
+ describe :skip_merged_commit do
+ subject { repository.commits(Gitlab::Git::BRANCH_REF_PREFIX + "'test'", nil, 100, 0, true).map{ |k| k.id } }
+
+ it { is_expected.not_to include('e56497bb5f03a90a51293fc6d516788730953899') }
+ end
end
diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb
index cee051f5732..47ce409fe4b 100644
--- a/spec/models/user_spec.rb
+++ b/spec/models/user_spec.rb
@@ -119,37 +119,15 @@ describe User, models: true do
it { is_expected.to validate_length_of(:bio).is_within(0..255) }
- describe 'email' do
- it 'accepts info@example.com' do
- user = build(:user, email: 'info@example.com')
- expect(user).to be_valid
- end
-
- it 'accepts info+test@example.com' do
- user = build(:user, email: 'info+test@example.com')
- expect(user).to be_valid
- end
-
- it "accepts o'reilly@example.com" do
- user = build(:user, email: "o'reilly@example.com")
- expect(user).to be_valid
- end
-
- it 'rejects test@test@example.com' do
- user = build(:user, email: 'test@test@example.com')
- expect(user).to be_invalid
- end
-
- it 'rejects mailto:test@example.com' do
- user = build(:user, email: 'mailto:test@example.com')
- expect(user).to be_invalid
- end
+ it_behaves_like 'an object with email-formated attributes', :email do
+ subject { build(:user) }
+ end
- it "rejects lol!'+=?><#$%^&*()@gmail.com" do
- user = build(:user, email: "lol!'+=?><#$%^&*()@gmail.com")
- expect(user).to be_invalid
- end
+ it_behaves_like 'an object with email-formated attributes', :public_email, :notification_email do
+ subject { build(:user).tap { |user| user.emails << build(:email, email: email_value) } }
+ end
+ describe 'email' do
context 'when no signup domains listed' do
before { allow(current_application_settings).to receive(:restricted_signup_domains).and_return([]) }
it 'accepts any email' do
diff --git a/spec/requests/api/merge_requests_spec.rb b/spec/requests/api/merge_requests_spec.rb
index a91a8696831..4fd1df25568 100644
--- a/spec/requests/api/merge_requests_spec.rb
+++ b/spec/requests/api/merge_requests_spec.rb
@@ -10,6 +10,7 @@ describe API::API, api: true do
let!(:merge_request_merged) { create(:merge_request, state: "merged", author: user, assignee: user, source_project: project, target_project: project, title: "Merged test", created_at: base_time + 2.seconds) }
let!(:note) { create(:note_on_merge_request, author: user, project: project, noteable: merge_request, note: "a comment on a MR") }
let!(:note2) { create(:note_on_merge_request, author: user, project: project, noteable: merge_request, note: "another comment on a MR") }
+ let(:milestone) { create(:milestone, title: '1.0.0', project: project) }
before do
project.team << [user, :reporters]
@@ -170,10 +171,12 @@ describe API::API, api: true do
source_branch: 'feature_conflict',
target_branch: 'master',
author: user,
- labels: 'label, label2'
+ labels: 'label, label2',
+ milestone_id: milestone.id
expect(response.status).to eq(201)
expect(json_response['title']).to eq('Test merge_request')
expect(json_response['labels']).to eq(['label', 'label2'])
+ expect(json_response['milestone']['id']).to eq(milestone.id)
end
it "should return 422 when source_branch equals target_branch" do
@@ -374,18 +377,24 @@ describe API::API, api: true do
end
describe "PUT /projects/:id/merge_requests/:merge_request_id" do
- it "should return merge_request" do
+ it "updates title and returns merge_request" do
put api("/projects/#{project.id}/merge_requests/#{merge_request.id}", user), title: "New title"
expect(response.status).to eq(200)
expect(json_response['title']).to eq('New title')
end
- it "should return merge_request" do
+ it "updates description and returns merge_request" do
put api("/projects/#{project.id}/merge_requests/#{merge_request.id}", user), description: "New description"
expect(response.status).to eq(200)
expect(json_response['description']).to eq('New description')
end
+ it "updates milestone_id and returns merge_request" do
+ put api("/projects/#{project.id}/merge_requests/#{merge_request.id}", user), milestone_id: milestone.id
+ expect(response.status).to eq(200)
+ expect(json_response['milestone']['id']).to eq(milestone.id)
+ end
+
it "should return 400 when source_branch is specified" do
put api("/projects/#{project.id}/merge_requests/#{merge_request.id}", user),
source_branch: "master", target_branch: "master"
@@ -449,6 +458,28 @@ describe API::API, api: true do
end
end
+ describe 'GET :id/merge_requests/:merge_request_id/closes_issues' do
+ it 'returns the issue that will be closed on merge' do
+ issue = create(:issue, project: project)
+ mr = merge_request.tap do |mr|
+ mr.update_attribute(:description, "Closes #{issue.to_reference(mr.project)}")
+ end
+
+ get api("/projects/#{project.id}/merge_requests/#{mr.id}/closes_issues", user)
+ expect(response.status).to eq(200)
+ expect(json_response).to be_an Array
+ expect(json_response.length).to eq(1)
+ expect(json_response.first['id']).to eq(issue.id)
+ end
+
+ it 'returns an empty array when there are no issues to be closed' do
+ get api("/projects/#{project.id}/merge_requests/#{merge_request.id}/closes_issues", user)
+ expect(response.status).to eq(200)
+ expect(json_response).to be_an Array
+ expect(json_response.length).to eq(0)
+ end
+ end
+
def mr_with_later_created_and_updated_at_time
merge_request
merge_request.created_at += 1.hour
diff --git a/spec/support/email_format_shared_examples.rb b/spec/support/email_format_shared_examples.rb
new file mode 100644
index 00000000000..b924a208e71
--- /dev/null
+++ b/spec/support/email_format_shared_examples.rb
@@ -0,0 +1,44 @@
+# Specifications for behavior common to all objects with an email attribute.
+# Takes a list of email-format attributes and requires:
+# - subject { "the object with a attribute= setter" }
+# Note: You have access to `email_value` which is the email address value
+# being currently tested).
+
+shared_examples 'an object with email-formated attributes' do |*attributes|
+ attributes.each do |attribute|
+ describe "specifically its :#{attribute} attribute" do
+ %w[
+ info@example.com
+ info+test@example.com
+ o'reilly@example.com
+ mailto:test@example.com
+ lol!'+=?><#$%^&*()@gmail.com
+ ].each do |valid_email|
+ context "with a value of '#{valid_email}'" do
+ let(:email_value) { valid_email }
+
+ it 'is valid' do
+ subject.send("#{attribute}=", valid_email)
+
+ expect(subject).to be_valid
+ end
+ end
+ end
+
+ %w[
+ foobar
+ test@test@example.com
+ ].each do |invalid_email|
+ context "with a value of '#{invalid_email}'" do
+ let(:email_value) { invalid_email }
+
+ it 'is invalid' do
+ subject.send("#{attribute}=", invalid_email)
+
+ expect(subject).to be_invalid
+ end
+ end
+ end
+ end
+ end
+end