diff options
66 files changed, 514 insertions, 468 deletions
diff --git a/CHANGELOG b/CHANGELOG index a6bfedf283a..3af83ddc256 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,6 +1,7 @@ Please view this file on the master branch, on stable branches it's out of date. v 7.11.0 (unreleased) + - Don't allow a merge request to be merged when its title starts with "WIP". - Get Gitorious importer to work again. - Fix clone URL field and X11 Primary selection (Dmitry Medvinsky) - Ignore invalid lines in .gitmodules @@ -18,8 +19,10 @@ v 7.11.0 (unreleased) - Add project activity atom feed. - Don't crash when an MR from a fork has a cross-reference comment from the target project on of its commits. - Include commit comments in MR from a forked project. - - + - Fix adding new group members from admin area - Add default project and snippet visibility settings to the admin web UI. + - + - Fix bug where commit data would not appear in some subdirectories (Stan Hu) - Fix bug where Slack service channel was not saved in admin template settings. (Stan Hu) - Move snippets UI to fluid layout - Improve UI for sidebar. Increase separation between navigation and content @@ -27,6 +30,8 @@ v 7.11.0 (unreleased) - Prevent sending empty messages to HipChat (Chulki Lee) - Improve UI for mobile phones on dashboard and project pages - Add room notification and message color option for HipChat + - Allow to use non-ASCII letters and dashes in project and namespace name. (Jakub Jirutka) + - Add footnotes support to Markdown (Guillaume Delbergue) v 7.10.0 - Ignore submodules that are defined in .gitmodules but are checked in as directories. @@ -208,6 +208,7 @@ group :development do gem "letter_opener" gem 'quiet_assets', '~> 1.0.1' gem 'rack-mini-profiler', require: false + gem 'rerun', '~> 0.10.0' # Better errors handler gem 'better_errors' diff --git a/Gemfile.lock b/Gemfile.lock index 0f965d7b542..676a5197900 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -167,7 +167,7 @@ GEM faraday (>= 0.7.4, < 0.9) fastercsv (1.5.5) ffaker (1.22.1) - ffi (1.9.3) + ffi (1.9.8) fog (1.21.0) fog-brightbox fog-core (~> 1.21, >= 1.21.1) @@ -323,8 +323,8 @@ GEM addressable (~> 2.3) letter_opener (1.1.2) launchy (~> 2.2) - listen (2.3.1) - celluloid (>= 0.15.2) + listen (2.10.0) + celluloid (~> 0.16.0) rb-fsevent (>= 0.9.3) rb-inotify (>= 0.9) lumberjack (1.0.4) @@ -456,8 +456,8 @@ GEM raindrops (0.13.0) rake (10.4.2) raphael-rails (2.1.2) - rb-fsevent (0.9.3) - rb-inotify (0.9.2) + rb-fsevent (0.9.4) + rb-inotify (0.9.5) ffi (>= 0.5.0) rdoc (3.12.2) json (~> 1.4) @@ -482,6 +482,8 @@ GEM redis-store (1.1.4) redis (>= 2.2) request_store (1.0.5) + rerun (0.10.0) + listen (~> 2.7, >= 2.7.3) rest-client (1.6.7) mime-types (>= 1.16) rinku (1.7.3) @@ -763,6 +765,7 @@ DEPENDENCIES redcarpet (~> 3.2.3) redis-rails request_store + rerun (~> 0.10.0) rspec-rails (= 2.99) rubocop (= 0.28.0) rugments diff --git a/app/assets/stylesheets/base/gl_bootstrap.scss b/app/assets/stylesheets/base/gl_bootstrap.scss index 427f333423c..21acbfa5e5a 100644 --- a/app/assets/stylesheets/base/gl_bootstrap.scss +++ b/app/assets/stylesheets/base/gl_bootstrap.scss @@ -137,6 +137,12 @@ color: #666; } +.nav-pills > .active > a > span > .badge { + background-color: #fff; + color: $gl-primary; +} + + /** * fix to keep tooltips position in top navigation bar * diff --git a/app/assets/stylesheets/generic/common.scss b/app/assets/stylesheets/generic/common.scss index 7c3021989a8..1e569978cc8 100644 --- a/app/assets/stylesheets/generic/common.scss +++ b/app/assets/stylesheets/generic/common.scss @@ -333,17 +333,8 @@ table { } .search_box { - position: relative; - padding: 30px; + @extend .well; text-align: center; - background-color: #F9F9F9; - border: 1px solid #DDDDDD; - border-radius: 0px; -} - -.search_glyph { - color: #555; - font-size: 42px; } .task-status { diff --git a/app/assets/stylesheets/generic/header.scss b/app/assets/stylesheets/generic/header.scss index b861646191f..df1553d8594 100644 --- a/app/assets/stylesheets/generic/header.scss +++ b/app/assets/stylesheets/generic/header.scss @@ -10,7 +10,10 @@ header { border: none; width: 100%; - .navbar-inner { + .container { + width: 100% !important; + padding: 0; + background: #FFF; border-bottom: 1px solid #DDD; filter: none; @@ -123,11 +126,6 @@ header { } } - .container { - width: 100% !important; - padding: 0px; - } - /** * * Logo holder diff --git a/app/assets/stylesheets/generic/mobile.scss b/app/assets/stylesheets/generic/mobile.scss index c9bbacd7348..b7f6fac5223 100644 --- a/app/assets/stylesheets/generic/mobile.scss +++ b/app/assets/stylesheets/generic/mobile.scss @@ -56,7 +56,7 @@ } } - .navbar-inner .title { + .container .title { margin-left: 6px !important; max-width: 70% !important; } diff --git a/app/assets/stylesheets/pages/issuable.scss b/app/assets/stylesheets/pages/issuable.scss index a640a4e2051..586e7b5f8da 100644 --- a/app/assets/stylesheets/pages/issuable.scss +++ b/app/assets/stylesheets/pages/issuable.scss @@ -19,7 +19,7 @@ &.affix { position: fixed; top: 70px; - width: 220px; + margin-right: 35px; } } } diff --git a/app/assets/stylesheets/themes/gitlab-theme.scss b/app/assets/stylesheets/themes/gitlab-theme.scss index ee75fe61881..139b3cc1ac4 100644 --- a/app/assets/stylesheets/themes/gitlab-theme.scss +++ b/app/assets/stylesheets/themes/gitlab-theme.scss @@ -1,19 +1,17 @@ @mixin gitlab-theme($color-light, $color, $color-darker, $color-dark) { header { &.navbar-gitlab { - .navbar-inner { - .app_logo { - background-color: $color-darker; + .app_logo { + background-color: $color-darker; - a { - color: $color-light; - } + a { + color: $color-light; + } - &:hover { - background-color: $color-dark; - a { - color: #FFF; - } + &:hover { + background-color: $color-dark; + a { + color: #FFF; } } } diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index cfe2c76265c..69fd7901832 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -182,18 +182,6 @@ class ApplicationController < ActionController::Base response.headers["Expires"] = "Fri, 01 Jan 1990 00:00:00 GMT" end - def default_url_options - if !Rails.env.test? - port = Gitlab.config.gitlab.port unless Gitlab.config.gitlab_on_standard_port? - { host: Gitlab.config.gitlab.host, - protocol: Gitlab.config.gitlab.protocol, - port: port, - script_name: Gitlab.config.gitlab.relative_url_root } - else - super - end - end - def default_headers headers['X-Frame-Options'] = 'DENY' headers['X-XSS-Protection'] = '1; mode=block' diff --git a/app/controllers/projects/merge_requests_controller.rb b/app/controllers/projects/merge_requests_controller.rb index 41b4e55a598..5b93e95866a 100644 --- a/app/controllers/projects/merge_requests_controller.rb +++ b/app/controllers/projects/merge_requests_controller.rb @@ -124,13 +124,13 @@ class Projects::MergeRequestsController < Projects::ApplicationController @merge_request.check_if_can_be_merged end - render json: { merge_status: @merge_request.merge_status_name } + render json: { merge_status: @merge_request.automerge_status } end def automerge return access_denied! unless allowed_to_merge? - if @merge_request.open? && @merge_request.can_be_merged? + if @merge_request.automergeable? AutoMergeWorker.perform_async(@merge_request.id, current_user.id, params) @status = true else diff --git a/app/controllers/projects/services_controller.rb b/app/controllers/projects/services_controller.rb index 2080ee9a00f..dc18bbd8d5b 100644 --- a/app/controllers/projects/services_controller.rb +++ b/app/controllers/projects/services_controller.rb @@ -1,5 +1,5 @@ class Projects::ServicesController < Projects::ApplicationController - ALLOWED_PARAMS = [:title, :token, :type, :active, :api_key, :subdomain, + ALLOWED_PARAMS = [:title, :token, :type, :active, :api_key, :api_version, :subdomain, :room, :recipients, :project_url, :webhook, :user_key, :device, :priority, :sound, :bamboo_url, :username, :password, :build_key, :server, :teamcity_url, :build_type, diff --git a/app/controllers/search_controller.rb b/app/controllers/search_controller.rb index c5828d0b2df..ad9e9e8487e 100644 --- a/app/controllers/search_controller.rb +++ b/app/controllers/search_controller.rb @@ -4,20 +4,22 @@ class SearchController < ApplicationController def show return if params[:search].nil? || params[:search].blank? + @search_term = params[:search] + if params[:project_id].present? @project = Project.find_by(id: params[:project_id]) @project = nil unless can?(current_user, :download_code, @project) end if params[:group_id].present? - @group = Group.find_by(id: params[:group_id]) + @group = Group.find_by(id: params[:group_id]) @group = nil unless can?(current_user, :read_group, @group) end - + @scope = params[:scope] @show_snippets = params[:snippets].eql? 'true' - @search_results = + @search_results = if @project unless %w(blobs notes issues merge_requests wiki_blobs). include?(@scope) @@ -37,6 +39,7 @@ class SearchController < ApplicationController end Search::GlobalService.new(current_user, params).execute end + @objects = @search_results.objects(@scope, params[:page]) end diff --git a/app/helpers/gitlab_markdown_helper.rb b/app/helpers/gitlab_markdown_helper.rb index aff7011edd0..bc234500000 100644 --- a/app/helpers/gitlab_markdown_helper.rb +++ b/app/helpers/gitlab_markdown_helper.rb @@ -49,7 +49,8 @@ module GitlabMarkdownHelper strikethrough: true, lax_spacing: true, space_after_headers: true, - superscript: true + superscript: true, + footnotes: true ) end diff --git a/app/mailers/notify.rb b/app/mailers/notify.rb index 2c0d451511f..79fb48b00d3 100644 --- a/app/mailers/notify.rb +++ b/app/mailers/notify.rb @@ -16,11 +16,6 @@ class Notify < ActionMailer::Base attr_accessor :current_user helper_method :current_user, :can? - default_url_options[:host] = Gitlab.config.gitlab.host - default_url_options[:protocol] = Gitlab.config.gitlab.protocol - default_url_options[:port] = Gitlab.config.gitlab.port unless Gitlab.config.gitlab_on_standard_port? - default_url_options[:script_name] = Gitlab.config.gitlab.relative_url_root - default from: Proc.new { default_sender_address.format } default reply_to: Gitlab.config.gitlab.email_reply_to @@ -69,7 +64,7 @@ class Notify < ActionMailer::Base # Only the displayed name changes; the actual email address is always the same. def sender(sender_id, send_from_user_email = false) return unless sender = User.find(sender_id) - + address = default_sender_address address.display_name = sender.name diff --git a/app/models/merge_request.rb b/app/models/merge_request.rb index 49a00697ee1..64f3c39f131 100644 --- a/app/models/merge_request.rb +++ b/app/models/merge_request.rb @@ -199,6 +199,8 @@ class MergeRequest < ActiveRecord::Base end def automerge!(current_user, commit_message = nil) + return unless automergeable? + MergeRequests::AutoMergeService. new(target_project, current_user). execute(self, commit_message) @@ -208,6 +210,22 @@ class MergeRequest < ActiveRecord::Base opened? || reopened? end + def work_in_progress? + title =~ /\A\[?WIP\]?:? /i + end + + def automergeable? + open? && !work_in_progress? && can_be_merged? + end + + def automerge_status + if work_in_progress? + "work_in_progress" + else + merge_status_name + end + end + def mr_and_commit_notes # Fetch comments only from last 100 commits commits_for_notes_limit = 100 diff --git a/app/models/project_services/gitlab_issue_tracker_service.rb b/app/models/project_services/gitlab_issue_tracker_service.rb index 5f0553f3b0b..0ebc0a3ba1a 100644 --- a/app/models/project_services/gitlab_issue_tracker_service.rb +++ b/app/models/project_services/gitlab_issue_tracker_service.rb @@ -21,11 +21,6 @@ class GitlabIssueTrackerService < IssueTrackerService include Rails.application.routes.url_helpers - default_url_options[:host] = Gitlab.config.gitlab.host - default_url_options[:protocol] = Gitlab.config.gitlab.protocol - default_url_options[:port] = Gitlab.config.gitlab.port unless Gitlab.config.gitlab_on_standard_port? - default_url_options[:script_name] = Gitlab.config.gitlab.relative_url_root - prop_accessor :title, :description, :project_url, :issues_url, :new_issue_url def default? diff --git a/app/models/project_services/hipchat_service.rb b/app/models/project_services/hipchat_service.rb index 2fa5f0ce71c..3a15b2207ea 100644 --- a/app/models/project_services/hipchat_service.rb +++ b/app/models/project_services/hipchat_service.rb @@ -20,7 +20,7 @@ class HipchatService < Service MAX_COMMITS = 3 - prop_accessor :token, :room, :server, :notify, :color + prop_accessor :token, :room, :server, :notify, :color, :api_version validates :token, presence: true, if: :activated? def title @@ -41,6 +41,8 @@ class HipchatService < Service { type: 'text', name: 'room', placeholder: 'Room name or ID' }, { type: 'checkbox', name: 'notify' }, { type: 'select', name: 'color', choices: ['yellow', 'red', 'green', 'purple', 'gray', 'random'] }, + { type: 'text', name: 'api_version', + placeholder: 'Leave blank for default (v2)' }, { type: 'text', name: 'server', placeholder: 'Leave blank for default. https://hipchat.example.com' } ] @@ -60,7 +62,7 @@ class HipchatService < Service private def gate - options = { api_version: 'v2' } + options = { api_version: api_version || 'v2' } options[:server_url] = server unless server.blank? @gate ||= HipChat::Client.new(token, options) end diff --git a/app/views/admin/application_settings/_form.html.haml b/app/views/admin/application_settings/_form.html.haml index 98d3e00153d..87e7c9634e9 100644 --- a/app/views/admin/application_settings/_form.html.haml +++ b/app/views/admin/application_settings/_form.html.haml @@ -42,11 +42,11 @@ = f.label :default_branch_protection, class: 'control-label col-sm-2' .col-sm-10 = f.select :default_branch_protection, options_for_select(Gitlab::Access.protection_options, @application_setting.default_branch_protection), {}, class: 'form-control' - .form-group + .form-group.project-visibility-level-holder = f.label :default_project_visibility, class: 'control-label col-sm-2' .col-sm-10 = render('shared/visibility_radios', model_method: :default_project_visibility, form: f, selected_level: @application_setting.default_project_visibility, form_model: 'Project') - .form-group + .form-group.project-visibility-level-holder = f.label :default_snippet_visibility, class: 'control-label col-sm-2' .col-sm-10 = render('shared/visibility_radios', model_method: :default_snippet_visibility, form: f, selected_level: @application_setting.default_snippet_visibility, form_model: 'Snippet') diff --git a/app/views/admin/groups/show.html.haml b/app/views/admin/groups/show.html.haml index 14996dcd6a2..427f38018b0 100644 --- a/app/views/admin/groups/show.html.haml +++ b/app/views/admin/groups/show.html.haml @@ -60,7 +60,7 @@ = form_tag members_update_admin_group_path(@group), id: "new_project_member", class: "bulk_import", method: :put do %div - = users_select_tag(:user_ids, multiple: true, email_user: true) + = users_select_tag(:user_ids, multiple: true, email_user: true, scope: :all) %div.prepend-top-10 = select_tag :access_level, options_for_select(GroupMember.access_level_roles), class: "project-access-select select2" %hr diff --git a/app/views/admin/projects/index.html.haml b/app/views/admin/projects/index.html.haml index 3bbe10bc270..0a13791029d 100644 --- a/app/views/admin/projects/index.html.haml +++ b/app/views/admin/projects/index.html.haml @@ -1,6 +1,6 @@ += render 'shared/show_aside' + .row - = link_to '#aside', class: 'show-aside' do - %i.fa.fa-angle-left %aside.col-md-3 .admin-filter = form_tag admin_namespaces_projects_path, method: :get, class: '' do diff --git a/app/views/admin/services/_form.html.haml b/app/views/admin/services/_form.html.haml index 34ca7776c9e..cdbfc60f9a4 100644 --- a/app/views/admin/services/_form.html.haml +++ b/app/views/admin/services/_form.html.haml @@ -4,79 +4,7 @@ %p #{@service.description} template = form_for :service, url: admin_application_settings_service_path, method: :put, html: { class: 'form-horizontal fieldset-form' } do |form| - - if @service.errors.any? - #error_explanation - .alert.alert-danger - - @service.errors.full_messages.each do |msg| - %p= msg - - if @service.help.present? - .well - = preserve do - = markdown @service.help - - .form-group - = form.label :active, "Active", class: "control-label" - .col-sm-10 - = form.check_box :active - - - if @service.supported_events.length > 1 - .form-group - = form.label :url, "Trigger", class: 'control-label' - .col-sm-10 - - if @service.supported_events.include?("push") - %div - = form.check_box :push_events, class: 'pull-left' - .prepend-left-20 - = form.label :push_events, class: 'list-label' do - %strong Push events - %p.light - This url will be triggered by a push to the repository - - if @service.supported_events.include?("tag_push") - %div - = form.check_box :tag_push_events, class: 'pull-left' - .prepend-left-20 - = form.label :tag_push_events, class: 'list-label' do - %strong Tag push events - %p.light - This url will be triggered when a new tag is pushed to the repository - - if @service.supported_events.include?("note") - %div - = form.check_box :note_events, class: 'pull-left' - .prepend-left-20 - = form.label :note_events, class: 'list-label' do - %strong Comments - %p.light - This url will be triggered when someone adds a comment - - if @service.supported_events.include?("issue") - %div - = form.check_box :issues_events, class: 'pull-left' - .prepend-left-20 - = form.label :issues_events, class: 'list-label' do - %strong Issues events - %p.light - This url will be triggered when an issue is created - - if @service.supported_events.include?("merge_request") - %div - = form.check_box :merge_requests_events, class: 'pull-left' - .prepend-left-20 - = form.label :merge_requests_events, class: 'list-label' do - %strong Merge Request events - %p.light - This url will be triggered when a merge request is created - - - @service.fields.each do |field| - - type = field[:type] - - - if type == 'fieldset' - - fields = field[:fields] - - legend = field[:legend] - - %fieldset - %legend= legend - - fields.each do |subfield| - = render 'shared/field', form: form, field: subfield - - else - = render 'shared/field', form: form, field: field + = render 'shared/service_settings', form: form .form-actions = form.submit 'Save', class: 'btn btn-save' diff --git a/app/views/admin/users/index.html.haml b/app/views/admin/users/index.html.haml index 25c1730ef70..23a9d769639 100644 --- a/app/views/admin/users/index.html.haml +++ b/app/views/admin/users/index.html.haml @@ -1,6 +1,6 @@ += render 'shared/show_aside' + .row - = link_to '#aside', class: 'show-aside' do - %i.fa.fa-angle-left %aside.col-md-3 .admin-filter %ul.nav.nav-pills.nav-stacked diff --git a/app/views/dashboard/projects/starred.html.haml b/app/views/dashboard/projects/starred.html.haml index f4ad2b294b3..67943f2267b 100644 --- a/app/views/dashboard/projects/starred.html.haml +++ b/app/views/dashboard/projects/starred.html.haml @@ -1,4 +1,6 @@ - if @projects.any? + = render 'shared/show_aside' + .dashboard.row %section.activities.col-md-8 = render 'dashboard/activities' @@ -15,9 +17,6 @@ = render 'shared/projects_list', projects: @projects, projects_limit: 20, stars: true, avatar: false - = link_to '#aside', class: 'show-aside' do - %i.fa.fa-angle-left - - else %h3 You don't have starred projects yet %p.slead Visit project page and press on star icon and it will appear on this page. diff --git a/app/views/dashboard/show.html.haml b/app/views/dashboard/show.html.haml index 2754a4894da..5001c2101e1 100644 --- a/app/views/dashboard/show.html.haml +++ b/app/views/dashboard/show.html.haml @@ -3,13 +3,13 @@ = auto_discovery_link_tag(:atom, dashboard_url(format: :atom, private_token: current_user.private_token), title: "All activity") - if @projects.any? + = render 'shared/show_aside' + .dashboard.row %section.activities.col-md-8 = render 'activities' %aside.col-md-4 = render 'sidebar' - = link_to '#aside', class: 'show-aside' do - %i.fa.fa-angle-left - else = render "zero_authorized_projects" diff --git a/app/views/groups/show.html.haml b/app/views/groups/show.html.haml index 3db0dfa59b1..1678311141e 100644 --- a/app/views/groups/show.html.haml +++ b/app/views/groups/show.html.haml @@ -13,6 +13,9 @@ .description = escaped_autolink(@group.description) %hr + + = render 'shared/show_aside' + .row %section.activities.col-md-8 .hidden-xs @@ -33,5 +36,3 @@ = spinner %aside.side.col-md-4 = render "projects", projects: @projects - = link_to '#aside', class: 'show-aside' do - %i.fa.fa-angle-left diff --git a/app/views/layouts/_empty_head_panel.html.haml b/app/views/layouts/_empty_head_panel.html.haml index b81c2d0364b..358caa3868b 100644 --- a/app/views/layouts/_empty_head_panel.html.haml +++ b/app/views/layouts/_empty_head_panel.html.haml @@ -1,5 +1,4 @@ %header.navbar.navbar-fixed-top.navbar-gitlab - .navbar-inner - .container - %h4.center - = image_tag 'logo-white.png', width: 32, height: 32 + .container + %h4.center + = image_tag 'logo-white.png', width: 32, height: 32 diff --git a/app/views/layouts/_head_panel.html.haml b/app/views/layouts/_head_panel.html.haml index fc4656be079..3329a712430 100644 --- a/app/views/layouts/_head_panel.html.haml +++ b/app/views/layouts/_head_panel.html.haml @@ -1,48 +1,47 @@ %header.navbar.navbar-fixed-top.navbar-gitlab{ class: nav_header_class } .container - .navbar-inner - %div.app_logo - = link_to root_path, class: 'home', title: 'Dashboard', id: 'js-shortcuts-home', data: {toggle: 'tooltip', placement: 'bottom'} do - = brand_header_logo - %h3 GitLab - %h1.title= title + %div.app_logo + = link_to root_path, class: 'home', title: 'Dashboard', id: 'js-shortcuts-home', data: {toggle: 'tooltip', placement: 'bottom'} do + = brand_header_logo + %h3 GitLab + %h1.title= title - %button.navbar-toggle{type: 'button', data: {target: '.navbar-collapse', toggle: 'collapse'}} - %span.sr-only Toggle navigation - = icon('bars') + %button.navbar-toggle{type: 'button', data: {target: '.navbar-collapse', toggle: 'collapse'}} + %span.sr-only Toggle navigation + = icon('bars') - .navbar-collapse.collapse - %ul.nav.navbar-nav - %li.hidden-sm.hidden-xs - = render 'layouts/search' - %li.visible-sm.visible-xs - = link_to search_path, title: 'Search', data: {toggle: 'tooltip', placement: 'bottom'} do - = icon('search') + .navbar-collapse.collapse + %ul.nav.navbar-nav + %li.hidden-sm.hidden-xs + = render 'layouts/search' + %li.visible-sm.visible-xs + = link_to search_path, title: 'Search', data: {toggle: 'tooltip', placement: 'bottom'} do + = icon('search') + %li + = link_to help_path, title: 'Help', data: {toggle: 'tooltip', placement: 'bottom'} do + = icon('question-circle') + %li + = link_to explore_root_path, title: 'Explore', data: {toggle: 'tooltip', placement: 'bottom'} do + = icon('globe') + %li + = link_to user_snippets_path(current_user), title: 'Your snippets', data: {toggle: 'tooltip', placement: 'bottom'} do + = icon('clipboard') + - if current_user.is_admin? %li - = link_to help_path, title: 'Help', data: {toggle: 'tooltip', placement: 'bottom'} do - = icon('question-circle') + = link_to admin_root_path, title: 'Admin area', data: {toggle: 'tooltip', placement: 'bottom'} do + = icon('cogs') + - if current_user.can_create_project? %li - = link_to explore_root_path, title: 'Explore', data: {toggle: 'tooltip', placement: 'bottom'} do - = icon('globe') - %li - = link_to user_snippets_path(current_user), title: 'Your snippets', data: {toggle: 'tooltip', placement: 'bottom'} do - = icon('clipboard') - - if current_user.is_admin? - %li - = link_to admin_root_path, title: 'Admin area', data: {toggle: 'tooltip', placement: 'bottom'} do - = icon('cogs') - - if current_user.can_create_project? - %li - = link_to new_project_path, title: 'New project', data: {toggle: 'tooltip', placement: 'bottom'} do - = icon('plus') - %li - = link_to profile_path, title: 'Profile settings', data: {toggle: 'tooltip', placement: 'bottom'} do - = icon('user') - %li - = link_to destroy_user_session_path, class: 'logout', method: :delete, title: 'Sign out', data: {toggle: 'tooltip', placement: 'bottom'} do - = icon('sign-out') - %li.hidden-xs - = link_to current_user, class: 'profile-pic', id: 'profile-pic', data: {toggle: 'tooltip', placement: 'bottom'} do - = image_tag avatar_icon(current_user.email, 60), alt: 'User activity' + = link_to new_project_path, title: 'New project', data: {toggle: 'tooltip', placement: 'bottom'} do + = icon('plus') + %li + = link_to profile_path, title: 'Profile settings', data: {toggle: 'tooltip', placement: 'bottom'} do + = icon('user') + %li + = link_to destroy_user_session_path, class: 'logout', method: :delete, title: 'Sign out', data: {toggle: 'tooltip', placement: 'bottom'} do + = icon('sign-out') + %li.hidden-xs + = link_to current_user, class: 'profile-pic', id: 'profile-pic', data: {toggle: 'tooltip', placement: 'bottom'} do + = image_tag avatar_icon(current_user.email, 60), alt: 'User activity' = render 'shared/outdated_browser' diff --git a/app/views/layouts/_public_head_panel.html.haml b/app/views/layouts/_public_head_panel.html.haml index 98a87a39bd4..8a297566d6c 100644 --- a/app/views/layouts/_public_head_panel.html.haml +++ b/app/views/layouts/_public_head_panel.html.haml @@ -1,23 +1,22 @@ %header.navbar.navbar-fixed-top.navbar-gitlab{ class: nav_header_class } - .navbar-inner - .container - %div.app_logo - = link_to explore_root_path, class: "home" do - = brand_header_logo - %h3 GitLab - %h1.title= title + .container + %div.app_logo + = link_to explore_root_path, class: "home" do + = brand_header_logo + %h3 GitLab + %h1.title= title - %button.navbar-toggle{"data-target" => ".navbar-collapse", "data-toggle" => "collapse", type: "button"} - %span.sr-only Toggle navigation - %i.fa.fa-bars + %button.navbar-toggle{"data-target" => ".navbar-collapse", "data-toggle" => "collapse", type: "button"} + %span.sr-only Toggle navigation + %i.fa.fa-bars - - unless current_controller?('sessions') - .pull-right.hidden-xs - = link_to "Sign in", new_session_path(:user, redirect_to_referer: 'yes'), class: 'btn btn-sign-in btn-new append-right-10' + - unless current_controller?('sessions') + .pull-right.hidden-xs + = link_to "Sign in", new_session_path(:user, redirect_to_referer: 'yes'), class: 'btn btn-sign-in btn-new append-right-10' - .navbar-collapse.collapse - %ul.nav.navbar-nav - %li.visible-xs - = link_to "Sign in", new_session_path(:user, redirect_to_referer: 'yes') + .navbar-collapse.collapse + %ul.nav.navbar-nav + %li.visible-xs + = link_to "Sign in", new_session_path(:user, redirect_to_referer: 'yes') = render 'shared/outdated_browser' diff --git a/app/views/layouts/search.html.haml b/app/views/layouts/search.html.haml index f9d8db06e10..4b526686be4 100644 --- a/app/views/layouts/search.html.haml +++ b/app/views/layouts/search.html.haml @@ -2,9 +2,5 @@ %html{ lang: "en"} = render "layouts/head", title: "Search" %body{class: "#{app_theme} application", :'data-page' => body_data_page} - = render "layouts/broadcast" = render "layouts/head_panel", title: link_to("Search", search_path) - .container.navless-container - .content - = render "layouts/flash" - = yield + = render 'layouts/page' diff --git a/app/views/projects/issues/_discussion.html.haml b/app/views/projects/issues/_discussion.html.haml index 288b48f4583..ceca2653016 100644 --- a/app/views/projects/issues/_discussion.html.haml +++ b/app/views/projects/issues/_discussion.html.haml @@ -4,6 +4,9 @@ = link_to 'Reopen Issue', issue_path(@issue, issue: {state_event: :reopen }, status_only: true), method: :put, class: "btn btn-grouped btn-reopen js-note-target-reopen", title: 'Reopen Issue' - else = link_to 'Close Issue', issue_path(@issue, issue: {state_event: :close }, status_only: true), method: :put, class: "btn btn-grouped btn-close js-note-target-close", title: "Close Issue" + += render 'shared/show_aside' + .row %section.col-md-9 .votes-holder.pull-right @@ -29,5 +32,3 @@ - @issue.labels.each do |label| = link_to namespace_project_issues_path(@project.namespace, @project, label_name: label.name) do = render_colored_label(label) - = link_to '#aside', class: 'show-aside' do - %i.fa.fa-angle-left diff --git a/app/views/projects/merge_requests/_discussion.html.haml b/app/views/projects/merge_requests/_discussion.html.haml index eb72eaabd8b..9a2aa9c3de0 100644 --- a/app/views/projects/merge_requests/_discussion.html.haml +++ b/app/views/projects/merge_requests/_discussion.html.haml @@ -5,6 +5,8 @@ - if @merge_request.closed? = link_to 'Reopen', merge_request_path(@merge_request, merge_request: {state_event: :reopen }), method: :put, class: "btn btn-grouped btn-reopen reopen-mr-link js-note-target-reopen", title: "Reopen merge request" += render 'shared/show_aside' + .row %section.col-md-9 .votes-holder.pull-right @@ -27,5 +29,3 @@ - @merge_request.labels.each do |label| = link_to namespace_project_merge_requests_path(@project.namespace, @project, label_name: label.name) do = render_colored_label(label) - = link_to '#aside', class: 'show-aside' do - %i.fa.fa-angle-left diff --git a/app/views/projects/merge_requests/_show.html.haml b/app/views/projects/merge_requests/_show.html.haml index cec02de84ca..45dd410dd15 100644 --- a/app/views/projects/merge_requests/_show.html.haml +++ b/app/views/projects/merge_requests/_show.html.haml @@ -72,6 +72,6 @@ check_enable: #{@merge_request.unchecked? ? "true" : "false"}, url_to_ci_check: "#{ci_status_namespace_project_merge_request_path(@project.namespace, @project, @merge_request)}", ci_enable: #{@project.ci_service ? "true" : "false"}, - current_status: "#{@merge_request.merge_status_name}", + current_status: "#{@merge_request.automerge_status}", action: "#{controller.action_name}" }); diff --git a/app/views/projects/merge_requests/show/_mr_accept.html.haml b/app/views/projects/merge_requests/show/_mr_accept.html.haml index 9f51f84d400..41f739a45b8 100644 --- a/app/views/projects/merge_requests/show/_mr_accept.html.haml +++ b/app/views/projects/merge_requests/show/_mr_accept.html.haml @@ -4,9 +4,11 @@ %strong Archived projects cannot be committed to! - else .automerge_widget.cannot_be_merged.hide - %strong This can't be merged automatically, even if it could be merged you don't have the permission to do so. + %strong This request can't be merged automatically. Even if it could be merged, you don't have permission to do so. + .automerge_widget.work_in_progress.hide + %strong This request can't be merged automatically because it is marked a Work In Progress. Even if it could be merged, you don't have permission to do so. .automerge_widget.can_be_merged.hide - %strong This can be merged automatically but you don't have the permission to do so. + %strong This request can be merged automatically, but you don't have permission to do so. - if @show_merge_controls @@ -57,6 +59,18 @@ This usually happens when git can not resolve conflicts between branches automatically. + .automerge_widget.work_in_progress.hide + %h4 + This request can't be merged because it is marked a <strong>Work In Progress</strong>. + + %p + %button.btn.disabled + %i.fa.fa-warning + Accept Merge Request + + + When the merge request is ready, remove the "WIP" prefix from the title to allow it to be merged. + .automerge_widget.unchecked %p %strong diff --git a/app/views/projects/services/_form.html.haml b/app/views/projects/services/_form.html.haml index 1b465e3addd..e1823b51198 100644 --- a/app/views/projects/services/_form.html.haml +++ b/app/views/projects/services/_form.html.haml @@ -11,80 +11,7 @@ %hr = form_for(@service, as: :service, url: namespace_project_service_path(@project.namespace, @project, @service.to_param), method: :put, html: { class: 'form-horizontal' }) do |form| - - if @service.errors.any? - .alert.alert-danger - %ul - - @service.errors.full_messages.each do |msg| - %li= msg - - - if @service.help.present? - .well - = preserve do - = markdown @service.help - - .form-group - = form.label :active, "Active", class: "control-label" - .col-sm-10 - = form.check_box :active - - - if @service.supported_events.length > 1 - .form-group - = form.label :url, "Trigger", class: 'control-label' - .col-sm-10 - - if @service.supported_events.include?("push") - %div - = form.check_box :push_events, class: 'pull-left' - .prepend-left-20 - = form.label :push_events, class: 'list-label' do - %strong Push events - %p.light - This url will be triggered by a push to the repository - - if @service.supported_events.include?("tag_push") - %div - = form.check_box :tag_push_events, class: 'pull-left' - .prepend-left-20 - = form.label :tag_push_events, class: 'list-label' do - %strong Tag push events - %p.light - This url will be triggered when a new tag is pushed to the repository - - if @service.supported_events.include?("note") - %div - = form.check_box :note_events, class: 'pull-left' - .prepend-left-20 - = form.label :note_events, class: 'list-label' do - %strong Comments - %p.light - This url will be triggered when someone adds a comment - - if @service.supported_events.include?("issue") - %div - = form.check_box :issues_events, class: 'pull-left' - .prepend-left-20 - = form.label :issues_events, class: 'list-label' do - %strong Issues events - %p.light - This url will be triggered when an issue is created - - if @service.supported_events.include?("merge_request") - %div - = form.check_box :merge_requests_events, class: 'pull-left' - .prepend-left-20 - = form.label :merge_requests_events, class: 'list-label' do - %strong Merge Request events - %p.light - This url will be triggered when a merge request is created - - - @service.fields.each do |field| - - type = field[:type] - - - if type == 'fieldset' - - fields = field[:fields] - - legend = field[:legend] - - %fieldset - %legend= legend - - fields.each do |subfield| - = render 'shared/field', form: form, field: subfield - - else - = render 'shared/field', form: form, field: field + = render 'shared/service_settings', form: form .form-actions = form.submit 'Save', class: 'btn btn-save' diff --git a/app/views/projects/show.html.haml b/app/views/projects/show.html.haml index 1787caa243d..cd18ae0c8da 100644 --- a/app/views/projects/show.html.haml +++ b/app/views/projects/show.html.haml @@ -37,9 +37,9 @@ .tab-content .tab-pane.active#tab-activity + = render 'shared/show_aside' + .row - = link_to '#aside', class: 'show-aside' do - %i.fa.fa-angle-left %section.col-md-9 .hidden-xs = render "events/event_last_push", event: @last_push diff --git a/app/views/search/_category.html.haml b/app/views/search/_category.html.haml new file mode 100644 index 00000000000..154332cb9a9 --- /dev/null +++ b/app/views/search/_category.html.haml @@ -0,0 +1,77 @@ +%ul.nav.nav-pills.search-filter + - if @project + %li{class: ("active" if @scope == 'blobs')} + = link_to search_filter_path(scope: 'blobs') do + = icon('code fw') + %span + Code + %span.badge + = @search_results.blobs_count + %li{class: ("active" if @scope == 'issues')} + = link_to search_filter_path(scope: 'issues') do + = icon('exclamation-circle fw') + %span + Issues + %span.badge + = @search_results.issues_count + %li{class: ("active" if @scope == 'merge_requests')} + = link_to search_filter_path(scope: 'merge_requests') do + = icon('tasks fw') + %span + Merge requests + %span.badge + = @search_results.merge_requests_count + %li{class: ("active" if @scope == 'notes')} + = link_to search_filter_path(scope: 'notes') do + = icon('comments fw') + %span + Comments + %span.badge + = @search_results.notes_count + %li{class: ("active" if @scope == 'wiki_blobs')} + = link_to search_filter_path(scope: 'wiki_blobs') do + = icon('book fw') + %span + Wiki + %span.badge + = @search_results.wiki_blobs_count + + - elsif @show_snippets + %li{class: ("active" if @scope == 'snippet_blobs')} + = link_to search_filter_path(scope: 'snippet_blobs', snippets: true, group_id: nil, project_id: nil) do + = icon('code fw') + %span + Snippet Contents + %span.badge + = @search_results.snippet_blobs_count + %li{class: ("active" if @scope == 'snippet_titles')} + = link_to search_filter_path(scope: 'snippet_titles', snippets: true, group_id: nil, project_id: nil) do + = icon('book fw') + %span + Titles and Filenames + %span.badge + = @search_results.snippet_titles_count + + - else + %li{class: ("active" if @scope == 'projects')} + = link_to search_filter_path(scope: 'projects') do + = icon('bookmark fw') + %span + Projects + %span.badge + = @search_results.projects_count + %li{class: ("active" if @scope == 'issues')} + = link_to search_filter_path(scope: 'issues') do + = icon('exclamation-circle fw') + %span + Issues + %span.badge + = @search_results.issues_count + %li{class: ("active" if @scope == 'merge_requests')} + = link_to search_filter_path(scope: 'merge_requests') do + = icon('tasks fw') + %span + Merge requests + %span.badge + = @search_results.merge_requests_count + diff --git a/app/views/search/_filter.html.haml b/app/views/search/_filter.html.haml index ffc145497ab..e2d0cab9e79 100644 --- a/app/views/search/_filter.html.haml +++ b/app/views/search/_filter.html.haml @@ -1,5 +1,5 @@ .dropdown.inline - %button.dropdown-toggle.btn.btn-sm{type: 'button', 'data-toggle' => 'dropdown'} + %button.dropdown-toggle.btn.btn{type: 'button', 'data-toggle' => 'dropdown'} %i.fa.fa-tags %span.light Group: - if @group.present? @@ -17,7 +17,7 @@ = group.name .dropdown.inline.prepend-left-10.project-filter - %button.dropdown-toggle.btn.btn-sm{type: 'button', 'data-toggle' => 'dropdown'} + %button.dropdown-toggle.btn.btn{type: 'button', 'data-toggle' => 'dropdown'} %i.fa.fa-tags %span.light Project: - if @project.present? diff --git a/app/views/search/_form.html.haml b/app/views/search/_form.html.haml new file mode 100644 index 00000000000..47016daf1f0 --- /dev/null +++ b/app/views/search/_form.html.haml @@ -0,0 +1,12 @@ += form_tag search_path, method: :get, class: 'form-inline' do |f| + = hidden_field_tag :project_id, params[:project_id] + = hidden_field_tag :group_id, params[:group_id] + = hidden_field_tag :snippets, params[:snippets] + = hidden_field_tag :scope, params[:scope] + .search-holder.clearfix + .form-group + = search_field_tag :search, params[:search], placeholder: "Search for projects, issues etc", class: "form-control search-text-input input-mn-300", id: "dashboard_search", autofocus: true + = button_tag 'Search', class: "btn btn-primary" + - unless params[:snippets].eql? 'true' + .pull-right + = render 'filter' diff --git a/app/views/search/_global_filter.html.haml b/app/views/search/_global_filter.html.haml deleted file mode 100644 index 442bd84f930..00000000000 --- a/app/views/search/_global_filter.html.haml +++ /dev/null @@ -1,16 +0,0 @@ -%ul.nav.nav-pills.nav-stacked.search-filter - %li{class: ("active" if @scope == 'projects')} - = link_to search_filter_path(scope: 'projects') do - Projects - .pull-right - = @search_results.projects_count - %li{class: ("active" if @scope == 'issues')} - = link_to search_filter_path(scope: 'issues') do - Issues - .pull-right - = @search_results.issues_count - %li{class: ("active" if @scope == 'merge_requests')} - = link_to search_filter_path(scope: 'merge_requests') do - Merge requests - .pull-right - = @search_results.merge_requests_count diff --git a/app/views/search/_project_filter.html.haml b/app/views/search/_project_filter.html.haml deleted file mode 100644 index ad933502a28..00000000000 --- a/app/views/search/_project_filter.html.haml +++ /dev/null @@ -1,32 +0,0 @@ -%ul.nav.nav-pills.nav-stacked.search-filter - %li{class: ("active" if @scope == 'blobs')} - = link_to search_filter_path(scope: 'blobs') do - %i.fa.fa-code - Code - .pull-right - = @search_results.blobs_count - %li{class: ("active" if @scope == 'issues')} - = link_to search_filter_path(scope: 'issues') do - %i.fa.fa-exclamation-circle - Issues - .pull-right - = @search_results.issues_count - %li{class: ("active" if @scope == 'merge_requests')} - = link_to search_filter_path(scope: 'merge_requests') do - %i.fa.fa-code-fork - Merge requests - .pull-right - = @search_results.merge_requests_count - %li{class: ("active" if @scope == 'notes')} - = link_to search_filter_path(scope: 'notes') do - %i.fa.fa-comments - Comments - .pull-right - = @search_results.notes_count - %li{class: ("active" if @scope == 'wiki_blobs')} - = link_to search_filter_path(scope: 'wiki_blobs') do - %i.fa.fa-book - Wiki - .pull-right - = @search_results.wiki_blobs_count - diff --git a/app/views/search/_results.html.haml b/app/views/search/_results.html.haml index 796dd752a4c..741c780ad96 100644 --- a/app/views/search/_results.html.haml +++ b/app/views/search/_results.html.haml @@ -1,28 +1,21 @@ -%h4 - #{@search_results.total_count} results found - - unless @show_snippets - - if @project - for #{link_to @project.name_with_namespace, [@project.namespace.becomes(Namespace), @project]} - - elsif @group - for #{link_to @group.name, @group} +- if @search_results.empty? + = render partial: "search/results/empty" +- else + .light + Search results for + %code + = @search_term + - unless @show_snippets + - if @project + in project #{link_to @project.name_with_namespace, [@project.namespace.becomes(Namespace), @project]} + - elsif @group + in group #{link_to @group.name, @group} -%hr - -.row - .col-sm-3 - - if @project - = render "project_filter" - - elsif @show_snippets - = render 'snippet_filter' - - else - = render "global_filter" - .col-sm-9 + %br + .results.prepend-top-10 .search-results - - if @search_results.empty? - = render partial: "search/results/empty", locals: { message: "We couldn't find any matching results" } - - else - = render partial: "search/results/#{@scope.singularize}", collection: @objects - = paginate @objects, theme: 'gitlab' + = render partial: "search/results/#{@scope.singularize}", collection: @objects + = paginate @objects, theme: 'gitlab' :javascript $(".search-results .term").highlight("#{escape_javascript(params[:search])}"); diff --git a/app/views/search/_snippet_filter.html.haml b/app/views/search/_snippet_filter.html.haml deleted file mode 100644 index 95d23fa9f47..00000000000 --- a/app/views/search/_snippet_filter.html.haml +++ /dev/null @@ -1,13 +0,0 @@ -%ul.nav.nav-pills.nav-stacked.search-filter - %li{class: ("active" if @scope == 'snippet_blobs')} - = link_to search_filter_path(scope: 'snippet_blobs', snippets: true, group_id: nil, project_id: nil) do - %i.fa.fa-code - Snippet Contents - .pull-right - = @search_results.snippet_blobs_count - %li{class: ("active" if @scope == 'snippet_titles')} - = link_to search_filter_path(scope: 'snippet_titles', snippets: true, group_id: nil, project_id: nil) do - %i.fa.fa-book - Titles and Filenames - .pull-right - = @search_results.snippet_titles_count diff --git a/app/views/search/results/_empty.html.haml b/app/views/search/results/_empty.html.haml index 01fb8cd9b8e..05a63016c09 100644 --- a/app/views/search/results/_empty.html.haml +++ b/app/views/search/results/_empty.html.haml @@ -1,4 +1,6 @@ .search_box .search_glyph - %span.fa.fa-search - %h4 #{message} + %h4 + = icon('search') + We couldn't find any results matching + %code #{@search_term} diff --git a/app/views/search/show.html.haml b/app/views/search/show.html.haml index 5b4816e4c40..e9f2711be2a 100644 --- a/app/views/search/show.html.haml +++ b/app/views/search/show.html.haml @@ -1,22 +1,6 @@ -= form_tag search_path, method: :get, class: 'form-horizontal' do |f| - .search-holder.clearfix - .form-group - = label_tag :search, class: 'control-label' do - %span Looking for - .col-sm-6 - = search_field_tag :search, params[:search], placeholder: "issue 143", class: "form-control search-text-input", id: "dashboard_search" - .col-sm-4 - = button_tag 'Search', class: "btn btn-create" - .form-group - .col-sm-2 - - unless params[:snippets].eql? 'true' - .col-sm-10 - = render 'filter', f: f - = hidden_field_tag :project_id, params[:project_id] - = hidden_field_tag :group_id, params[:group_id] - = hidden_field_tag :snippets, params[:snippets] - = hidden_field_tag :scope, params[:scope] - - .results.prepend-top-10 - - if params[:search].present? - = render 'search/results' += render 'search/form' +%hr +- if @search_term + = render 'search/category' + %hr + = render 'search/results' diff --git a/app/views/shared/_service_settings.html.haml b/app/views/shared/_service_settings.html.haml new file mode 100644 index 00000000000..16a98a7233c --- /dev/null +++ b/app/views/shared/_service_settings.html.haml @@ -0,0 +1,75 @@ +- if @service.errors.any? + #error_explanation + .alert.alert-danger + %ul + - @service.errors.full_messages.each do |msg| + %li= msg + +- if @service.help.present? + .well + = preserve do + = markdown @service.help + +.form-group + = form.label :active, "Active", class: "control-label" + .col-sm-10 + = form.check_box :active + +- if @service.supported_events.length > 1 + .form-group + = form.label :url, "Trigger", class: 'control-label' + .col-sm-10 + - if @service.supported_events.include?("push") + %div + = form.check_box :push_events, class: 'pull-left' + .prepend-left-20 + = form.label :push_events, class: 'list-label' do + %strong Push events + %p.light + This url will be triggered by a push to the repository + - if @service.supported_events.include?("tag_push") + %div + = form.check_box :tag_push_events, class: 'pull-left' + .prepend-left-20 + = form.label :tag_push_events, class: 'list-label' do + %strong Tag push events + %p.light + This url will be triggered when a new tag is pushed to the repository + - if @service.supported_events.include?("note") + %div + = form.check_box :note_events, class: 'pull-left' + .prepend-left-20 + = form.label :note_events, class: 'list-label' do + %strong Comments + %p.light + This url will be triggered when someone adds a comment + - if @service.supported_events.include?("issue") + %div + = form.check_box :issues_events, class: 'pull-left' + .prepend-left-20 + = form.label :issues_events, class: 'list-label' do + %strong Issues events + %p.light + This url will be triggered when an issue is created + - if @service.supported_events.include?("merge_request") + %div + = form.check_box :merge_requests_events, class: 'pull-left' + .prepend-left-20 + = form.label :merge_requests_events, class: 'list-label' do + %strong Merge Request events + %p.light + This url will be triggered when a merge request is created + +- @service.fields.each do |field| + - type = field[:type] + + - if type == 'fieldset' + - fields = field[:fields] + - legend = field[:legend] + + %fieldset + %legend= legend + - fields.each do |subfield| + = render 'shared/field', form: form, field: subfield + - else + = render 'shared/field', form: form, field: field diff --git a/app/views/shared/_show_aside.html.haml b/app/views/shared/_show_aside.html.haml new file mode 100644 index 00000000000..3ac9b11b4fa --- /dev/null +++ b/app/views/shared/_show_aside.html.haml @@ -0,0 +1,2 @@ += link_to '#aside', class: 'show-aside' do + %i.fa.fa-angle-left diff --git a/app/views/users/show.html.haml b/app/views/users/show.html.haml index 15a3f741e6c..0576c6a11b9 100644 --- a/app/views/users/show.html.haml +++ b/app/views/users/show.html.haml @@ -1,9 +1,9 @@ = content_for :meta_tags do = auto_discovery_link_tag(:atom, user_url(@user, format: :atom), title: "#{@user.name} activity") += render 'shared/show_aside' + .row - = link_to '#aside', class: 'show-aside' do - %i.fa.fa-angle-left %section.col-md-8 .header-with-avatar = image_tag avatar_icon(@user.email, 90), class: "avatar avatar-tile s90", alt: '' diff --git a/config/initializers/8_default_url_options.rb b/config/initializers/8_default_url_options.rb index 8c1b56846d2..8fd27b1d88e 100644 --- a/config/initializers/8_default_url_options.rb +++ b/config/initializers/8_default_url_options.rb @@ -1,13 +1,11 @@ -unless Rails.env.test? - default_url_options = { - host: Gitlab.config.gitlab.host, - protocol: Gitlab.config.gitlab.protocol, - script_name: Gitlab.config.gitlab.relative_url_root - } +default_url_options = { + host: Gitlab.config.gitlab.host, + protocol: Gitlab.config.gitlab.protocol, + script_name: Gitlab.config.gitlab.relative_url_root +} - unless Gitlab.config.gitlab_on_standard_port? - default_url_options[:port] = Gitlab.config.gitlab.port - end - - Rails.application.routes.default_url_options = default_url_options +unless Gitlab.config.gitlab_on_standard_port? + default_url_options[:port] = Gitlab.config.gitlab.port end + +Rails.application.routes.default_url_options = default_url_options diff --git a/config/routes.rb b/config/routes.rb index e059f5830f5..4b38dede7b4 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -435,7 +435,7 @@ Gitlab::Application.routes.draw do member do # tree viewer logs get 'logs_tree', constraints: { id: Gitlab::Regex.git_reference_regex } - get 'logs_tree/:path' => 'refs#logs_tree', as: :logs_file, constraints: { + get 'logs_tree/*path' => 'refs#logs_tree', as: :logs_file, constraints: { id: Gitlab::Regex.git_reference_regex, path: /.*/ } diff --git a/db/migrate/20150429002313_remove_abandoned_group_members_records.rb b/db/migrate/20150429002313_remove_abandoned_group_members_records.rb new file mode 100644 index 00000000000..6013605bb35 --- /dev/null +++ b/db/migrate/20150429002313_remove_abandoned_group_members_records.rb @@ -0,0 +1,6 @@ +class RemoveAbandonedGroupMembersRecords < ActiveRecord::Migration + def change + execute("DELETE FROM members WHERE type = 'GroupMember' AND source_id NOT IN(\ + SELECT id FROM namespaces WHERE type='Group')") + end +end diff --git a/db/schema.rb b/db/schema.rb index 8683c0446fe..a2ed9efc933 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -11,7 +11,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 20150425173433) do +ActiveRecord::Schema.define(version: 20150429002313) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -349,10 +349,10 @@ ActiveRecord::Schema.define(version: 20150425173433) do t.string "import_url" t.integer "visibility_level", default: 0, null: false t.boolean "archived", default: false, null: false - t.string "avatar" t.string "import_status" t.float "repository_size", default: 0.0 t.integer "star_count", default: 0, null: false + t.string "avatar" t.string "import_type" t.string "import_source" end @@ -472,7 +472,6 @@ ActiveRecord::Schema.define(version: 20150425173433) do t.integer "notification_level", default: 1, null: false t.datetime "password_expires_at" t.integer "created_by_id" - t.datetime "last_credential_check_at" t.string "avatar" t.string "confirmation_token" t.datetime "confirmed_at" @@ -480,6 +479,7 @@ ActiveRecord::Schema.define(version: 20150425173433) do t.string "unconfirmed_email" t.boolean "hide_no_ssh_key", default: false t.string "website_url", default: "", null: false + t.datetime "last_credential_check_at" t.string "github_access_token" t.string "gitlab_access_token" t.string "notification_email" @@ -501,6 +501,30 @@ ActiveRecord::Schema.define(version: 20150425173433) do add_index "users", ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true, using: :btree add_index "users", ["username"], name: "index_users_on_username", using: :btree + create_table "users_groups", force: true do |t| + t.integer "group_access", null: false + t.integer "group_id", null: false + t.integer "user_id", null: false + t.datetime "created_at" + t.datetime "updated_at" + t.integer "notification_level", default: 3, null: false + end + + add_index "users_groups", ["user_id"], name: "index_users_groups_on_user_id", using: :btree + + create_table "users_projects", force: true do |t| + t.integer "user_id", null: false + t.integer "project_id", null: false + t.datetime "created_at" + t.datetime "updated_at" + t.integer "project_access", default: 0, null: false + t.integer "notification_level", default: 3, null: false + end + + add_index "users_projects", ["project_access"], name: "index_users_projects_on_project_access", using: :btree + add_index "users_projects", ["project_id"], name: "index_users_projects_on_project_id", using: :btree + add_index "users_projects", ["user_id"], name: "index_users_projects_on_user_id", using: :btree + create_table "users_star_projects", force: true do |t| t.integer "project_id", null: false t.integer "user_id", null: false diff --git a/doc/customization/issue_closing.md b/doc/customization/issue_closing.md index aa65a082a53..64f128f5a63 100644 --- a/doc/customization/issue_closing.md +++ b/doc/customization/issue_closing.md @@ -1,5 +1,7 @@ # Issue closing pattern +Here's how to close multiple issues in one commit message: + If a commit message matches the regular expression below, all issues referenced from the matched text will be closed. This happens when the commit is pushed or merged into the default branch of a project. @@ -33,4 +35,4 @@ issue_closing_pattern: '((?:[Cc]los(?:e[sd]|ing)|[Ff]ix(?:e[sd]|ing)?) +(?:(?:is For manual installs you can customize the pattern in [gitlab.yml][0]. [0]: https://gitlab.com/gitlab-org/gitlab-ce/blob/40c3675372320febf5264061c9bcd63db2dfd13c/config/gitlab.yml.example#L65 -[1]: http://rubular.com/r/Xmbexed1OJ +[1]: http://rubular.com/r/Xmbexed1OJ
\ No newline at end of file diff --git a/doc/update/7.9-to-7.10.md b/doc/update/7.9-to-7.10.md index 0512e7cde7c..d1179dc2ec7 100644 --- a/doc/update/7.9-to-7.10.md +++ b/doc/update/7.9-to-7.10.md @@ -106,7 +106,7 @@ only contains a root URL (ex. `https://gitlab.example.com/`) ## Things went south? Revert to previous version (7.9) ### 1. Revert the code to the previous version -Follow the [upgrade guide from 7.8 to 7.8](7.8-to-7.9.md), except for the database migration +Follow the [upgrade guide from 7.8 to 7.9](7.8-to-7.9.md), except for the database migration (The backup is already migrated to the previous version) ### 2. Restore from the backup: @@ -115,4 +115,4 @@ Follow the [upgrade guide from 7.8 to 7.8](7.8-to-7.9.md), except for the databa cd /home/git/gitlab sudo -u git -H bundle exec rake gitlab:backup:restore RAILS_ENV=production ``` -If you have more than one backup *.tar file(s) please add `BACKUP=timestamp_of_backup` to the command above.
\ No newline at end of file +If you have more than one backup *.tar file(s) please add `BACKUP=timestamp_of_backup` to the command above. diff --git a/docker/README.md b/docker/README.md index b7e8b0db7e7..a54739ae3d3 100644 --- a/docker/README.md +++ b/docker/README.md @@ -3,16 +3,19 @@ What is GitLab? GitLab offers git repository management, code reviews, issue tracking, activity feeds, wikis. It has LDAP/AD integration, handles 25,000 users on a single server but can also run on a highly available active/active cluster. A subscription gives you access to our support team and to GitLab Enterprise Edition that contains extra features aimed at larger organizations. -<https://about.gitlab.com> +Learn more on [https://about.gitlab.com](https://about.gitlab.com) -![GitLab Logo](https://gitlab.com/uploads/appearance/logo/1/brand_logo-c37eb221b456bb4b472cc1084480991f.png) - -How to use these images +How to build and use images yourself ====================== -At this moment GitLab doesn't have official Docker images. For convinience we will use suffix _xy where xy is current version of GitLab. -Build your own based on the Omnibus packages with the following commands (it assumes you're in the GitLab repo root directory): +At this moment GitLab doesn't have official Docker images. +There are unofficial images at the bottom of this document. +But in this section we'll build our own. +For convinience we will use suffix _xy where xy is current version of GitLab. +Build your own based on the Omnibus packages with the following commands. +Run these from the GitLab repo root directory. +People using boot2docker should run it without sudo. ```bash sudo docker build --tag gitlab_data_image docker/data/ @@ -42,11 +45,11 @@ sudo docker run --detach --name gitlab_app_xy --publish 8080:80 --publish 2222:2 It might take a while before the docker container is responding to queries. You can follow the configuration process with `sudo docker logs -f gitlab_app_xy`. -You can then go to `http://localhost:8080/` (or `http://192.168.59.103:8080/` if you use boot2docker). +You can then go to [http://localhost:8080/](http://localhost:8080/) or [http://192.168.59.103:8080/](http://192.168.59.103:8080/) if you use boot2docker. + You can login with username `root` and password `5iveL!fe`. Next time, you can just use `sudo docker start gitlab_app` and `sudo docker stop gitlab_app`. - How to configure GitLab ======================== @@ -55,7 +58,7 @@ This container uses the official Omnibus GitLab distribution, so all configurati To access GitLab configuration, you can start an interactive command line in a new container using the shared data volume container, you will be able to browse the 3 directories and use your favorite text editor: ```bash -sudo docker run -ti -e TERM=linux --rm --volumes-from gitlab_data ubuntu +sudo docker run -ti -e TERM=linux --rm --volumes-from gitlab_data ubuntu vi /etc/gitlab/gitlab.rb ``` @@ -86,3 +89,26 @@ sudo docker rmi gitlab_app_image_78 Troubleshooting ========================= Please see the [troubleshooting](troubleshooting.md) file in this directory. + + +Publish the images to Dockerhub +========================= +Login to Dockerhub with `sudo docker login` and run the following (replace '7.9.2' with the version you're using and 'Sytse Sijbrandij' with your name): + +```bash +sudo docker commit -m "Initial commit" -a "Sytse Sijbrandij" gitlab_app_xy sytse/gitlab-ce:7.9.2 +sudo docker push sytse/gitlab-ce:7.9.2 +sudo docker commit -m "Initial commit" -a "Sytse Sijbrandij" gitlab_data sytse/gitlab_data +sudo docker push sytse/gitlab_data +``` + +Use images published to Dockerhub +================================ +This examples uses the unofficial images made by GitLab CEO Sytse. + +```bash +sudo docker pull sytse/gitlab_data +sudo docker pull sytse/gitlab-ce:7.9.2 +sudo docker run --name gitlab_data_volume sytse/gitlab_data /bin/true +sudo docker run --detach --name gitlab_app_7_9_2 --publish 8080:80 --publish 2222:22 --volumes-from gitlab_data_volume sytse/gitlab-ce:7.9.2 +``` diff --git a/features/steps/project/source/search_code.rb b/features/steps/project/source/search_code.rb index 9c2864cc936..b66c5a4123a 100644 --- a/features/steps/project/source/search_code.rb +++ b/features/steps/project/source/search_code.rb @@ -14,6 +14,6 @@ class Spinach::Features::ProjectSourceSearchCode < Spinach::FeatureSteps end step 'I should see empty result' do - page.should have_content "We couldn't find any matching" + page.should have_content "We couldn't find any" end end diff --git a/lib/api/api.rb b/lib/api/api.rb index 60858a39407..d2a35c78fc1 100644 --- a/lib/api/api.rb +++ b/lib/api/api.rb @@ -19,7 +19,7 @@ module API message << " " << trace.join("\n ") API.logger.add Logger::FATAL, message - rack_response({ 'message' => '500 Internal Server Error' }, 500) + rack_response({ 'message' => '500 Internal Server Error' }.to_json, 500) end format :json diff --git a/lib/api/merge_requests.rb b/lib/api/merge_requests.rb index f3765f5ab03..b252c57faed 100644 --- a/lib/api/merge_requests.rb +++ b/lib/api/merge_requests.rb @@ -186,7 +186,7 @@ module API merge_request.check_if_can_be_merged end - if merge_request.open? + if merge_request.open? && !merge_request.work_in_progress? if merge_request.can_be_merged? merge_request.automerge!(current_user, params[:merge_commit_message] || merge_request.merge_commit_message) present merge_request, with: Entities::MergeRequest @@ -195,7 +195,7 @@ module API end else # Merge request can not be merged - # because it is already closed/merged + # because it is already closed/merged or marked as WIP not_allowed! end else diff --git a/lib/gitlab/regex.rb b/lib/gitlab/regex.rb index 0571574aa4f..9f1adc860d1 100644 --- a/lib/gitlab/regex.rb +++ b/lib/gitlab/regex.rb @@ -15,20 +15,20 @@ module Gitlab def namespace_name_regex - @namespace_name_regex ||= /\A[a-zA-Z0-9_\-\. ]*\z/.freeze + @namespace_name_regex ||= /\A[\p{Alnum}\p{Pd}_\. ]*\z/.freeze end def namespace_name_regex_message - "can contain only letters, digits, '_', '-', '.' and space." + "can contain only letters, digits, '_', '.', dash and space." end def project_name_regex - @project_name_regex ||= /\A[a-zA-Z0-9_.][a-zA-Z0-9_\-\. ]*\z/.freeze + @project_name_regex ||= /\A[\p{Alnum}_][\p{Alnum}\p{Pd}_\. ]*\z/.freeze end def project_name_regex_message - "can contain only letters, digits, '_', '-', '.' and space. " \ + "can contain only letters, digits, '_', '.', dash and space. " \ "It must start with letter, digit or '_'." end diff --git a/lib/tasks/dev.rake b/lib/tasks/dev.rake index 058c7417040..b22c631c8ba 100644 --- a/lib/tasks/dev.rake +++ b/lib/tasks/dev.rake @@ -7,4 +7,9 @@ namespace :dev do Rake::Task["gitlab:setup"].invoke Rake::Task["gitlab:shell:setup"].invoke end + + desc 'GITLAB | Start/restart foreman and watch for changes' + task :foreman => :environment do + sh 'rerun --dir app,config,lib -- foreman start' + end end diff --git a/spec/features/users_spec.rb b/spec/features/users_spec.rb index 4cfaab03caf..93d2b18b5fc 100644 --- a/spec/features/users_spec.rb +++ b/spec/features/users_spec.rb @@ -1,13 +1,6 @@ require 'spec_helper' feature 'Users' do - around do |ex| - old_url_options = Rails.application.routes.default_url_options - Rails.application.routes.default_url_options = { host: 'example.foo' } - ex.run - Rails.application.routes.default_url_options = old_url_options - end - scenario 'GET /users/sign_in creates a new user account' do visit new_user_session_path fill_in 'user_name', with: 'Name Surname' diff --git a/spec/lib/extracts_path_spec.rb b/spec/lib/extracts_path_spec.rb index ac602eac154..05bcebaa3a2 100644 --- a/spec/lib/extracts_path_spec.rb +++ b/spec/lib/extracts_path_spec.rb @@ -2,6 +2,8 @@ require 'spec_helper' describe ExtractsPath do include ExtractsPath + include RepoHelpers + include Rails.application.routes.url_helpers let(:project) { double('project') } @@ -11,6 +13,20 @@ describe ExtractsPath do project.stub(path_with_namespace: 'gitlab/gitlab-ci') end + describe '#assign_ref' do + let(:ref) { sample_commit[:id] } + let(:params) { {path: sample_commit[:line_code_path], ref: ref} } + + before do + @project = create(:project) + end + + it "log tree path should have no escape sequences" do + assign_ref_vars + expect(@logs_path).to eq("/#{@project.path_with_namespace}/refs/#{ref}/logs_tree/files/ruby/popen.rb") + end + end + describe '#extract_ref' do it "returns an empty pair when no @project is set" do @project = nil diff --git a/spec/lib/gitlab/regex_spec.rb b/spec/lib/gitlab/regex_spec.rb index 727884c41c5..7fdc8fa600d 100644 --- a/spec/lib/gitlab/regex_spec.rb +++ b/spec/lib/gitlab/regex_spec.rb @@ -1,3 +1,4 @@ +# coding: utf-8 require 'spec_helper' describe Gitlab::Regex do @@ -16,6 +17,8 @@ describe Gitlab::Regex do it { expect('GitLab CE').to match(Gitlab::Regex.project_name_regex) } it { expect('100 lines').to match(Gitlab::Regex.project_name_regex) } it { expect('gitlab.git').to match(Gitlab::Regex.project_name_regex) } + it { expect('Český název').to match(Gitlab::Regex.project_name_regex) } + it { expect('Dash – is this').to match(Gitlab::Regex.project_name_regex) } it { expect('?gitlab').not_to match(Gitlab::Regex.project_name_regex) } end end diff --git a/spec/models/merge_request_spec.rb b/spec/models/merge_request_spec.rb index 3fcd063efe8..97b8abc49dd 100644 --- a/spec/models/merge_request_spec.rb +++ b/spec/models/merge_request_spec.rb @@ -115,6 +115,32 @@ describe MergeRequest do end end + describe "#work_in_progress?" do + it "detects the 'WIP ' prefix" do + subject.title = "WIP #{subject.title}" + expect(subject).to be_work_in_progress + end + + it "detects the 'WIP: ' prefix" do + subject.title = "WIP: #{subject.title}" + expect(subject).to be_work_in_progress + end + + it "detects the '[WIP] ' prefix" do + subject.title = "[WIP] #{subject.title}" + expect(subject).to be_work_in_progress + end + + it "doesn't detect WIP for words starting with WIP" do + subject.title = "Wipwap #{subject.title}" + expect(subject).not_to be_work_in_progress + end + + it "doesn't detect WIP by default" do + expect(subject).not_to be_work_in_progress + end + end + it_behaves_like 'an editable mentionable' do subject { create(:merge_request, source_project: project, target_project: project) } diff --git a/spec/requests/api/merge_requests_spec.rb b/spec/requests/api/merge_requests_spec.rb index 9e252441a4f..5fca831f9be 100644 --- a/spec/requests/api/merge_requests_spec.rb +++ b/spec/requests/api/merge_requests_spec.rb @@ -312,6 +312,13 @@ describe API::API, api: true do expect(json_response['message']).to eq('405 Method Not Allowed') end + it "should return 405 if merge_request is a work in progress" do + merge_request.update_attribute(:title, "WIP: #{merge_request.title}") + put api("/projects/#{project.id}/merge_request/#{merge_request.id}/merge", user) + expect(response.status).to eq(405) + expect(json_response['message']).to eq('405 Method Not Allowed') + end + it "should return 401 if user has no permissions to merge" do user2 = create(:user) project.team << [user2, :reporter] diff --git a/spec/support/reference_filter_spec_helper.rb b/spec/support/reference_filter_spec_helper.rb index 41253811490..06c39e1ada5 100644 --- a/spec/support/reference_filter_spec_helper.rb +++ b/spec/support/reference_filter_spec_helper.rb @@ -4,17 +4,6 @@ module ReferenceFilterSpecHelper extend ActiveSupport::Concern - included do - before { set_default_url_options } - end - - # Allow *_url helpers to work - def set_default_url_options - Rails.application.routes.default_url_options = { - host: 'example.foo' - } - end - # Shortcut to Rails' auto-generated routes helpers, to avoid including the # module def urls |