diff options
author | James Lopez <james@jameslopez.es> | 2016-02-12 14:21:04 +0300 |
---|---|---|
committer | James Lopez <james@jameslopez.es> | 2016-02-12 14:21:04 +0300 |
commit | a5b011c9d8586453d37852856822dab692f6613b (patch) | |
tree | f3400cff867007d9962e6fd31e0a94d460db1b88 | |
parent | 3753c1e03edb516033b4ef856aed63668de59cf3 (diff) | |
parent | b1dda8145433f15fcea683451c9c79927b19352e (diff) |
Merge branch 'master' of gitlab.com:gitlab-org/gitlab-ce into fix/cross-reference-notes-forks
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 = 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 Binary files differnew file mode 100644 index 00000000000..7da5f23ed9b --- /dev/null +++ b/doc/markdown/img/logo.png 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 |