diff --git a/.gitignore b/.gitignore index 7a7b5c9393..3e30fb8cf7 100644 --- a/.gitignore +++ b/.gitignore @@ -37,6 +37,6 @@ public/assets/ public/uploads.* public/uploads/ rails_best_practices_output.html -tags +/tags tmp/ vendor/bundle/* diff --git a/CHANGELOG b/CHANGELOG index 77348e3d38..2e9b4126b9 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,31 +1,49 @@ Please view this file on the master branch, on stable branches it's out of date. v 7.11.0 (unreleased) + - Make Reply-To config apply to change e-mail confirmation and other Devise notifications (Stan Hu) + - Add application setting to restrict user signups to e-mail domains (Stan Hu) + - Don't allow a merge request to be merged when its title starts with "WIP". + - Add a page title to every page. + - Allow primary email to be set to an email that you've already added. + - Fix Error 500 when searching Wiki pages (Stan Hu) - Get Gitorious importer to work again. - Fix clone URL field and X11 Primary selection (Dmitry Medvinsky) - Ignore invalid lines in .gitmodules - Fix "Cannot move project" error message from popping up after a successful transfer (Stan Hu) - Redirect to sign in page after signing out. - Fix "Hello @username." references not working by no longer allowing usernames to end in period. + - Fix "Revspec not found" errors when viewing diffs in a forked project with submodules (Stan Hu) - + - Fix broken file browsing with relative submodule in personal projects (Stan Hu) + - Fix DB error when trying to tag a repository (Stan Hu) - Add "Reply quoting selected text" shortcut key (`r`) - Fix bug causing `@whatever` inside an issue's first code block to be picked up as a user mention. - Fix bug causing `@whatever` inside an inline code snippet (backtick-style) to be picked up as a user mention. - - Added GitLab Event header for project hooks - - Show Atom feed buttons everywhere where applicable. - 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. + - Don't crash when an MR from a fork has a cross-reference comment from the target project on one of its commits. - Include commit comments in MR from a forked project. - - + - Fix adding new group members from admin area + - Group milestones by title in the dashboard and all other issue views. + - Query issues, merge requests and milestones with their IID through API (Julien Bianchi) - Add default project and snippet visibility settings to the admin web UI. + - Show incompatible projects in Google Code import status (Stan Hu) + - Fix bug where commit data would not appear in some subdirectories (Stan Hu) + - Unescape branch names in compare commit (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 - Improve new project command options (Ben Bodenmiller) + - Add common method to force UTF-8 and use it to properly handle non-ascii OAuth user properties (Onur Küçük) - 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) + - Add current_sign_in_at to UserFull REST api. v 7.10.0 - Ignore submodules that are defined in .gitmodules but are checked in as directories. @@ -111,7 +129,6 @@ v 7.9.0 (unreleased) - Fixed link paths for HTTP and SSH on the admin project view (Jeremy Maziarz) - Fix and improve help rendering (Sullivan Sénéchal) - Fix final line in EmailsOnPush email diff being rendered as error. - - Authometic setup GitLab CI project for forks if origin project has GitLab CI enabled - Prevent duplicate Buildkite service creation. - Fix git over ssh errors 'fatal: protocol error: bad line length character' - Automatically setup GitLab CI project for forks if origin project has GitLab CI enabled diff --git a/Gemfile b/Gemfile index 27abaf3f5d..e85bf4517b 100644 --- a/Gemfile +++ b/Gemfile @@ -209,6 +209,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 79797f9803..3ceb8b47a2 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -47,7 +47,7 @@ GEM astrolabe (1.3.0) parser (>= 2.2.0.pre.3, < 3.0) attr_required (1.0.0) - autoprefixer-rails (5.1.6) + autoprefixer-rails (5.1.11) execjs json awesome_print (1.2.0) @@ -60,7 +60,7 @@ GEM erubis (>= 2.6.6) binding_of_caller (0.7.2) debug_inspector (>= 0.0.1) - bootstrap-sass (3.3.3) + bootstrap-sass (3.3.4.1) autoprefixer-rails (>= 5.0.0.1) sass (>= 3.2.19) brakeman (3.0.1) @@ -154,7 +154,7 @@ GEM escape_utils (0.2.4) eventmachine (1.0.4) excon (0.32.1) - execjs (2.0.2) + execjs (2.5.2) expression_parser (0.9.0) factory_girl (4.3.0) activesupport (>= 3.0.0) @@ -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) @@ -764,6 +766,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/javascripts/dispatcher.js.coffee b/app/assets/javascripts/dispatcher.js.coffee index 3314507352..8c0776e6cc 100644 --- a/app/assets/javascripts/dispatcher.js.coffee +++ b/app/assets/javascripts/dispatcher.js.coffee @@ -8,7 +8,6 @@ class Dispatcher initPageScripts: -> page = $('body').attr('data-page') - project_id = $('body').attr('data-project-id') unless page return false diff --git a/app/assets/stylesheets/base/gl_bootstrap.scss b/app/assets/stylesheets/base/gl_bootstrap.scss index 427f333423..21acbfa5e5 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 d187bc7327..cd242a6bfe 100644 --- a/app/assets/stylesheets/generic/common.scss +++ b/app/assets/stylesheets/generic/common.scss @@ -342,17 +342,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 b861646191..df1553d859 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 c9bbacd734..b7f6fac522 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/generic/typography.scss b/app/assets/stylesheets/generic/typography.scss index 80190424c1..36a9a54074 100644 --- a/app/assets/stylesheets/generic/typography.scss +++ b/app/assets/stylesheets/generic/typography.scss @@ -35,7 +35,12 @@ pre { /* Link to current header. */ h1, h2, h3, h4, h5, h6 { position: relative; - &:hover > :last-child { + + a.anchor { + display: none; + } + + &:hover > a.anchor { $size: 16px; position: absolute; right: 100%; diff --git a/app/assets/stylesheets/pages/issuable.scss b/app/assets/stylesheets/pages/issuable.scss index a640a4e205..586e7b5f8d 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 ee75fe6188..139b3cc1ac 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; + } + + &:hover { + background-color: $color-dark; a { - color: $color-light; - } - - &:hover { - background-color: $color-dark; - a { - color: #FFF; - } + color: #FFF; } } } diff --git a/app/controllers/admin/application_controller.rb b/app/controllers/admin/application_controller.rb index fe5456f820..56e2438646 100644 --- a/app/controllers/admin/application_controller.rb +++ b/app/controllers/admin/application_controller.rb @@ -2,8 +2,8 @@ # # Automatically sets the layout and ensures an administrator is logged in class Admin::ApplicationController < ApplicationController - layout 'admin' before_action :authenticate_admin! + layout 'admin' def authenticate_admin! return render_404 unless current_user.is_admin? diff --git a/app/controllers/admin/application_settings_controller.rb b/app/controllers/admin/application_settings_controller.rb index 657d70d726..87c81e6d46 100644 --- a/app/controllers/admin/application_settings_controller.rb +++ b/app/controllers/admin/application_settings_controller.rb @@ -42,7 +42,8 @@ class Admin::ApplicationSettingsController < Admin::ApplicationController :max_attachment_size, :default_project_visibility, :default_snippet_visibility, - restricted_visibility_levels: [] + :restricted_signup_domains_raw, + restricted_visibility_levels: [], ) end end diff --git a/app/controllers/admin/hooks_controller.rb b/app/controllers/admin/hooks_controller.rb index 690096bdbc..0a463239d7 100644 --- a/app/controllers/admin/hooks_controller.rb +++ b/app/controllers/admin/hooks_controller.rb @@ -33,7 +33,7 @@ class Admin::HooksController < Admin::ApplicationController owner_name: "Someone", owner_email: "example@gitlabhq.com" } - @hook.execute(data, 'system_hooks') + @hook.execute(data) redirect_to :back end diff --git a/app/controllers/admin/users_controller.rb b/app/controllers/admin/users_controller.rb index adb83996f8..d36e359934 100644 --- a/app/controllers/admin/users_controller.rb +++ b/app/controllers/admin/users_controller.rb @@ -102,8 +102,7 @@ class Admin::UsersController < Admin::ApplicationController email = user.emails.find(params[:email_id]) email.destroy - user.set_notification_email - user.save if user.notification_email_changed? + user.update_secondary_emails! respond_to do |format| format.html { redirect_to :back, notice: "Successfully removed email." } diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 5873aa8134..a41977c20e 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -3,6 +3,7 @@ require 'gon' class ApplicationController < ActionController::Base include Gitlab::CurrentSettings include GitlabRoutingHelper + include PageLayoutHelper PER_PAGE = 20 @@ -182,18 +183,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' @@ -304,40 +293,15 @@ class ApplicationController < ActionController::Base @filter_params end - def set_filter_values(collection) - assignee_id = @filter_params[:assignee_id] - author_id = @filter_params[:author_id] - milestone_id = @filter_params[:milestone_id] - - @sort = @filter_params[:sort] - @assignees = User.where(id: collection.pluck(:assignee_id)) - @authors = User.where(id: collection.pluck(:author_id)) - @milestones = Milestone.where(id: collection.pluck(:milestone_id)) - - if assignee_id.present? && !assignee_id.to_i.zero? - @assignee = @assignees.find_by(id: assignee_id) - end - - if author_id.present? && !author_id.to_i.zero? - @author = @authors.find_by(id: author_id) - end - - if milestone_id.present? && !milestone_id.to_i.zero? - @milestone = @milestones.find_by(id: milestone_id) - end - end - def get_issues_collection set_filters_params issues = IssuesFinder.new.execute(current_user, @filter_params) - set_filter_values(issues) issues end def get_merge_requests_collection set_filters_params merge_requests = MergeRequestsFinder.new.execute(current_user, @filter_params) - set_filter_values(merge_requests) merge_requests end diff --git a/app/controllers/dashboard/application_controller.rb b/app/controllers/dashboard/application_controller.rb new file mode 100644 index 0000000000..962ea38d6c --- /dev/null +++ b/app/controllers/dashboard/application_controller.rb @@ -0,0 +1,3 @@ +class Dashboard::ApplicationController < ApplicationController + layout 'dashboard' +end diff --git a/app/controllers/dashboard/groups_controller.rb b/app/controllers/dashboard/groups_controller.rb index ed14f4e1f3..3bc94ff218 100644 --- a/app/controllers/dashboard/groups_controller.rb +++ b/app/controllers/dashboard/groups_controller.rb @@ -1,4 +1,4 @@ -class Dashboard::GroupsController < ApplicationController +class Dashboard::GroupsController < Dashboard::ApplicationController def index @group_members = current_user.group_members.page(params[:page]).per(PER_PAGE) end diff --git a/app/controllers/dashboard/milestones_controller.rb b/app/controllers/dashboard/milestones_controller.rb index 33227e7f1d..53896d4f2c 100644 --- a/app/controllers/dashboard/milestones_controller.rb +++ b/app/controllers/dashboard/milestones_controller.rb @@ -1,4 +1,4 @@ -class Dashboard::MilestonesController < ApplicationController +class Dashboard::MilestonesController < Dashboard::ApplicationController before_action :load_projects def index diff --git a/app/controllers/dashboard/projects_controller.rb b/app/controllers/dashboard/projects_controller.rb index 426bc61541..da96171e88 100644 --- a/app/controllers/dashboard/projects_controller.rb +++ b/app/controllers/dashboard/projects_controller.rb @@ -1,4 +1,4 @@ -class Dashboard::ProjectsController < ApplicationController +class Dashboard::ProjectsController < Dashboard::ApplicationController before_action :event_filter def starred diff --git a/app/controllers/dashboard_controller.rb b/app/controllers/dashboard_controller.rb index 40b5de1295..17ddde68f9 100644 --- a/app/controllers/dashboard_controller.rb +++ b/app/controllers/dashboard_controller.rb @@ -1,8 +1,8 @@ -class DashboardController < ApplicationController - respond_to :html - +class DashboardController < Dashboard::ApplicationController before_action :load_projects, except: [:projects] before_action :event_filter, only: :show + + respond_to :html def show @projects = @projects.includes(:namespace) diff --git a/app/controllers/explore/application_controller.rb b/app/controllers/explore/application_controller.rb new file mode 100644 index 0000000000..4b275033d2 --- /dev/null +++ b/app/controllers/explore/application_controller.rb @@ -0,0 +1,3 @@ +class Explore::ApplicationController < ApplicationController + layout 'explore' +end diff --git a/app/controllers/explore/groups_controller.rb b/app/controllers/explore/groups_controller.rb index a7250b799f..55cda0cff1 100644 --- a/app/controllers/explore/groups_controller.rb +++ b/app/controllers/explore/groups_controller.rb @@ -1,9 +1,7 @@ -class Explore::GroupsController < ApplicationController +class Explore::GroupsController < Explore::ApplicationController skip_before_action :authenticate_user!, :reject_blocked, :set_current_user_for_observers - layout "explore" - def index @groups = GroupsFinder.new.execute(current_user) @groups = @groups.search(params[:search]) if params[:search].present? diff --git a/app/controllers/explore/projects_controller.rb b/app/controllers/explore/projects_controller.rb index b1b0a2514d..e9bcb44f6b 100644 --- a/app/controllers/explore/projects_controller.rb +++ b/app/controllers/explore/projects_controller.rb @@ -1,9 +1,7 @@ -class Explore::ProjectsController < ApplicationController +class Explore::ProjectsController < Explore::ApplicationController skip_before_action :authenticate_user!, :reject_blocked - layout 'explore' - def index @projects = ProjectsFinder.new.execute(current_user) @tags = @projects.tags_on(:tags) diff --git a/app/controllers/groups/application_controller.rb b/app/controllers/groups/application_controller.rb index 9a761d57e9..4eccf49e5d 100644 --- a/app/controllers/groups/application_controller.rb +++ b/app/controllers/groups/application_controller.rb @@ -1,4 +1,5 @@ class Groups::ApplicationController < ApplicationController + layout 'group' private @@ -21,12 +22,4 @@ class Groups::ApplicationController < ApplicationController def group @group ||= Group.find_by(path: params[:group_id]) end - - def determine_layout - if current_user - 'group' - else - 'public_group' - end - end end diff --git a/app/controllers/groups/avatars_controller.rb b/app/controllers/groups/avatars_controller.rb index 38071410f4..6aa64222f7 100644 --- a/app/controllers/groups/avatars_controller.rb +++ b/app/controllers/groups/avatars_controller.rb @@ -1,6 +1,4 @@ class Groups::AvatarsController < ApplicationController - layout "profile" - def destroy @group = Group.find_by(path: params[:group_id]) @group.remove_avatar! diff --git a/app/controllers/groups/group_members_controller.rb b/app/controllers/groups/group_members_controller.rb index 46ebdb74c5..85fbe0bb80 100644 --- a/app/controllers/groups/group_members_controller.rb +++ b/app/controllers/groups/group_members_controller.rb @@ -6,8 +6,6 @@ class Groups::GroupMembersController < Groups::ApplicationController before_action :authorize_read_group! before_action :authorize_admin_group!, except: [:index, :leave] - layout :determine_layout - def index @project = @group.projects.find(params[:project_id]) if params[:project_id] @members = @group.group_members diff --git a/app/controllers/groups/milestones_controller.rb b/app/controllers/groups/milestones_controller.rb index 41564b04a9..669f7f3126 100644 --- a/app/controllers/groups/milestones_controller.rb +++ b/app/controllers/groups/milestones_controller.rb @@ -1,6 +1,4 @@ -class Groups::MilestonesController < ApplicationController - layout 'group' - +class Groups::MilestonesController < Groups::ApplicationController before_action :authorize_group_milestone!, only: :update def index diff --git a/app/controllers/groups_controller.rb b/app/controllers/groups_controller.rb index 9ddd3b170f..3ba1ac2677 100644 --- a/app/controllers/groups_controller.rb +++ b/app/controllers/groups_controller.rb @@ -11,7 +11,6 @@ class GroupsController < Groups::ApplicationController # Load group projects before_action :load_projects, except: [:new, :create, :projects, :edit, :update] before_action :event_filter, only: :show - before_action :set_title, only: [:new, :create] layout :determine_layout @@ -121,17 +120,11 @@ class GroupsController < Groups::ApplicationController end end - def set_title - @title = 'New Group' - end - def determine_layout if [:new, :create].include?(action_name.to_sym) - 'navless' - elsif current_user - 'group' + 'application' else - 'public_group' + 'group' end end diff --git a/app/controllers/help_controller.rb b/app/controllers/help_controller.rb index 35ece5b270..8a45dc8860 100644 --- a/app/controllers/help_controller.rb +++ b/app/controllers/help_controller.rb @@ -1,14 +1,16 @@ class HelpController < ApplicationController + layout 'help' + def index end def show - category = clean_path_info(path_params[:category]) - file = path_params[:file] + @category = clean_path_info(path_params[:category]) + @file = path_params[:file] respond_to do |format| format.any(:markdown, :md, :html) do - path = Rails.root.join('doc', category, "#{file}.md") + path = Rails.root.join('doc', @category, "#{@file}.md") if File.exist?(path) @markdown = File.read(path) @@ -22,7 +24,7 @@ class HelpController < ApplicationController # Allow access to images in the doc folder format.any(:png, :gif, :jpeg) do - path = Rails.root.join('doc', category, "#{file}.#{params[:format]}") + path = Rails.root.join('doc', @category, "#{@file}.#{params[:format]}") if File.exist?(path) send_file(path, disposition: 'inline') diff --git a/app/controllers/import/google_code_controller.rb b/app/controllers/import/google_code_controller.rb index 5adf6ed785..4aa6d28c9a 100644 --- a/app/controllers/import/google_code_controller.rb +++ b/app/controllers/import/google_code_controller.rb @@ -72,6 +72,7 @@ class Import::GoogleCodeController < Import::BaseController end @repos = client.repos + @incompatible_repos = client.incompatible_repos @already_added_projects = current_user.created_projects.where(import_type: "google_code") already_added_projects_names = @already_added_projects.pluck(:import_source) diff --git a/app/controllers/invites_controller.rb b/app/controllers/invites_controller.rb index a29c03395f..eb3c823353 100644 --- a/app/controllers/invites_controller.rb +++ b/app/controllers/invites_controller.rb @@ -4,8 +4,6 @@ class InvitesController < ApplicationController respond_to :html - layout 'navless' - def show end diff --git a/app/controllers/oauth/applications_controller.rb b/app/controllers/oauth/applications_controller.rb index ea256de2c3..507b8290a2 100644 --- a/app/controllers/oauth/applications_controller.rb +++ b/app/controllers/oauth/applications_controller.rb @@ -1,6 +1,9 @@ class Oauth::ApplicationsController < Doorkeeper::ApplicationsController + include PageLayoutHelper + before_action :authenticate_user! - layout "profile" + + layout 'profile' def index head :forbidden and return diff --git a/app/controllers/oauth/authorizations_controller.rb b/app/controllers/oauth/authorizations_controller.rb index 6d3c1a320d..24025d8c72 100644 --- a/app/controllers/oauth/authorizations_controller.rb +++ b/app/controllers/oauth/authorizations_controller.rb @@ -1,6 +1,7 @@ class Oauth::AuthorizationsController < Doorkeeper::AuthorizationsController before_action :authenticate_resource_owner! - layout "profile" + + layout 'profile' def new if pre_auth.authorizable? diff --git a/app/controllers/oauth/authorized_applications_controller.rb b/app/controllers/oauth/authorized_applications_controller.rb index 0b27ce7da7..3ab6def511 100644 --- a/app/controllers/oauth/authorized_applications_controller.rb +++ b/app/controllers/oauth/authorized_applications_controller.rb @@ -1,5 +1,7 @@ class Oauth::AuthorizedApplicationsController < Doorkeeper::AuthorizedApplicationsController - layout "profile" + include PageLayoutHelper + + layout 'profile' def destroy Doorkeeper::AccessToken.revoke_all_for(params[:id], current_resource_owner) diff --git a/app/controllers/profiles/accounts_controller.rb b/app/controllers/profiles/accounts_controller.rb index 9bd34fe226..175afbf842 100644 --- a/app/controllers/profiles/accounts_controller.rb +++ b/app/controllers/profiles/accounts_controller.rb @@ -1,6 +1,4 @@ -class Profiles::AccountsController < ApplicationController - layout "profile" - +class Profiles::AccountsController < Profiles::ApplicationController def show @user = current_user end diff --git a/app/controllers/profiles/application_controller.rb b/app/controllers/profiles/application_controller.rb new file mode 100644 index 0000000000..c8be288b9a --- /dev/null +++ b/app/controllers/profiles/application_controller.rb @@ -0,0 +1,3 @@ +class Profiles::ApplicationController < ApplicationController + layout 'profile' +end diff --git a/app/controllers/profiles/avatars_controller.rb b/app/controllers/profiles/avatars_controller.rb index 57f3bbf062..f193adb46b 100644 --- a/app/controllers/profiles/avatars_controller.rb +++ b/app/controllers/profiles/avatars_controller.rb @@ -1,6 +1,4 @@ -class Profiles::AvatarsController < ApplicationController - layout "profile" - +class Profiles::AvatarsController < Profiles::ApplicationController def destroy @user = current_user @user.remove_avatar! diff --git a/app/controllers/profiles/emails_controller.rb b/app/controllers/profiles/emails_controller.rb index 954c98c0d9..0ede9b8e21 100644 --- a/app/controllers/profiles/emails_controller.rb +++ b/app/controllers/profiles/emails_controller.rb @@ -1,16 +1,17 @@ -class Profiles::EmailsController < ApplicationController - layout "profile" - +class Profiles::EmailsController < Profiles::ApplicationController def index @primary = current_user.email - @public_email = current_user.public_email @emails = current_user.emails end def create @email = current_user.emails.new(email_params) - flash[:alert] = @email.errors.full_messages.first unless @email.save + if @email.save + NotificationService.new.new_email(@email) + else + flash[:alert] = @email.errors.full_messages.first + end redirect_to profile_emails_url end @@ -19,9 +20,7 @@ class Profiles::EmailsController < ApplicationController @email = current_user.emails.find(params[:id]) @email.destroy - current_user.set_notification_email - current_user.set_public_email - current_user.save if current_user.notification_email_changed? or current_user.public_email_changed? + current_user.update_secondary_emails! respond_to do |format| format.html { redirect_to profile_emails_url } diff --git a/app/controllers/profiles/keys_controller.rb b/app/controllers/profiles/keys_controller.rb index 157ce038a2..f1a5b5ba18 100644 --- a/app/controllers/profiles/keys_controller.rb +++ b/app/controllers/profiles/keys_controller.rb @@ -1,5 +1,4 @@ -class Profiles::KeysController < ApplicationController - layout "profile" +class Profiles::KeysController < Profiles::ApplicationController skip_before_action :authenticate_user!, only: [:get_keys] def index diff --git a/app/controllers/profiles/notifications_controller.rb b/app/controllers/profiles/notifications_controller.rb index 3fdcbbab61..22423651c1 100644 --- a/app/controllers/profiles/notifications_controller.rb +++ b/app/controllers/profiles/notifications_controller.rb @@ -1,6 +1,4 @@ -class Profiles::NotificationsController < ApplicationController - layout 'profile' - +class Profiles::NotificationsController < Profiles::ApplicationController def show @user = current_user @notification = current_user.notification diff --git a/app/controllers/profiles/passwords_controller.rb b/app/controllers/profiles/passwords_controller.rb index b719a7fe9a..c780e0983f 100644 --- a/app/controllers/profiles/passwords_controller.rb +++ b/app/controllers/profiles/passwords_controller.rb @@ -1,12 +1,11 @@ -class Profiles::PasswordsController < ApplicationController - layout :determine_layout - +class Profiles::PasswordsController < Profiles::ApplicationController skip_before_action :check_password_expiration, only: [:new, :create] before_action :set_user - before_action :set_title before_action :authorize_change_password! + layout :determine_layout + def new end @@ -66,13 +65,9 @@ class Profiles::PasswordsController < ApplicationController @user = current_user end - def set_title - @title = "New password" - end - def determine_layout if [:new, :create].include?(action_name.to_sym) - 'navless' + 'application' else 'profile' end diff --git a/app/controllers/profiles_controller.rb b/app/controllers/profiles_controller.rb index eb001e8d73..f4366c18e7 100644 --- a/app/controllers/profiles_controller.rb +++ b/app/controllers/profiles_controller.rb @@ -1,12 +1,10 @@ -class ProfilesController < ApplicationController +class ProfilesController < Profiles::ApplicationController include ActionView::Helpers::SanitizeHelper before_action :user before_action :authorize_change_username!, only: :update_username skip_before_action :require_email, only: [:show, :update] - layout 'profile' - def show end diff --git a/app/controllers/projects/application_controller.rb b/app/controllers/projects/application_controller.rb index f7a28e920d..ee88d49b40 100644 --- a/app/controllers/projects/application_controller.rb +++ b/app/controllers/projects/application_controller.rb @@ -1,7 +1,7 @@ class Projects::ApplicationController < ApplicationController before_action :project before_action :repository - layout :determine_layout + layout 'project' def authenticate_user! # Restrict access to Projects area only @@ -17,14 +17,6 @@ class Projects::ApplicationController < ApplicationController super end - def determine_layout - if current_user - 'projects' - else - 'public_projects' - end - end - def require_branch_head unless @repository.branch_names.include?(@ref) redirect_to( diff --git a/app/controllers/projects/avatars_controller.rb b/app/controllers/projects/avatars_controller.rb index 22a12c4b9a..9c3763d593 100644 --- a/app/controllers/projects/avatars_controller.rb +++ b/app/controllers/projects/avatars_controller.rb @@ -1,6 +1,4 @@ class Projects::AvatarsController < Projects::ApplicationController - layout 'project' - before_action :project def show diff --git a/app/controllers/projects/compare_controller.rb b/app/controllers/projects/compare_controller.rb index 03e6c38127..7c20b81c0b 100644 --- a/app/controllers/projects/compare_controller.rb +++ b/app/controllers/projects/compare_controller.rb @@ -1,3 +1,5 @@ +require 'addressable/uri' + class Projects::CompareController < Projects::ApplicationController # Authorize before_action :require_non_empty_project @@ -7,8 +9,8 @@ class Projects::CompareController < Projects::ApplicationController end def show - base_ref = params[:from] - head_ref = params[:to] + base_ref = Addressable::URI.unescape(params[:from]) + head_ref = Addressable::URI.unescape(params[:to]) compare_result = CompareService.new.execute( current_user, diff --git a/app/controllers/projects/forks_controller.rb b/app/controllers/projects/forks_controller.rb index 01a079d2e6..9e72597ea8 100644 --- a/app/controllers/projects/forks_controller.rb +++ b/app/controllers/projects/forks_controller.rb @@ -18,7 +18,6 @@ class Projects::ForksController < Projects::ApplicationController notice: 'Project was successfully forked.' ) else - @title = 'Fork project' render :error end end diff --git a/app/controllers/projects/merge_requests_controller.rb b/app/controllers/projects/merge_requests_controller.rb index 41b4e55a59..5b93e95866 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 3f9b578793..ddb3bcfaad 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/projects/uploads_controller.rb b/app/controllers/projects/uploads_controller.rb index e2d0b0d945..71ecc20dd9 100644 --- a/app/controllers/projects/uploads_controller.rb +++ b/app/controllers/projects/uploads_controller.rb @@ -1,6 +1,4 @@ class Projects::UploadsController < Projects::ApplicationController - layout 'project' - skip_before_action :authenticate_user!, :reject_blocked!, :project, :repository, if: -> { action_name == 'show' && image? } diff --git a/app/controllers/projects_controller.rb b/app/controllers/projects_controller.rb index 936a014fb9..ce8da402b9 100644 --- a/app/controllers/projects_controller.rb +++ b/app/controllers/projects_controller.rb @@ -6,17 +6,16 @@ class ProjectsController < ApplicationController # Authorize before_action :authorize_admin_project!, only: [:edit, :update, :destroy, :transfer, :archive, :unarchive] - before_action :set_title, only: [:new, :create] before_action :event_filter, only: :show - layout 'navless', only: [:new, :create, :fork] + layout :determine_layout def new @project = Project.new end def edit - render 'edit', layout: 'project_settings' + render 'edit' end def create @@ -46,7 +45,7 @@ class ProjectsController < ApplicationController end format.js else - format.html { render 'edit', layout: 'project_settings' } + format.html { render 'edit' } format.js end end @@ -72,13 +71,13 @@ class ProjectsController < ApplicationController format.html do if @project.repository_exists? if @project.empty_repo? - render 'projects/empty', layout: user_layout + render 'projects/empty' else @last_push = current_user.recent_push(@project.id) if current_user - render :show, layout: user_layout + render :show end else - render 'projects/no_repo', layout: user_layout + render 'projects/no_repo' end end @@ -160,12 +159,14 @@ class ProjectsController < ApplicationController private - def set_title - @title = 'New Project' - end - - def user_layout - current_user ? 'projects' : 'public_projects' + def determine_layout + if [:new, :create].include?(action_name.to_sym) + 'application' + elsif [:edit, :update].include?(action_name.to_sym) + 'project_settings' + else + 'project' + end end def load_events diff --git a/app/controllers/search_controller.rb b/app/controllers/search_controller.rb index c5828d0b2d..4e2ea6c571 100644 --- a/app/controllers/search_controller.rb +++ b/app/controllers/search_controller.rb @@ -1,23 +1,27 @@ class SearchController < ApplicationController include SearchHelper + layout 'search' + 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 +41,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/controllers/snippets_controller.rb b/app/controllers/snippets_controller.rb index a5259466cb..cf672c5c09 100644 --- a/app/controllers/snippets_controller.rb +++ b/app/controllers/snippets_controller.rb @@ -7,14 +7,11 @@ class SnippetsController < ApplicationController # Allow destroy snippet before_action :authorize_admin_snippet!, only: [:destroy] - before_action :set_title - skip_before_action :authenticate_user!, only: [:index, :user_index, :show, :raw] + layout 'snippets' respond_to :html - layout :determine_layout - def index if params[:username].present? @user = User.find_by(username: params[:username]) @@ -98,16 +95,7 @@ class SnippetsController < ApplicationController return render_404 unless can?(current_user, :admin_personal_snippet, @snippet) end - def set_title - @title = 'Snippets' - @title_url = snippets_path - end - def snippet_params params.require(:personal_snippet).permit(:title, :content, :file_name, :private, :visibility_level) end - - def determine_layout - current_user ? 'snippets' : 'public_users' - end end diff --git a/app/controllers/unsubscribes_controller.rb b/app/controllers/unsubscribes_controller.rb index 542e14bcfe..a65e37acc3 100644 --- a/app/controllers/unsubscribes_controller.rb +++ b/app/controllers/unsubscribes_controller.rb @@ -2,7 +2,6 @@ class UnsubscribesController < ApplicationController skip_before_action :authenticate_user!, :reject_blocked, :set_current_user_for_observers, :add_abilities - layout 'public_users' def show @user = get_user diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb index 460cc868b3..2bb5c338cf 100644 --- a/app/controllers/users_controller.rb +++ b/app/controllers/users_controller.rb @@ -1,7 +1,6 @@ class UsersController < ApplicationController skip_before_action :authenticate_user! before_action :set_user - layout :determine_layout def show @contributed_projects = contributed_projects.joined(@user). @@ -13,9 +12,6 @@ class UsersController < ApplicationController # Collect only groups common for both users @groups = @user.groups & GroupsFinder.new.execute(current_user) - @title = @user.name - @title_url = user_path(@user) - respond_to do |format| format.html @@ -51,14 +47,6 @@ class UsersController < ApplicationController render 'calendar_activities', layout: false end - def determine_layout - if current_user - 'navless' - else - 'public_users' - end - end - private def set_user diff --git a/app/finders/issuable_finder.rb b/app/finders/issuable_finder.rb index 2c0702073d..b8f367c633 100644 --- a/app/finders/issuable_finder.rb +++ b/app/finders/issuable_finder.rb @@ -113,8 +113,9 @@ class IssuableFinder end def by_milestone(items) - if params[:milestone_id].present? - items = items.where(milestone_id: (params[:milestone_id] == NONE ? nil : params[:milestone_id])) + if params[:milestone_title].present? + milestone_ids = (params[:milestone_title] == NONE ? nil : Milestone.where(title: params[:milestone_title]).pluck(:id)) + items = items.where(milestone_id: milestone_ids) end items diff --git a/app/helpers/diff_helper.rb b/app/helpers/diff_helper.rb index 4f42972a4d..162778ade5 100644 --- a/app/helpers/diff_helper.rb +++ b/app/helpers/diff_helper.rb @@ -140,8 +140,8 @@ module DiffHelper end end - def submodule_link(blob, ref) - tree, commit = submodule_links(blob, ref) + def submodule_link(blob, ref, repository = @repository) + tree, commit = submodule_links(blob, ref, repository) commit_id = if commit.nil? blob.id[0..10] else diff --git a/app/helpers/gitlab_markdown_helper.rb b/app/helpers/gitlab_markdown_helper.rb index aff7011edd..24263a0f61 100644 --- a/app/helpers/gitlab_markdown_helper.rb +++ b/app/helpers/gitlab_markdown_helper.rb @@ -34,10 +34,8 @@ module GitlabMarkdownHelper # see https://github.com/vmg/redcarpet#darling-i-packed-you-a-couple-renderers-for-lunch rend = Redcarpet::Render::GitlabHTML.new(self, user_color_scheme_class, { - with_toc_data: true, - safe_links_only: true, - # Handled further down the line by HTML::Pipeline::SanitizationFilter - escape_html: false + # Handled further down the line by Gitlab::Markdown::SanitizationFilter + escape_html: false }.merge(options)) # see https://github.com/vmg/redcarpet#and-its-like-really-simple-to-use @@ -45,11 +43,11 @@ module GitlabMarkdownHelper no_intra_emphasis: true, tables: true, fenced_code_blocks: true, - autolink: true, strikethrough: true, lax_spacing: true, space_after_headers: true, - superscript: true + superscript: true, + footnotes: true ) end diff --git a/app/helpers/groups_helper.rb b/app/helpers/groups_helper.rb index 575818c19f..908ed838f1 100644 --- a/app/helpers/groups_helper.rb +++ b/app/helpers/groups_helper.rb @@ -19,24 +19,6 @@ module GroupsHelper end end - def group_head_title - title = @group.name - - title = if current_action?(:issues) - "Issues - " + title - elsif current_action?(:merge_requests) - "Merge requests - " + title - elsif current_action?(:members) - "Members - " + title - elsif current_action?(:edit) - "Settings - " + title - else - title - end - - title - end - def group_settings_page? if current_controller?('groups') current_action?('edit') || current_action?('projects') diff --git a/app/helpers/issues_helper.rb b/app/helpers/issues_helper.rb index c3b4731dff..36d3f371c1 100644 --- a/app/helpers/issues_helper.rb +++ b/app/helpers/issues_helper.rb @@ -43,17 +43,6 @@ module IssuesHelper end end - def title_for_issue(issue_iid, project = @project) - return '' if project.nil? - - if project.default_issues_tracker? - issue = project.issues.where(iid: issue_iid).first - return issue.title if issue - end - - '' - end - def issue_timestamp(issue) # Shows the created at time and the updated at time if different ts = "#{time_ago_with_tooltip(issue.created_at, 'bottom', 'note_created_ago')}" @@ -110,5 +99,5 @@ module IssuesHelper end # Required for Gitlab::Markdown::IssueReferenceFilter - module_function :url_for_issue, :title_for_issue + module_function :url_for_issue end diff --git a/app/helpers/milestones_helper.rb b/app/helpers/milestones_helper.rb index 282bdf744d..93e33ebefd 100644 --- a/app/helpers/milestones_helper.rb +++ b/app/helpers/milestones_helper.rb @@ -28,6 +28,7 @@ module MilestonesHelper Milestone.where(project_id: @projects) end.active - options_from_collection_for_select(milestones, 'id', 'title', params[:milestone_id]) + grouped_milestones = Milestones::GroupService.new(milestones).execute + options_from_collection_for_select(grouped_milestones, 'title', 'title', params[:milestone_title]) end end diff --git a/app/helpers/page_layout_helper.rb b/app/helpers/page_layout_helper.rb new file mode 100644 index 0000000000..01b6a63552 --- /dev/null +++ b/app/helpers/page_layout_helper.rb @@ -0,0 +1,26 @@ +module PageLayoutHelper + def page_title(*titles) + @page_title ||= [] + + @page_title.push(*titles.compact) if titles.any? + + @page_title.join(" | ") + end + + def header_title(title = nil, title_url = nil) + if title + @header_title = title + @header_title_url = title_url + else + @header_title_url ? link_to(@header_title, @header_title_url) : @header_title + end + end + + def sidebar(name = nil) + if name + @sidebar = name + else + @sidebar + end + end +end diff --git a/app/helpers/projects_helper.rb b/app/helpers/projects_helper.rb index f70c33187b..af80fa5f15 100644 --- a/app/helpers/projects_helper.rb +++ b/app/helpers/projects_helper.rb @@ -192,46 +192,6 @@ module ProjectsHelper 'unknown' end - def project_head_title - title = @project.name_with_namespace - - title = if current_controller?(:tree) - "#{@project.path}\/#{@path} at #{@ref} - " + title - elsif current_controller?(:issues) - if current_action?(:show) - "Issue ##{@issue.iid} - #{@issue.title} - " + title - else - "Issues - " + title - end - elsif current_controller?(:blob) - if current_action?(:new) || current_action?(:create) - "New file at #{@ref}" - elsif current_action?(:show) - "#{@blob.path} at #{@ref}" - elsif @blob - "Edit file #{@blob.path} at #{@ref}" - end - elsif current_controller?(:commits) - "Commits at #{@ref} - " + title - elsif current_controller?(:merge_requests) - if current_action?(:show) - "Merge request ##{@merge_request.iid} - " + title - else - "Merge requests - " + title - end - elsif current_controller?(:wikis) - "Wiki - " + title - elsif current_controller?(:network) - "Network graph - " + title - elsif current_controller?(:graphs) - "Graphs - " + title - else - title - end - - title - end - def default_url_to_repo(project = nil) project = project || @project current_user ? project.url_to_repo : project.http_url_to_repo diff --git a/app/helpers/submodule_helper.rb b/app/helpers/submodule_helper.rb index 9954617c76..6def7793dc 100644 --- a/app/helpers/submodule_helper.rb +++ b/app/helpers/submodule_helper.rb @@ -2,8 +2,8 @@ module SubmoduleHelper include Gitlab::ShellAdapter # links to files listing for submodule if submodule is a project on this server - def submodule_links(submodule_item, ref = nil) - url = @repository.submodule_url_for(ref, submodule_item.path) + def submodule_links(submodule_item, ref = nil, repository = @repository) + url = repository.submodule_url_for(ref, submodule_item.path) return url, nil unless url =~ /([^\/:]+)\/([^\/]+\.git)\Z/ @@ -63,7 +63,7 @@ module SubmoduleHelper namespace = components.pop.gsub(/^\.\.$/, '') if namespace.empty? - namespace = @project.group.path + namespace = @project.namespace.name end [ diff --git a/app/helpers/visibility_level_helper.rb b/app/helpers/visibility_level_helper.rb index 66a1383d61..00d4c7f105 100644 --- a/app/helpers/visibility_level_helper.rb +++ b/app/helpers/visibility_level_helper.rb @@ -47,7 +47,7 @@ module VisibilityLevelHelper haml_tag :span do case level when Gitlab::VisibilityLevel::PRIVATE - haml_concat "The snippet is visible only for me" + haml_concat "The snippet is visible only for me." when Gitlab::VisibilityLevel::INTERNAL haml_concat "The snippet is visible for any logged in user." when Gitlab::VisibilityLevel::PUBLIC diff --git a/app/helpers/wiki_helper.rb b/app/helpers/wiki_helper.rb index a3bc64c010..f8a96516e6 100644 --- a/app/helpers/wiki_helper.rb +++ b/app/helpers/wiki_helper.rb @@ -6,6 +6,8 @@ module WikiHelper case wiki_page when Symbol wiki_page + when String + wiki_page else wiki_page.slug end diff --git a/app/mailers/devise_mailer.rb b/app/mailers/devise_mailer.rb new file mode 100644 index 0000000000..5395fe1641 --- /dev/null +++ b/app/mailers/devise_mailer.rb @@ -0,0 +1,4 @@ +class DeviseMailer < Devise::Mailer + default from: "GitLab <#{Gitlab.config.gitlab.email_from}>" + default reply_to: Gitlab.config.gitlab.email_reply_to +end diff --git a/app/mailers/notify.rb b/app/mailers/notify.rb index d35e7de0c2..4e45da3158 100644 --- a/app/mailers/notify.rb +++ b/app/mailers/notify.rb @@ -17,11 +17,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 @@ -70,7 +65,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/application_setting.rb b/app/models/application_setting.rb index 9a90a8e467..8b62d87f78 100644 --- a/app/models/application_setting.rb +++ b/app/models/application_setting.rb @@ -2,13 +2,11 @@ # # Table name: application_settings # -# id :integer not null, primary key +# id :integer not null, primary key # default_projects_limit :integer -# default_branch_protection :integer # signup_enabled :boolean # signin_enabled :boolean # gravatar_enabled :boolean -# twitter_sharing_enabled :boolean # sign_in_text :text # created_at :datetime # updated_at :datetime @@ -17,13 +15,16 @@ # twitter_sharing_enabled :boolean default(TRUE) # help_text :text # restricted_visibility_levels :text -# max_attachment_size :integer default(10) +# max_attachment_size :integer default(10), not null # default_project_visibility :integer # default_snippet_visibility :integer +# restricted_signup_domains :text # class ApplicationSetting < ActiveRecord::Base serialize :restricted_visibility_levels + serialize :restricted_signup_domains, Array + attr_accessor :restricted_signup_domains_raw validates :home_page_url, allow_blank: true, @@ -56,11 +57,29 @@ class ApplicationSetting < ActiveRecord::Base restricted_visibility_levels: Settings.gitlab['restricted_visibility_levels'], max_attachment_size: Settings.gitlab['max_attachment_size'], default_project_visibility: Settings.gitlab.default_projects_features['visibility_level'], - default_snippet_visibility: Settings.gitlab.default_projects_features['visibility_level'] + default_snippet_visibility: Settings.gitlab.default_projects_features['visibility_level'], + restricted_signup_domains: Settings.gitlab['restricted_signup_domains'] ) end def home_page_url_column_exist ActiveRecord::Base.connection.column_exists?(:application_settings, :home_page_url) end + + def restricted_signup_domains_raw + self.restricted_signup_domains.join("\n") unless self.restricted_signup_domains.nil? + end + + def restricted_signup_domains_raw=(values) + self.restricted_signup_domains = [] + self.restricted_signup_domains = values.split( + /\s*[,;]\s* # comma or semicolon, optionally surrounded by whitespace + | # or + \s # any whitespace character + | # or + [\r\n] # any number of newline characters + /x) + self.restricted_signup_domains.reject! { |d| d.empty? } + end + end diff --git a/app/models/deploy_key.rb b/app/models/deploy_key.rb index 85d52d558c..9ab663c04a 100644 --- a/app/models/deploy_key.rb +++ b/app/models/deploy_key.rb @@ -7,10 +7,10 @@ # created_at :datetime # updated_at :datetime # key :text -# public :boolean default(FALSE) # title :string(255) # type :string(255) # fingerprint :string(255) +# public :boolean default(FALSE), not null # class DeployKey < Key diff --git a/app/models/email.rb b/app/models/email.rb index 556b0e9586..935705e2ed 100644 --- a/app/models/email.rb +++ b/app/models/email.rb @@ -18,7 +18,6 @@ class Email < ActiveRecord::Base validates :email, presence: true, email: { strict_mode: true }, uniqueness: true validate :unique_email, if: ->(email) { email.email_changed? } - after_create :notify before_validation :cleanup_email def cleanup_email @@ -28,8 +27,4 @@ class Email < ActiveRecord::Base def unique_email self.errors.add(:email, 'has already been taken') if User.exists?(email: self.email) end - - def notify - NotificationService.new.new_email(self) - end end diff --git a/app/models/external_issue.rb b/app/models/external_issue.rb index 50efcb32f1..85fdb12bfd 100644 --- a/app/models/external_issue.rb +++ b/app/models/external_issue.rb @@ -15,6 +15,10 @@ class ExternalIssue @issue_identifier.to_s end + def title + "External Issue #{self}" + end + def ==(other) other.is_a?(self.class) && (to_s == other.to_s) end diff --git a/app/models/hooks/web_hook.rb b/app/models/hooks/web_hook.rb index e9fd441352..315d96af1b 100644 --- a/app/models/hooks/web_hook.rb +++ b/app/models/hooks/web_hook.rb @@ -30,15 +30,12 @@ class WebHook < ActiveRecord::Base validates :url, presence: true, format: { with: /\A#{URI.regexp(%w(http https))}\z/, message: "should be a valid url" } - def execute(data, hook_name) + def execute(data) parsed_url = URI.parse(url) if parsed_url.userinfo.blank? WebHook.post(url, body: data.to_json, - headers: { - "Content-Type" => "application/json", - "X-Gitlab-Event" => hook_name.singularize.titleize - }, + headers: { "Content-Type" => "application/json" }, verify: false) else post_url = url.gsub("#{parsed_url.userinfo}@", "") @@ -48,10 +45,7 @@ class WebHook < ActiveRecord::Base } WebHook.post(post_url, body: data.to_json, - headers: { - "Content-Type" => "application/json", - "X-Gitlab-Event" => hook_name.singularize.titleize - }, + headers: { "Content-Type" => "application/json" }, verify: false, basic_auth: auth) end @@ -60,7 +54,7 @@ class WebHook < ActiveRecord::Base false end - def async_execute(data, hook_name) - Sidekiq::Client.enqueue(ProjectWebHookWorker, id, data, hook_name) + def async_execute(data) + Sidekiq::Client.enqueue(ProjectWebHookWorker, id, data) end end diff --git a/app/models/key.rb b/app/models/key.rb index 49928b5f03..f32765cab8 100644 --- a/app/models/key.rb +++ b/app/models/key.rb @@ -10,6 +10,7 @@ # title :string(255) # type :string(255) # fingerprint :string(255) +# public :boolean default(FALSE), not null # require 'digest/md5' diff --git a/app/models/member.rb b/app/models/member.rb index d151c7b239..cae8caa23f 100644 --- a/app/models/member.rb +++ b/app/models/member.rb @@ -6,14 +6,14 @@ # access_level :integer not null # source_id :integer not null # source_type :string(255) not null -# user_id :integer not null +# user_id :integer # notification_level :integer not null # type :string(255) # created_at :datetime # updated_at :datetime # created_by_id :integer -# invite_email :string -# invite_token :string +# invite_email :string(255) +# invite_token :string(255) # invite_accepted_at :datetime # diff --git a/app/models/members/group_member.rb b/app/models/members/group_member.rb index c94bfd1983..fbd00af578 100644 --- a/app/models/members/group_member.rb +++ b/app/models/members/group_member.rb @@ -6,11 +6,15 @@ # access_level :integer not null # source_id :integer not null # source_type :string(255) not null -# user_id :integer not null +# user_id :integer # notification_level :integer not null # type :string(255) # created_at :datetime # updated_at :datetime +# created_by_id :integer +# invite_email :string(255) +# invite_token :string(255) +# invite_accepted_at :datetime # class GroupMember < Member diff --git a/app/models/members/project_member.rb b/app/models/members/project_member.rb index 0a3b4d2182..1b0c76917a 100644 --- a/app/models/members/project_member.rb +++ b/app/models/members/project_member.rb @@ -6,11 +6,15 @@ # access_level :integer not null # source_id :integer not null # source_type :string(255) not null -# user_id :integer not null +# user_id :integer # notification_level :integer not null # type :string(255) # created_at :datetime # updated_at :datetime +# created_by_id :integer +# invite_email :string(255) +# invite_token :string(255) +# invite_accepted_at :datetime # class ProjectMember < Member diff --git a/app/models/merge_request.rb b/app/models/merge_request.rb index fab3fb259f..e562319dd9 100644 --- a/app/models/merge_request.rb +++ b/app/models/merge_request.rb @@ -202,6 +202,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) @@ -211,6 +213,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.rb b/app/models/project.rb index e6a9cd0c3e..27f7625152 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -334,14 +334,18 @@ class Project < ActiveRecord::Base self.id end - def issue_exists?(issue_id) + def get_issue(issue_id) if default_issues_tracker? - self.issues.where(iid: issue_id).first.present? + issues.find_by(iid: issue_id) else - true + ExternalIssue.new(issue_id, self) end end + def issue_exists?(issue_id) + get_issue(issue_id) + end + def default_issue_tracker gitlab_issue_tracker_service || create_gitlab_issue_tracker_service end @@ -355,11 +359,7 @@ class Project < ActiveRecord::Base end def default_issues_tracker? - if external_issue_tracker - false - else - true - end + !external_issue_tracker end def external_issues_trackers @@ -496,7 +496,7 @@ class Project < ActiveRecord::Base def execute_hooks(data, hooks_scope = :push_hooks) hooks.send(hooks_scope).each do |hook| - hook.async_execute(data, hooks_scope.to_s) + hook.async_execute(data) end if group group.hooks.send(hooks_scope).each do |hook| diff --git a/app/models/project_import_data.rb b/app/models/project_import_data.rb index 6a8a8a56eb..cd3319f077 100644 --- a/app/models/project_import_data.rb +++ b/app/models/project_import_data.rb @@ -1,10 +1,10 @@ # == Schema Information # -# Table name: project_import_datas +# Table name: project_import_data # -# id :integer not null, primary key -# project_id :integer -# data :text +# id :integer not null, primary key +# project_id :integer +# data :text # require 'carrierwave/orm/activerecord' diff --git a/app/models/project_services/ci_service.rb b/app/models/project_services/ci_service.rb index 1a36e43924..77d48d4af5 100644 --- a/app/models/project_services/ci_service.rb +++ b/app/models/project_services/ci_service.rb @@ -15,6 +15,7 @@ # issues_events :boolean default(TRUE) # merge_requests_events :boolean default(TRUE) # tag_push_events :boolean default(TRUE) +# note_events :boolean default(TRUE), not null # # Base class for CI services diff --git a/app/models/project_services/custom_issue_tracker_service.rb b/app/models/project_services/custom_issue_tracker_service.rb index 8d25f62787..7c2027c18e 100644 --- a/app/models/project_services/custom_issue_tracker_service.rb +++ b/app/models/project_services/custom_issue_tracker_service.rb @@ -15,6 +15,7 @@ # issues_events :boolean default(TRUE) # merge_requests_events :boolean default(TRUE) # tag_push_events :boolean default(TRUE) +# note_events :boolean default(TRUE), not null # class CustomIssueTrackerService < IssueTrackerService diff --git a/app/models/project_services/emails_on_push_service.rb b/app/models/project_services/emails_on_push_service.rb index 6f6e5950aa..8f5d8b086e 100644 --- a/app/models/project_services/emails_on_push_service.rb +++ b/app/models/project_services/emails_on_push_service.rb @@ -15,6 +15,7 @@ # issues_events :boolean default(TRUE) # merge_requests_events :boolean default(TRUE) # tag_push_events :boolean default(TRUE) +# note_events :boolean default(TRUE), not null # class EmailsOnPushService < Service diff --git a/app/models/project_services/external_wiki_service.rb b/app/models/project_services/external_wiki_service.rb index a199d0e86f..9c46af7e72 100644 --- a/app/models/project_services/external_wiki_service.rb +++ b/app/models/project_services/external_wiki_service.rb @@ -2,14 +2,20 @@ # # Table name: services # -# id :integer not null, primary key -# type :string(255) -# title :string(255) -# project_id :integer not null -# created_at :datetime -# updated_at :datetime -# active :boolean default(FALSE), not null -# properties :text +# id :integer not null, primary key +# type :string(255) +# title :string(255) +# project_id :integer +# created_at :datetime +# updated_at :datetime +# active :boolean default(FALSE), not null +# properties :text +# template :boolean default(FALSE) +# push_events :boolean default(TRUE) +# issues_events :boolean default(TRUE) +# merge_requests_events :boolean default(TRUE) +# tag_push_events :boolean default(TRUE) +# note_events :boolean default(TRUE), not null # class ExternalWikiService < Service diff --git a/app/models/project_services/flowdock_service.rb b/app/models/project_services/flowdock_service.rb index 99e361dd6e..bf801ba61a 100644 --- a/app/models/project_services/flowdock_service.rb +++ b/app/models/project_services/flowdock_service.rb @@ -15,6 +15,7 @@ # issues_events :boolean default(TRUE) # merge_requests_events :boolean default(TRUE) # tag_push_events :boolean default(TRUE) +# note_events :boolean default(TRUE), not null # require "flowdock-git-hook" diff --git a/app/models/project_services/gemnasium_service.rb b/app/models/project_services/gemnasium_service.rb index 4e75bdfc95..91ef267ad7 100644 --- a/app/models/project_services/gemnasium_service.rb +++ b/app/models/project_services/gemnasium_service.rb @@ -15,6 +15,7 @@ # issues_events :boolean default(TRUE) # merge_requests_events :boolean default(TRUE) # tag_push_events :boolean default(TRUE) +# note_events :boolean default(TRUE), not null # require "gemnasium/gitlab_service" diff --git a/app/models/project_services/gitlab_ci_service.rb b/app/models/project_services/gitlab_ci_service.rb index 0f9838a575..f95bd79dfd 100644 --- a/app/models/project_services/gitlab_ci_service.rb +++ b/app/models/project_services/gitlab_ci_service.rb @@ -15,6 +15,7 @@ # issues_events :boolean default(TRUE) # merge_requests_events :boolean default(TRUE) # tag_push_events :boolean default(TRUE) +# note_events :boolean default(TRUE), not null # class GitlabCiService < CiService diff --git a/app/models/project_services/gitlab_issue_tracker_service.rb b/app/models/project_services/gitlab_issue_tracker_service.rb index 5f0553f3b0..0ebc0a3ba1 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 2fa5f0ce71..38cb64f8c4 100644 --- a/app/models/project_services/hipchat_service.rb +++ b/app/models/project_services/hipchat_service.rb @@ -15,12 +15,13 @@ # issues_events :boolean default(TRUE) # merge_requests_events :boolean default(TRUE) # tag_push_events :boolean default(TRUE) +# note_events :boolean default(TRUE), not null # 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 +42,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 +63,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/models/project_services/irker_service.rb b/app/models/project_services/irker_service.rb index e9e1e276e7..89f312e8c9 100644 --- a/app/models/project_services/irker_service.rb +++ b/app/models/project_services/irker_service.rb @@ -15,6 +15,7 @@ # issues_events :boolean default(TRUE) # merge_requests_events :boolean default(TRUE) # tag_push_events :boolean default(TRUE) +# note_events :boolean default(TRUE), not null # require 'uri' diff --git a/app/models/service.rb b/app/models/service.rb index 25a78dfa73..594e57518d 100644 --- a/app/models/service.rb +++ b/app/models/service.rb @@ -15,6 +15,7 @@ # issues_events :boolean default(TRUE) # merge_requests_events :boolean default(TRUE) # tag_push_events :boolean default(TRUE) +# note_events :boolean default(TRUE), not null # # To add new service you should build a class inherited from Service diff --git a/app/models/user.rb b/app/models/user.rb index 676c9d6dca..171d1a98c6 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -49,6 +49,7 @@ # password_automatically_set :boolean default(FALSE) # bitbucket_access_token :string(255) # bitbucket_access_token_secret :string(255) +# location :string(255) # public_email :string(255) default(""), not null # @@ -139,13 +140,16 @@ class User < ActiveRecord::Base validate :avatar_type, if: ->(user) { user.avatar_changed? } validate :unique_email, if: ->(user) { user.email_changed? } validate :owns_notification_email, if: ->(user) { user.notification_email_changed? } + validate :owns_public_email, if: ->(user) { user.public_email_changed? } validates :avatar, file_size: { maximum: 200.kilobytes.to_i } before_validation :generate_password, on: :create + before_validation :restricted_signup_domains, on: :create before_validation :sanitize_attrs before_validation :set_notification_email, if: ->(user) { user.email_changed? } before_validation :set_public_email, if: ->(user) { user.public_email_changed? } + after_update :update_emails_with_primary_email, if: ->(user) { user.email_changed? } before_save :ensure_authentication_token after_save :ensure_namespace_correct after_initialize :set_projects_limit @@ -303,13 +307,29 @@ class User < ActiveRecord::Base end def unique_email - self.errors.add(:email, 'has already been taken') if Email.exists?(email: self.email) + if !self.emails.exists?(email: self.email) && Email.exists?(email: self.email) + self.errors.add(:email, 'has already been taken') + end end def owns_notification_email self.errors.add(:notification_email, "is not an email you own") unless self.all_emails.include?(self.notification_email) end + def owns_public_email + self.errors.add(:public_email, "is not an email you own") unless self.all_emails.include?(self.public_email) + end + + def update_emails_with_primary_email + primary_email_record = self.emails.find_by(email: self.email) + if primary_email_record + primary_email_record.destroy + self.emails.create(email: self.email_was) + + self.update_secondary_emails! + end + end + # Groups user has access to def authorized_groups @authorized_groups ||= begin @@ -476,10 +496,16 @@ class User < ActiveRecord::Base def set_public_email if self.public_email.blank? || !self.all_emails.include?(self.public_email) - self.public_email = '' + self.public_email = nil end end + def update_secondary_emails! + self.set_notification_email + self.set_public_email + self.save if self.notification_email_changed? || self.public_email_changed? + end + def set_projects_limit connection_default_value_defined = new_record? && !projects_limit_changed? return unless self.projects_limit.nil? || connection_default_value_defined @@ -643,4 +669,27 @@ class User < ActiveRecord::Base select(:project_id). uniq.map(&:project_id) end + + def restricted_signup_domains + email_domains = current_application_settings.restricted_signup_domains + + unless email_domains.blank? + match_found = email_domains.any? do |domain| + escaped = Regexp.escape(domain).gsub('\*','.*?') + regexp = Regexp.new "^#{escaped}$", Regexp::IGNORECASE + email_domain = Mail::Address.new(self.email).domain + email_domain =~ regexp + end + + unless match_found + self.errors.add :email, + 'is not whitelisted. ' + + 'Email domains valid for registration are: ' + + email_domains.join(', ') + return false + end + end + + true + end end diff --git a/app/services/system_hooks_service.rb b/app/services/system_hooks_service.rb index 60235b6be2..c5d0b08845 100644 --- a/app/services/system_hooks_service.rb +++ b/app/services/system_hooks_service.rb @@ -7,12 +7,12 @@ class SystemHooksService def execute_hooks(data) SystemHook.all.each do |sh| - async_execute_hook(sh, data, 'system_hooks') + async_execute_hook sh, data end end - def async_execute_hook(hook, data, hook_name) - Sidekiq::Client.enqueue(SystemHookWorker, hook.id, data, hook_name) + def async_execute_hook(hook, data) + Sidekiq::Client.enqueue(SystemHookWorker, hook.id, data) end def build_event_data(model, event) diff --git a/app/services/test_hook_service.rb b/app/services/test_hook_service.rb index 5b447909de..ab661984fc 100644 --- a/app/services/test_hook_service.rb +++ b/app/services/test_hook_service.rb @@ -1,7 +1,7 @@ class TestHookService def execute(hook, current_user) data = Gitlab::PushDataBuilder.build_sample(project(hook), current_user) - hook.execute(data, 'push_hooks') + hook.execute(data) end private diff --git a/app/views/admin/appearances/preview.html.haml b/app/views/admin/appearances/preview.html.haml index 146e05ae3f..dd4a64e80b 100644 --- a/app/views/admin/appearances/preview.html.haml +++ b/app/views/admin/appearances/preview.html.haml @@ -1,3 +1,4 @@ +- page_title "Preview | Appearance" %h3.page-title Appearance settings - Preview %hr diff --git a/app/views/admin/appearances/show.html.haml b/app/views/admin/appearances/show.html.haml index 52bbbf0d52..089e8e4cb7 100644 --- a/app/views/admin/appearances/show.html.haml +++ b/app/views/admin/appearances/show.html.haml @@ -1,3 +1,4 @@ +- page_title "Appearance" %h3.page-title Appearance settings %p.light diff --git a/app/views/admin/application_settings/_form.html.haml b/app/views/admin/application_settings/_form.html.haml index 3f41504b9d..db99121fee 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') @@ -77,6 +77,11 @@ = f.label :max_attachment_size, 'Maximum attachment size (MB)', class: 'control-label col-sm-2' .col-sm-10 = f.number_field :max_attachment_size, class: 'form-control' + .form-group + = f.label :restricted_signup_domains, 'Restricted domains for sign-ups', class: 'control-label col-sm-2' + .col-sm-10 + = f.text_area :restricted_signup_domains_raw, placeholder: 'domain.com', class: 'form-control' + .help-block Ex: domain.com, *.domain.com. Wildcards allowed. Use separate lines for multiple entries. .form-actions = f.submit 'Save', class: 'btn btn-primary' diff --git a/app/views/admin/application_settings/show.html.haml b/app/views/admin/application_settings/show.html.haml index 39b66647a5..1632dd8aff 100644 --- a/app/views/admin/application_settings/show.html.haml +++ b/app/views/admin/application_settings/show.html.haml @@ -1,3 +1,4 @@ +- page_title "Settings" %h3.page-title Application settings %hr = render 'form' diff --git a/app/views/admin/applications/edit.html.haml b/app/views/admin/applications/edit.html.haml index e408ae2f29..c596866bde 100644 --- a/app/views/admin/applications/edit.html.haml +++ b/app/views/admin/applications/edit.html.haml @@ -1,3 +1,4 @@ +- page_title "Edit", @application.name, "Applications" %h3.page-title Edit application - @url = admin_application_path(@application) -= render 'form', application: @application \ No newline at end of file += render 'form', application: @application diff --git a/app/views/admin/applications/index.html.haml b/app/views/admin/applications/index.html.haml index d550278710..fc921a966f 100644 --- a/app/views/admin/applications/index.html.haml +++ b/app/views/admin/applications/index.html.haml @@ -1,3 +1,4 @@ +- page_title "Applications" %h3.page-title System OAuth applications %p.light diff --git a/app/views/admin/applications/new.html.haml b/app/views/admin/applications/new.html.haml index 7c62425f19..6310d89bd6 100644 --- a/app/views/admin/applications/new.html.haml +++ b/app/views/admin/applications/new.html.haml @@ -1,3 +1,4 @@ +- page_title "New Application" %h3.page-title New application - @url = admin_applications_path -= render 'form', application: @application \ No newline at end of file += render 'form', application: @application diff --git a/app/views/admin/applications/show.html.haml b/app/views/admin/applications/show.html.haml index 2abe390ce1..0ea2ffeda9 100644 --- a/app/views/admin/applications/show.html.haml +++ b/app/views/admin/applications/show.html.haml @@ -1,3 +1,4 @@ +- page_title @application.name, "Applications" %h3.page-title Application: #{@application.name} diff --git a/app/views/admin/background_jobs/show.html.haml b/app/views/admin/background_jobs/show.html.haml index 4ef8e878a7..3a01e11510 100644 --- a/app/views/admin/background_jobs/show.html.haml +++ b/app/views/admin/background_jobs/show.html.haml @@ -1,3 +1,4 @@ +- page_title "Background Jobs" %h3.page-title Background Jobs %p.light GitLab uses #{link_to "sidekiq", "http://sidekiq.org/"} library for async job processing diff --git a/app/views/admin/broadcast_messages/index.html.haml b/app/views/admin/broadcast_messages/index.html.haml index 7e29311bf4..267c9a5292 100644 --- a/app/views/admin/broadcast_messages/index.html.haml +++ b/app/views/admin/broadcast_messages/index.html.haml @@ -1,3 +1,4 @@ +- page_title "Broadcast Messages" %h3.page-title Broadcast Messages %p.light diff --git a/app/views/admin/deploy_keys/index.html.haml b/app/views/admin/deploy_keys/index.html.haml index 2ae83ab95f..367d25cd6a 100644 --- a/app/views/admin/deploy_keys/index.html.haml +++ b/app/views/admin/deploy_keys/index.html.haml @@ -1,3 +1,4 @@ +- page_title "Deploy Keys" .panel.panel-default .panel-heading Public deploy keys (#{@deploy_keys.count}) diff --git a/app/views/admin/deploy_keys/new.html.haml b/app/views/admin/deploy_keys/new.html.haml index c00049424c..5b46b3222a 100644 --- a/app/views/admin/deploy_keys/new.html.haml +++ b/app/views/admin/deploy_keys/new.html.haml @@ -1,3 +1,4 @@ +- page_title "New Deploy Key" %h3.page-title New public deploy key %hr diff --git a/app/views/admin/deploy_keys/show.html.haml b/app/views/admin/deploy_keys/show.html.haml index cfa2adf92e..ea361ca4bd 100644 --- a/app/views/admin/deploy_keys/show.html.haml +++ b/app/views/admin/deploy_keys/show.html.haml @@ -1,3 +1,4 @@ +- page_title @deploy_key.title, "Deploy Keys" .row .col-md-4 .panel.panel-default diff --git a/app/views/admin/emails/show.html.haml b/app/views/admin/emails/show.html.haml index 90e4e3aa2f..a2f421a853 100644 --- a/app/views/admin/emails/show.html.haml +++ b/app/views/admin/emails/show.html.haml @@ -1,5 +1,6 @@ +- page_title "Email Notification" %h3.page-title - Send email notication + Send email notification %p.light You can notify the app / group or a project by sending them an email notification diff --git a/app/views/admin/git_hooks/index.html.haml b/app/views/admin/git_hooks/index.html.haml index 297b1cb16f..276de761ed 100644 --- a/app/views/admin/git_hooks/index.html.haml +++ b/app/views/admin/git_hooks/index.html.haml @@ -1,3 +1,4 @@ +- page_title "Git Hooks" %h3.page-title Pre-defined git hooks. %p.light @@ -10,4 +11,4 @@ .alert.alert-danger - @git_hook.errors.full_messages.each do |msg| %p= msg - = render "shared/git_hooks_form", f: f \ No newline at end of file + = render "shared/git_hooks_form", f: f diff --git a/app/views/admin/groups/edit.html.haml b/app/views/admin/groups/edit.html.haml index 824e51c1cf..eb09a6328e 100644 --- a/app/views/admin/groups/edit.html.haml +++ b/app/views/admin/groups/edit.html.haml @@ -1,3 +1,4 @@ +- page_title "Edit", @group.name, "Groups" %h3.page-title Edit group: #{@group.name} %hr = render 'form' diff --git a/app/views/admin/groups/index.html.haml b/app/views/admin/groups/index.html.haml index 4c53ff5570..e00b23ad99 100644 --- a/app/views/admin/groups/index.html.haml +++ b/app/views/admin/groups/index.html.haml @@ -1,3 +1,4 @@ +- page_title "Groups" %h3.page-title Groups (#{@groups.total_count}) = link_to 'New Group', new_admin_group_path, class: "btn btn-new pull-right" diff --git a/app/views/admin/groups/new.html.haml b/app/views/admin/groups/new.html.haml index f46f45c551..c81ee552ac 100644 --- a/app/views/admin/groups/new.html.haml +++ b/app/views/admin/groups/new.html.haml @@ -1,3 +1,4 @@ +- page_title "New Group" %h3.page-title New group %hr = render 'form' diff --git a/app/views/admin/groups/show.html.haml b/app/views/admin/groups/show.html.haml index 46bec86f17..14a0d9280c 100644 --- a/app/views/admin/groups/show.html.haml +++ b/app/views/admin/groups/show.html.haml @@ -1,3 +1,4 @@ +- page_title @group.name, "Groups" %h3.page-title Group: #{@group.name} @@ -87,7 +88,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, skip_ldap: @group.ldap_synced?) + = users_select_tag(:user_ids, multiple: true, email_user: true, skip_ldap: @group.ldap_synced?, 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/hooks/index.html.haml b/app/views/admin/hooks/index.html.haml index 7a9dc113f2..e74e1e85f4 100644 --- a/app/views/admin/hooks/index.html.haml +++ b/app/views/admin/hooks/index.html.haml @@ -1,3 +1,4 @@ +- page_title "System Hooks" %h3.page-title System hooks diff --git a/app/views/admin/keys/show.html.haml b/app/views/admin/keys/show.html.haml index 5b23027b3a..9ee77c7739 100644 --- a/app/views/admin/keys/show.html.haml +++ b/app/views/admin/keys/show.html.haml @@ -1 +1,2 @@ +- page_title @key.title, "Keys" = render "profiles/keys/key_details", admin: true diff --git a/app/views/admin/logs/show.html.haml b/app/views/admin/logs/show.html.haml index 384c6ee9af..1484baa78e 100644 --- a/app/views/admin/logs/show.html.haml +++ b/app/views/admin/logs/show.html.haml @@ -1,3 +1,4 @@ +- page_title "Logs" - loggers = [Gitlab::GitLogger, Gitlab::AppLogger, Gitlab::ProductionLogger, Gitlab::SidekiqLogger] %ul.nav.nav-tabs.log-tabs diff --git a/app/views/admin/projects/index.html.haml b/app/views/admin/projects/index.html.haml index 3bbe10bc27..f43d46356f 100644 --- a/app/views/admin/projects/index.html.haml +++ b/app/views/admin/projects/index.html.haml @@ -1,6 +1,7 @@ +- page_title "Projects" += 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/projects/show.html.haml b/app/views/admin/projects/show.html.haml index 78684c692c..4c2865ac3f 100644 --- a/app/views/admin/projects/show.html.haml +++ b/app/views/admin/projects/show.html.haml @@ -1,3 +1,4 @@ +- page_title @project.name_with_namespace, "Projects" %h3.page-title Project: #{@project.name_with_namespace} = link_to edit_project_path(@project), class: "btn pull-right" do diff --git a/app/views/admin/services/_form.html.haml b/app/views/admin/services/_form.html.haml index 34ca7776c9..cdbfc60f9a 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/services/edit.html.haml b/app/views/admin/services/edit.html.haml index bcc5832792..53d970e33c 100644 --- a/app/views/admin/services/edit.html.haml +++ b/app/views/admin/services/edit.html.haml @@ -1 +1,2 @@ +- page_title @service.title, "Service Templates" = render 'form' diff --git a/app/views/admin/services/index.html.haml b/app/views/admin/services/index.html.haml index 0093fb9776..e237729114 100644 --- a/app/views/admin/services/index.html.haml +++ b/app/views/admin/services/index.html.haml @@ -1,3 +1,4 @@ +- page_title "Service Templates" %h3.page-title Service templates %p.light Service template allows you to set default values for project services diff --git a/app/views/admin/users/edit.html.haml b/app/views/admin/users/edit.html.haml index d71d8189c5..a8837d74dd 100644 --- a/app/views/admin/users/edit.html.haml +++ b/app/views/admin/users/edit.html.haml @@ -1,3 +1,4 @@ +- page_title "Edit", @user.name, "Users" %h3.page-title Edit user: #{@user.name} .back-link diff --git a/app/views/admin/users/index.html.haml b/app/views/admin/users/index.html.haml index 3fc205d23b..2962319340 100644 --- a/app/views/admin/users/index.html.haml +++ b/app/views/admin/users/index.html.haml @@ -1,6 +1,7 @@ +- page_title "Users" += 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/admin/users/new.html.haml b/app/views/admin/users/new.html.haml index 8fbb757f42..bfc36ed737 100644 --- a/app/views/admin/users/new.html.haml +++ b/app/views/admin/users/new.html.haml @@ -1,3 +1,4 @@ +- page_title "New User" %h3.page-title New user %hr diff --git a/app/views/admin/users/show.html.haml b/app/views/admin/users/show.html.haml index 3524f04c5e..7fc8520610 100644 --- a/app/views/admin/users/show.html.haml +++ b/app/views/admin/users/show.html.haml @@ -1,3 +1,4 @@ +- page_title @user.name, "Users" %h3.page-title User: = @user.name diff --git a/app/views/audit_events/group_log.html.haml b/app/views/audit_events/group_log.html.haml index 7a63b50dee..92a10e355e 100644 --- a/app/views/audit_events/group_log.html.haml +++ b/app/views/audit_events/group_log.html.haml @@ -1,3 +1,4 @@ +- page_title "Audit Events" %h3.page-title Group Audit Events %p.light Events in #{@group.name} diff --git a/app/views/audit_events/project_log.html.haml b/app/views/audit_events/project_log.html.haml index 061efd3c54..5fa7b70542 100644 --- a/app/views/audit_events/project_log.html.haml +++ b/app/views/audit_events/project_log.html.haml @@ -1,3 +1,4 @@ +- page_title "Audit Events" %h3.page-title Project Audit Events %p.light Events in #{@project.path_with_namespace} diff --git a/app/views/dashboard/groups/index.html.haml b/app/views/dashboard/groups/index.html.haml index 0cb7f764fa..5ecd53cff8 100644 --- a/app/views/dashboard/groups/index.html.haml +++ b/app/views/dashboard/groups/index.html.haml @@ -1,3 +1,4 @@ +- page_title "Groups" %h3.page-title Group Membership - if current_user.can_create_group? diff --git a/app/views/dashboard/issues.html.haml b/app/views/dashboard/issues.html.haml index 62cc80a30d..dfdf0d68c8 100644 --- a/app/views/dashboard/issues.html.haml +++ b/app/views/dashboard/issues.html.haml @@ -1,3 +1,4 @@ +- page_title "Issues" = content_for :meta_tags do - if current_user = auto_discovery_link_tag(:atom, issues_dashboard_url(format: :atom, private_token: current_user.private_token), title: "#{current_user.name} issues") diff --git a/app/views/dashboard/merge_requests.html.haml b/app/views/dashboard/merge_requests.html.haml index 97a42461b4..a7e1b08a0a 100644 --- a/app/views/dashboard/merge_requests.html.haml +++ b/app/views/dashboard/merge_requests.html.haml @@ -1,3 +1,4 @@ +- page_title "Merge Requests" %h3.page-title Merge Requests diff --git a/app/views/dashboard/milestones/index.html.haml b/app/views/dashboard/milestones/index.html.haml index 9944c0df81..9a9a5e139a 100644 --- a/app/views/dashboard/milestones/index.html.haml +++ b/app/views/dashboard/milestones/index.html.haml @@ -1,3 +1,4 @@ +- page_title "Milestones" %h3.page-title Milestones %span.pull-right #{@dashboard_milestones.count} milestones diff --git a/app/views/dashboard/milestones/show.html.haml b/app/views/dashboard/milestones/show.html.haml index 57cce9ab74..24f0bcb60d 100644 --- a/app/views/dashboard/milestones/show.html.haml +++ b/app/views/dashboard/milestones/show.html.haml @@ -1,3 +1,4 @@ +- page_title @dashboard_milestone.title, "Milestones" %h4.page-title .issue-box{ class: "issue-box-#{@dashboard_milestone.closed? ? 'closed' : 'open'}" } - if @dashboard_milestone.closed? diff --git a/app/views/dashboard/projects/starred.html.haml b/app/views/dashboard/projects/starred.html.haml index f4ad2b294b..8aaa0a7f07 100644 --- a/app/views/dashboard/projects/starred.html.haml +++ b/app/views/dashboard/projects/starred.html.haml @@ -1,4 +1,7 @@ +- page_title "Starred Projects" - if @projects.any? + = render 'shared/show_aside' + .dashboard.row %section.activities.col-md-8 = render 'dashboard/activities' @@ -15,9 +18,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 2754a4894d..5001c2101e 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/devise/registrations/new.html.haml b/app/views/devise/registrations/new.html.haml index d3e37f7494..42cfbbf84f 100644 --- a/app/views/devise/registrations/new.html.haml +++ b/app/views/devise/registrations/new.html.haml @@ -1,3 +1,4 @@ +- page_title "Sign up" = render 'devise/shared/signup_box' -= render 'devise/shared/sign_in_link' \ No newline at end of file += render 'devise/shared/sign_in_link' diff --git a/app/views/devise/sessions/new.html.haml b/app/views/devise/sessions/new.html.haml index 89e4e229ac..dbc8eda619 100644 --- a/app/views/devise/sessions/new.html.haml +++ b/app/views/devise/sessions/new.html.haml @@ -1,3 +1,4 @@ +- page_title "Sign in" %div - if signin_enabled? || ldap_enabled? = render 'devise/shared/signin_box' diff --git a/app/views/doorkeeper/applications/edit.html.haml b/app/views/doorkeeper/applications/edit.html.haml index 61584eb9c4..fb6aa30ace 100644 --- a/app/views/doorkeeper/applications/edit.html.haml +++ b/app/views/doorkeeper/applications/edit.html.haml @@ -1,2 +1,3 @@ +- page_title "Edit", @application.name, "Applications" %h3.page-title Edit application -= render 'form', application: @application \ No newline at end of file += render 'form', application: @application diff --git a/app/views/doorkeeper/applications/index.html.haml b/app/views/doorkeeper/applications/index.html.haml index e5be4b4bca..3b0b19107c 100644 --- a/app/views/doorkeeper/applications/index.html.haml +++ b/app/views/doorkeeper/applications/index.html.haml @@ -1,3 +1,4 @@ +- page_title "Applications" %h3.page-title Your applications %p= link_to 'New Application', new_oauth_application_path, class: 'btn btn-success' %table.table.table-striped @@ -13,4 +14,4 @@ %td= link_to application.name, oauth_application_path(application) %td= application.redirect_uri %td= link_to 'Edit', edit_oauth_application_path(application), class: 'btn btn-link' - %td= render 'delete_form', application: application \ No newline at end of file + %td= render 'delete_form', application: application diff --git a/app/views/doorkeeper/applications/show.html.haml b/app/views/doorkeeper/applications/show.html.haml index 82e78b4af1..80340aca54 100644 --- a/app/views/doorkeeper/applications/show.html.haml +++ b/app/views/doorkeeper/applications/show.html.haml @@ -1,3 +1,4 @@ +- page_title @application.name, "Applications" %h3.page-title Application: #{@application.name} diff --git a/app/views/errors/access_denied.html.haml b/app/views/errors/access_denied.html.haml index a1d8664c4c..012e985764 100644 --- a/app/views/errors/access_denied.html.haml +++ b/app/views/errors/access_denied.html.haml @@ -1,3 +1,4 @@ +- page_title "Access Denied" %h1 403 %h3 Access Denied %hr diff --git a/app/views/errors/encoding.html.haml b/app/views/errors/encoding.html.haml index 64c7451a8d..90cfbebfcc 100644 --- a/app/views/errors/encoding.html.haml +++ b/app/views/errors/encoding.html.haml @@ -1,3 +1,4 @@ +- page_title "Encoding Error" %h1 500 %h3 Encoding Error %hr diff --git a/app/views/errors/git_not_found.html.haml b/app/views/errors/git_not_found.html.haml index 189e53bca5..ff5d4cc150 100644 --- a/app/views/errors/git_not_found.html.haml +++ b/app/views/errors/git_not_found.html.haml @@ -1,3 +1,4 @@ +- page_title "Git Resource Not Found" %h1 404 %h3 Git Resource Not found %hr diff --git a/app/views/errors/not_found.html.haml b/app/views/errors/not_found.html.haml index 7bf88f592c..3756b98ebb 100644 --- a/app/views/errors/not_found.html.haml +++ b/app/views/errors/not_found.html.haml @@ -1,3 +1,4 @@ +- page_title "Not Found" %h1 404 %h3 The resource you were looking for doesn't exist. %hr diff --git a/app/views/errors/omniauth_error.html.haml b/app/views/errors/omniauth_error.html.haml index f3c8221a9d..3e70e98a24 100644 --- a/app/views/errors/omniauth_error.html.haml +++ b/app/views/errors/omniauth_error.html.haml @@ -1,3 +1,4 @@ +- page_title "Auth Error" %h1 422 %h3 Sign-in using #{@provider} auth failed %hr diff --git a/app/views/explore/groups/index.html.haml b/app/views/explore/groups/index.html.haml index 2ea6cb1865..c05d45e010 100644 --- a/app/views/explore/groups/index.html.haml +++ b/app/views/explore/groups/index.html.haml @@ -1,3 +1,4 @@ +- page_title "Groups" .clearfix .pull-left = form_tag explore_groups_path, method: :get, class: 'form-inline form-tiny' do |f| diff --git a/app/views/explore/projects/index.html.haml b/app/views/explore/projects/index.html.haml index 5086b58cd0..ba2276f51c 100644 --- a/app/views/explore/projects/index.html.haml +++ b/app/views/explore/projects/index.html.haml @@ -1,3 +1,4 @@ +- page_title "Projects" .clearfix = render 'filter' diff --git a/app/views/explore/projects/starred.html.haml b/app/views/explore/projects/starred.html.haml index 420f069375..b5d146b1f2 100644 --- a/app/views/explore/projects/starred.html.haml +++ b/app/views/explore/projects/starred.html.haml @@ -1,3 +1,4 @@ +- page_title "Starred Projects" .explore-trending-block %p.lead %i.fa.fa-star diff --git a/app/views/explore/projects/trending.html.haml b/app/views/explore/projects/trending.html.haml index 18749ac00a..5ae2653fed 100644 --- a/app/views/explore/projects/trending.html.haml +++ b/app/views/explore/projects/trending.html.haml @@ -1,3 +1,4 @@ +- page_title "Trending Projects" .explore-title %h3 Explore GitLab diff --git a/app/views/groups/_settings_nav.html.haml b/app/views/groups/_settings_nav.html.haml deleted file mode 100644 index b660e7e751..0000000000 --- a/app/views/groups/_settings_nav.html.haml +++ /dev/null @@ -1,27 +0,0 @@ -%ul.sidebar-subnav - = nav_link(path: 'groups#edit') do - = link_to edit_group_path(@group), title: 'Group', data: {placement: 'right'} do - = icon('pencil-square-o') - %span - Group - = nav_link(path: 'groups#projects') do - = link_to projects_group_path(@group), title: 'Projects', data: {placement: 'right'} do - = icon('folder') - %span - Projects - - if ldap_enabled? - = nav_link(controller: :ldap_group_links) do - = link_to group_ldap_group_links_path(@group) do - %i.fa.fa-exchange - %span - LDAP Groups - = nav_link(controller: :hooks) do - = link_to group_hooks_path(@group) do - %i.fa.fa-link - %span - Web Hooks - = nav_link(controller: :audit_events) do - = link_to group_audit_events_path(@group) do - %i.fa.fa-file-text-o - %span - Audit Events diff --git a/app/views/groups/edit.html.haml b/app/views/groups/edit.html.haml index 30d8a5c951..4621b529ec 100644 --- a/app/views/groups/edit.html.haml +++ b/app/views/groups/edit.html.haml @@ -1,3 +1,4 @@ +- page_title "Settings" .panel.panel-default .panel-heading %strong= @group.name diff --git a/app/views/groups/group_members/index.html.haml b/app/views/groups/group_members/index.html.haml index 1e74704f40..b6ca850b3f 100644 --- a/app/views/groups/group_members/index.html.haml +++ b/app/views/groups/group_members/index.html.haml @@ -1,3 +1,4 @@ +- page_title "Members" - show_roles = should_user_see_group_roles?(current_user, @group) %h3.page-title diff --git a/app/views/groups/hooks/index.html.haml b/app/views/groups/hooks/index.html.haml index 7039c070d9..d8a2f0b19d 100644 --- a/app/views/groups/hooks/index.html.haml +++ b/app/views/groups/hooks/index.html.haml @@ -1,3 +1,4 @@ +- page_title "Web Hooks" %h3.page-title Web hooks diff --git a/app/views/groups/issues.html.haml b/app/views/groups/issues.html.haml index cf0da2da46..6a3da6adac 100644 --- a/app/views/groups/issues.html.haml +++ b/app/views/groups/issues.html.haml @@ -1,3 +1,4 @@ +- page_title "Issues" = content_for :meta_tags do - if current_user = auto_discovery_link_tag(:atom, issues_group_url(@group, format: :atom, private_token: current_user.private_token), title: "#{@group.name} issues") diff --git a/app/views/groups/ldap_group_links/index.html.haml b/app/views/groups/ldap_group_links/index.html.haml index 45f2703e07..44791bc7ce 100644 --- a/app/views/groups/ldap_group_links/index.html.haml +++ b/app/views/groups/ldap_group_links/index.html.haml @@ -1,3 +1,4 @@ +- page_title "LDAP Groups" %h3.page-title Linked LDAP groups = render 'ldap_group_links/form', group: @group = render 'ldap_group_links/ldap_group_links', group: @group diff --git a/app/views/groups/merge_requests.html.haml b/app/views/groups/merge_requests.html.haml index 1ad7490563..268f33d576 100644 --- a/app/views/groups/merge_requests.html.haml +++ b/app/views/groups/merge_requests.html.haml @@ -1,3 +1,4 @@ +- page_title "Merge Requests" %h3.page-title Merge Requests diff --git a/app/views/groups/milestones/index.html.haml b/app/views/groups/milestones/index.html.haml index 008d5a6bd2..385222fa5b 100644 --- a/app/views/groups/milestones/index.html.haml +++ b/app/views/groups/milestones/index.html.haml @@ -1,3 +1,4 @@ +- page_title "Milestones" %h3.page-title Milestones %span.pull-right #{@group_milestones.count} milestones diff --git a/app/views/groups/milestones/show.html.haml b/app/views/groups/milestones/show.html.haml index fb32f2caa4..6c41cd6b9e 100644 --- a/app/views/groups/milestones/show.html.haml +++ b/app/views/groups/milestones/show.html.haml @@ -1,3 +1,4 @@ +- page_title @group_milestone.title, "Milestones" %h4.page-title .issue-box{ class: "issue-box-#{@group_milestone.closed? ? 'closed' : 'open'}" } - if @group_milestone.closed? diff --git a/app/views/groups/new.html.haml b/app/views/groups/new.html.haml index 6e17cdaef6..edb882bea1 100644 --- a/app/views/groups/new.html.haml +++ b/app/views/groups/new.html.haml @@ -1,3 +1,5 @@ +- page_title 'New Group' +- header_title 'New Group' = form_for @group, html: { class: 'group-form form-horizontal' } do |f| - if @group.errors.any? .alert.alert-danger diff --git a/app/views/groups/projects.html.haml b/app/views/groups/projects.html.haml index 05683de503..e28e732f09 100644 --- a/app/views/groups/projects.html.haml +++ b/app/views/groups/projects.html.haml @@ -1,3 +1,4 @@ +- page_title "Projects" .panel.panel-default .panel-heading %strong= @group.name diff --git a/app/views/groups/show.html.haml b/app/views/groups/show.html.haml index 872a498463..f6f5c07db2 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 @@ -35,5 +38,3 @@ = render "projects", projects: @projects %br = render "shared_projects", projects: @shared_projects - = link_to '#aside', class: 'show-aside' do - %i.fa.fa-angle-left diff --git a/app/views/help/show.html.haml b/app/views/help/show.html.haml index cc1be6a717..8551496b98 100644 --- a/app/views/help/show.html.haml +++ b/app/views/help/show.html.haml @@ -1,2 +1,3 @@ +- page_title @file.humanize, *@category.split("/").reverse.map(&:humanize) .documentation.wiki = markdown @markdown.gsub('$your_email', current_user.email) diff --git a/app/views/help/ui.html.haml b/app/views/help/ui.html.haml index 246a6c1bdf..7c89457ace 100644 --- a/app/views/help/ui.html.haml +++ b/app/views/help/ui.html.haml @@ -1,3 +1,4 @@ +- page_title "UI Development Kit", "Help" - lorem = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed fermentum nisi sapien, non consequat lectus aliquam ultrices. Suspendisse sodales est euismod nunc condimentum, a consectetur diam ornare." .gitlab-ui-dev-kit diff --git a/app/views/import/bitbucket/status.html.haml b/app/views/import/bitbucket/status.html.haml index 4e49bbbc7f..9d2858e4e7 100644 --- a/app/views/import/bitbucket/status.html.haml +++ b/app/views/import/bitbucket/status.html.haml @@ -1,3 +1,4 @@ +- page_title "Bitbucket import" %h3.page-title %i.fa.fa-bitbucket Import projects from Bitbucket diff --git a/app/views/import/github/status.html.haml b/app/views/import/github/status.html.haml index f0bc3e6b1a..ef55249823 100644 --- a/app/views/import/github/status.html.haml +++ b/app/views/import/github/status.html.haml @@ -1,3 +1,4 @@ +- page_title "GitHub import" %h3.page-title %i.fa.fa-github Import projects from GitHub diff --git a/app/views/import/gitlab/status.html.haml b/app/views/import/gitlab/status.html.haml index 33b0a21acf..727f3c7e7f 100644 --- a/app/views/import/gitlab/status.html.haml +++ b/app/views/import/gitlab/status.html.haml @@ -1,3 +1,4 @@ +- page_title "GitLab.com import" %h3.page-title %i.fa.fa-heart Import projects from GitLab.com diff --git a/app/views/import/gitorious/status.html.haml b/app/views/import/gitorious/status.html.haml index 78c5e957be..bff7ee7c85 100644 --- a/app/views/import/gitorious/status.html.haml +++ b/app/views/import/gitorious/status.html.haml @@ -1,3 +1,4 @@ +- page_title "Gitorious import" %h3.page-title %i.icon-gitorious.icon-gitorious-big Import projects from Gitorious.org diff --git a/app/views/import/google_code/new.html.haml b/app/views/import/google_code/new.html.haml index ce78fec205..9c64e0a009 100644 --- a/app/views/import/google_code/new.html.haml +++ b/app/views/import/google_code/new.html.haml @@ -1,3 +1,4 @@ +- page_title "Google Code import" %h3.page-title %i.fa.fa-google Import projects from Google Code diff --git a/app/views/import/google_code/new_user_map.html.haml b/app/views/import/google_code/new_user_map.html.haml index 9c6824ecad..e53ebda7dc 100644 --- a/app/views/import/google_code/new_user_map.html.haml +++ b/app/views/import/google_code/new_user_map.html.haml @@ -1,3 +1,4 @@ +- page_title "User map", "Google Code import" %h3.page-title %i.fa.fa-google Import projects from Google Code diff --git a/app/views/import/google_code/status.html.haml b/app/views/import/google_code/status.html.haml index 2013b8c03c..e8ec79e72f 100644 --- a/app/views/import/google_code/status.html.haml +++ b/app/views/import/google_code/status.html.haml @@ -1,16 +1,21 @@ +- page_title "Google Code import" %h3.page-title %i.fa.fa-google Import projects from Google Code -%p.light - Select projects you want to import. -%p.light - Optionally, you can - = link_to "customize", new_user_map_import_google_code_path - how Google Code email addresses and usernames are imported into GitLab. -%hr -%p - = button_tag 'Import all projects', class: "btn btn-success js-import-all" +- if @repos.any? + %p.light + Select projects you want to import. + %p.light + Optionally, you can + = link_to "customize", new_user_map_import_google_code_path + how Google Code email addresses and usernames are imported into GitLab. + %hr + %p + - if @incompatible_repos.any? + = button_tag 'Import all compatible projects', class: "btn btn-success js-import-all" + - else + = button_tag 'Import all projects', class: "btn btn-success js-import-all" %table.table.import-jobs %thead @@ -44,6 +49,22 @@ = "#{current_user.username}/#{repo.name}" %td.import-actions.job-status = button_tag "Import", class: "btn js-add-to-import" + - @incompatible_repos.each do |repo| + %tr{id: "repo_#{repo.id}"} + %td + = link_to repo.name, "https://code.google.com/p/#{repo.name}", target: "_blank" + %td.import-target + %td.import-actions-job-status + = label_tag "Incompatible Project", nil, class: "label label-danger" + +- if @incompatible_repos.any? + %p + One or more of your Google Code projects cannot be imported into GitLab + directly because they use Subversion or Mercurial for version control, + rather than Git. Please convert them to Git on Google Code, and go + through the + = link_to "import flow", new_import_google_code_path + again. :coffeescript new ImporterStatus("#{jobs_import_google_code_path}", "#{import_google_code_path}") diff --git a/app/views/invites/show.html.haml b/app/views/invites/show.html.haml index ab0ecffe4d..2fd4859c1c 100644 --- a/app/views/invites/show.html.haml +++ b/app/views/invites/show.html.haml @@ -1,3 +1,4 @@ +- page_title "Invitation" %h3.page-title Invitation %p diff --git a/app/views/layouts/_empty_head_panel.html.haml b/app/views/layouts/_empty_head_panel.html.haml index b81c2d0364..358caa3868 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.html.haml b/app/views/layouts/_head.html.haml index fd4165d6b6..f3f9723379 100644 --- a/app/views/layouts/_head.html.haml +++ b/app/views/layouts/_head.html.haml @@ -1,10 +1,10 @@ +- page_title "GitLab" %head %meta{charset: "utf-8"} + %meta{'http-equiv' => 'X-UA-Compatible', content: 'IE=edge'} %meta{content: "GitLab Enterprise Edition", name: "description"} - %title - = "#{title} | " if defined?(title) - GitLab + %title= page_title = favicon_link_tag 'favicon.ico' = stylesheet_link_tag "application", :media => "all" diff --git a/app/views/layouts/_head_panel.html.haml b/app/views/layouts/_head_panel.html.haml index 8d4c7b39b1..3329a71243 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 } - .navbar-inner - .container - %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 + .container + %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/_page.html.haml b/app/views/layouts/_page.html.haml index 0fa2ec9824..5c55bdb546 100644 --- a/app/views/layouts/_page.html.haml +++ b/app/views/layouts/_page.html.haml @@ -1,8 +1,8 @@ .page-with-sidebar{ class: nav_sidebar_class } = render "layouts/broadcast" .sidebar-wrapper - - if defined?(sidebar) - = render(sidebar) + - if defined?(sidebar) && sidebar + = render "layouts/nav/#{sidebar}" - elsif current_user = render 'layouts/nav/dashboard' .collapse-nav diff --git a/app/views/layouts/_public_head_panel.html.haml b/app/views/layouts/_public_head_panel.html.haml index 98a87a39bd..8a297566d6 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/admin.html.haml b/app/views/layouts/admin.html.haml index ab84e87c30..1c738719bd 100644 --- a/app/views/layouts/admin.html.haml +++ b/app/views/layouts/admin.html.haml @@ -1,6 +1,5 @@ -!!! 5 -%html{ lang: "en"} - = render "layouts/head", title: "Admin area" - %body{class: "#{app_theme} admin", :'data-page' => body_data_page} - = render "layouts/head_panel", title: link_to("Admin area", admin_root_path) - = render 'layouts/page', sidebar: 'layouts/nav/admin' +- page_title "Admin area" +- header_title "Admin area", admin_root_path +- sidebar "admin" + += render template: "layouts/application" diff --git a/app/views/layouts/application.html.haml b/app/views/layouts/application.html.haml index 6bd8ac4adb..a97feeb1ec 100644 --- a/app/views/layouts/application.html.haml +++ b/app/views/layouts/application.html.haml @@ -1,6 +1,10 @@ !!! 5 %html{ lang: "en"} - = render "layouts/head", title: "Dashboard" - %body{class: "#{app_theme} application", :'data-page' => body_data_page } - = render "layouts/head_panel", title: link_to("Dashboard", root_path) - = render 'layouts/page', sidebar: 'layouts/nav/dashboard' + = render "layouts/head" + %body{class: "#{app_theme}", :'data-page' => body_data_page} + - if current_user + = render "layouts/head_panel", title: header_title + - else + = render "layouts/public_head_panel", title: header_title + + = render 'layouts/page', sidebar: sidebar diff --git a/app/views/layouts/dashboard.html.haml b/app/views/layouts/dashboard.html.haml new file mode 100644 index 0000000000..c72eca10bf --- /dev/null +++ b/app/views/layouts/dashboard.html.haml @@ -0,0 +1,5 @@ +- page_title "Dashboard" +- header_title "Dashboard", root_path +- sidebar "dashboard" + += render template: "layouts/application" diff --git a/app/views/layouts/errors.html.haml b/app/views/layouts/errors.html.haml index e51fd4cb82..aa0f3f0a81 100644 --- a/app/views/layouts/errors.html.haml +++ b/app/views/layouts/errors.html.haml @@ -1,6 +1,6 @@ !!! 5 %html{ lang: "en"} - = render "layouts/head", title: "Error" + = render "layouts/head" %body{class: "#{app_theme} application"} = render "layouts/head_panel", title: "" if current_user .container.navless-container diff --git a/app/views/layouts/explore.html.haml b/app/views/layouts/explore.html.haml index ca79382324..56bb92a536 100644 --- a/app/views/layouts/explore.html.haml +++ b/app/views/layouts/explore.html.haml @@ -1,12 +1,5 @@ -- page_title = 'Explore GitLab' -!!! 5 -%html{ lang: "en"} - = render "layouts/head", title: page_title - %body{class: "#{app_theme} application", :'data-page' => body_data_page} - = render "layouts/broadcast" - - if current_user - = render "layouts/head_panel", title: link_to(page_title, explore_root_path) - - else - = render "layouts/public_head_panel", title: link_to(page_title, explore_root_path) +- page_title "Explore" +- header_title "Explore GitLab", explore_root_path +- sidebar "explore" - = render 'layouts/page', sidebar: 'layouts/nav/explore' += render template: "layouts/application" diff --git a/app/views/layouts/group.html.haml b/app/views/layouts/group.html.haml index f4a6bee15f..5edc03129d 100644 --- a/app/views/layouts/group.html.haml +++ b/app/views/layouts/group.html.haml @@ -1,6 +1,5 @@ -!!! 5 -%html{ lang: "en"} - = render "layouts/head", title: group_head_title - %body{class: "#{app_theme} application", :'data-page' => body_data_page} - = render "layouts/head_panel", title: link_to(@group.name, group_path(@group)) - = render 'layouts/page', sidebar: 'layouts/nav/group' +- page_title @group.name +- header_title @group.name, group_path(@group) +- sidebar "group" + += render template: "layouts/application" diff --git a/app/views/layouts/help.html.haml b/app/views/layouts/help.html.haml new file mode 100644 index 0000000000..224b24befb --- /dev/null +++ b/app/views/layouts/help.html.haml @@ -0,0 +1,4 @@ +- page_title "Help" +- header_title "Help", help_path + += render template: "layouts/application" diff --git a/app/views/layouts/nav/_group.html.haml b/app/views/layouts/nav/_group.html.haml index 74a8526dbd..babd984083 100644 --- a/app/views/layouts/nav/_group.html.haml +++ b/app/views/layouts/nav/_group.html.haml @@ -39,4 +39,30 @@ = icon ('angle-down fw') - if group_settings_page? - = render 'groups/settings_nav' + %ul.sidebar-subnav + = nav_link(path: 'groups#edit') do + = link_to edit_group_path(@group), title: 'Group', data: {placement: 'right'} do + = icon('pencil-square-o') + %span + Group + = nav_link(path: 'groups#projects') do + = link_to projects_group_path(@group), title: 'Projects', data: {placement: 'right'} do + = icon('folder') + %span + Projects + - if ldap_enabled? + = nav_link(controller: :ldap_group_links) do + = link_to group_ldap_group_links_path(@group) do + %i.fa.fa-exchange + %span + LDAP Groups + = nav_link(controller: :hooks) do + = link_to group_hooks_path(@group) do + %i.fa.fa-link + %span + Web Hooks + = nav_link(controller: :audit_events) do + = link_to group_audit_events_path(@group) do + %i.fa.fa-file-text-o + %span + Audit Events diff --git a/app/views/layouts/nav/_project.html.haml b/app/views/layouts/nav/_project.html.haml index 01b3d70194..172f5197b2 100644 --- a/app/views/layouts/nav/_project.html.haml +++ b/app/views/layouts/nav/_project.html.haml @@ -1,97 +1,85 @@ %ul.project-navigation.nav.nav-sidebar - - if @project_settings_nav - = nav_link do - = link_to project_path(@project), title: 'Back to project', data: {placement: 'right'} do - = icon('caret-square-o-left fw') + = nav_link(path: 'projects#show', html_options: {class: 'home'}) do + = link_to project_path(@project), title: 'Project', class: 'shortcuts-project', data: {placement: 'right'} do + = icon('dashboard fw') + %span + Project + - if project_nav_tab? :files + = nav_link(controller: %w(tree blob blame edit_tree new_tree)) do + = link_to namespace_project_tree_path(@project.namespace, @project, @ref || @repository.root_ref), title: 'Files', class: 'shortcuts-tree', data: {placement: 'right'} do + = icon('files-o fw') %span - Back to project + Files - %li.separate-item - - = render 'projects/settings_nav' - - - else - = nav_link(path: 'projects#show', html_options: {class: 'home'}) do - = link_to project_path(@project), title: 'Project', class: 'shortcuts-project', data: {placement: 'right'} do - = icon('dashboard fw') + - if project_nav_tab? :commits + = nav_link(controller: %w(commit commits compare repositories tags branches)) do + = link_to namespace_project_commits_path(@project.namespace, @project, @ref || @repository.root_ref), title: 'Commits', class: 'shortcuts-commits', data: {placement: 'right'} do + = icon('history fw') %span - Project - - if project_nav_tab? :files - = nav_link(controller: %w(tree blob blame edit_tree new_tree)) do - = link_to namespace_project_tree_path(@project.namespace, @project, @ref || @repository.root_ref), title: 'Files', class: 'shortcuts-tree', data: {placement: 'right'} do - = icon('files-o fw') - %span - Files + Commits - - if project_nav_tab? :commits - = nav_link(controller: %w(commit commits compare repositories tags branches)) do - = link_to namespace_project_commits_path(@project.namespace, @project, @ref || @repository.root_ref), title: 'Commits', class: 'shortcuts-commits', data: {placement: 'right'} do - = icon('history fw') - %span - Commits + - if project_nav_tab? :network + = nav_link(controller: %w(network)) do + = link_to namespace_project_network_path(@project.namespace, @project, @ref || @repository.root_ref), title: 'Network', class: 'shortcuts-network', data: {placement: 'right'} do + = icon('code-fork fw') + %span + Network - - if project_nav_tab? :network - = nav_link(controller: %w(network)) do - = link_to namespace_project_network_path(@project.namespace, @project, @ref || @repository.root_ref), title: 'Network', class: 'shortcuts-network', data: {placement: 'right'} do - = icon('code-fork fw') - %span - Network + - if project_nav_tab? :graphs + = nav_link(controller: %w(graphs)) do + = link_to namespace_project_graph_path(@project.namespace, @project, @ref || @repository.root_ref), title: 'Graphs', class: 'shortcuts-graphs', data: {placement: 'right'} do + = icon('area-chart fw') + %span + Graphs - - if project_nav_tab? :graphs - = nav_link(controller: %w(graphs)) do - = link_to namespace_project_graph_path(@project.namespace, @project, @ref || @repository.root_ref), title: 'Graphs', class: 'shortcuts-graphs', data: {placement: 'right'} do - = icon('area-chart fw') - %span - Graphs + - if project_nav_tab? :milestones + = nav_link(controller: :milestones) do + = link_to namespace_project_milestones_path(@project.namespace, @project), title: 'Milestones', data: {placement: 'right'} do + = icon('clock-o fw') + %span + Milestones - - if project_nav_tab? :milestones - = nav_link(controller: :milestones) do - = link_to namespace_project_milestones_path(@project.namespace, @project), title: 'Milestones', data: {placement: 'right'} do - = icon('clock-o fw') - %span - Milestones + - if project_nav_tab? :issues + = nav_link(controller: :issues) do + = link_to url_for_project_issues(@project, only_path: true), title: 'Issues', class: 'shortcuts-issues', data: {placement: 'right'} do + = icon('exclamation-circle fw') + %span + Issues + - if @project.default_issues_tracker? + %span.count.issue_counter= @project.issues.opened.count - - if project_nav_tab? :issues - = nav_link(controller: :issues) do - = link_to url_for_project_issues(@project, only_path: true), title: 'Issues', class: 'shortcuts-issues', data: {placement: 'right'} do - = icon('exclamation-circle fw') - %span - Issues - - if @project.default_issues_tracker? - %span.count.issue_counter= @project.issues.opened.count + - if project_nav_tab? :merge_requests + = nav_link(controller: :merge_requests) do + = link_to namespace_project_merge_requests_path(@project.namespace, @project), title: 'Merge Requests', class: 'shortcuts-merge_requests', data: {placement: 'right'} do + = icon('tasks fw') + %span + Merge Requests + %span.count.merge_counter= @project.merge_requests.opened.count - - if project_nav_tab? :merge_requests - = nav_link(controller: :merge_requests) do - = link_to namespace_project_merge_requests_path(@project.namespace, @project), title: 'Merge Requests', class: 'shortcuts-merge_requests', data: {placement: 'right'} do - = icon('tasks fw') - %span - Merge Requests - %span.count.merge_counter= @project.merge_requests.opened.count + - if project_nav_tab? :labels + = nav_link(controller: :labels) do + = link_to namespace_project_labels_path(@project.namespace, @project), title: 'Labels', data: {placement: 'right'} do + = icon('tags fw') + %span + Labels - - if project_nav_tab? :labels - = nav_link(controller: :labels) do - = link_to namespace_project_labels_path(@project.namespace, @project), title: 'Labels', data: {placement: 'right'} do - = icon('tags fw') - %span - Labels + - if project_nav_tab? :wiki + = nav_link(controller: :wikis) do + = link_to get_project_wiki_path(@project), title: 'Wiki', class: 'shortcuts-wiki', data: {placement: 'right'} do + = icon('book fw') + %span + Wiki - - if project_nav_tab? :wiki - = nav_link(controller: :wikis) do - = link_to get_project_wiki_path(@project), title: 'Wiki', class: 'shortcuts-wiki', data: {placement: 'right'} do - = icon('book fw') - %span - Wiki + - if project_nav_tab? :snippets + = nav_link(controller: :snippets) do + = link_to namespace_project_snippets_path(@project.namespace, @project), title: 'Snippets', class: 'shortcuts-snippets', data: {placement: 'right'} do + = icon('file-text-o fw') + %span + Snippets - - if project_nav_tab? :snippets - = nav_link(controller: :snippets) do - = link_to namespace_project_snippets_path(@project.namespace, @project), title: 'Snippets', class: 'shortcuts-snippets', data: {placement: 'right'} do - = icon('file-text-o fw') - %span - Snippets - - - if project_nav_tab? :settings - = nav_link(html_options: {class: "#{project_tab_class} separate-item"}) do - = link_to edit_project_path(@project), title: 'Settings', class: 'stat-tab tab no-highlight', data: {placement: 'right'} do - = icon('cogs fw') - %span - Settings + - if project_nav_tab? :settings + = nav_link(html_options: {class: "#{project_tab_class} separate-item"}) do + = link_to edit_project_path(@project), title: 'Settings', class: 'stat-tab tab no-highlight', data: {placement: 'right'} do + = icon('cogs fw') + %span + Settings diff --git a/app/views/layouts/nav/_project_settings.html.haml b/app/views/layouts/nav/_project_settings.html.haml new file mode 100644 index 0000000000..67e5e49b15 --- /dev/null +++ b/app/views/layouts/nav/_project_settings.html.haml @@ -0,0 +1,55 @@ +%ul.project-navigation.nav.nav-sidebar + = nav_link do + = link_to project_path(@project), title: 'Back to project', data: {placement: 'right'} do + = icon('caret-square-o-left fw') + %span + Back to project + + %li.separate-item + + %ul.project-settings-nav.sidebar-subnav + = nav_link(path: 'projects#edit') do + = link_to edit_project_path(@project), title: 'Project', class: 'stat-tab tab', data: {placement: 'right'} do + = icon('pencil-square-o') + %span + Project + = nav_link(controller: [:project_members, :teams]) do + = link_to namespace_project_project_members_path(@project.namespace, @project), title: 'Members', class: 'team-tab tab', data: {placement: 'right'} do + = icon('users') + %span + Members + = nav_link(controller: :group_links) do + = link_to namespace_project_group_links_path(@project.namespace, @project) do + %i.fa.fa-share-square-o + %span + Groups + = nav_link(controller: :deploy_keys) do + = link_to namespace_project_deploy_keys_path(@project.namespace, @project), title: 'Deploy Keys', data: {placement: 'right'} do + = icon('key') + %span + Deploy Keys + = nav_link(controller: :hooks) do + = link_to namespace_project_hooks_path(@project.namespace, @project), title: 'Web Hooks', data: {placement: 'right'} do + = icon('link') + %span + Web Hooks + = nav_link(controller: :git_hooks) do + = link_to namespace_project_git_hooks_path(@project.namespace, @project) do + %i.fa.fa-git-square + %span + Git Hooks + = nav_link(controller: :services) do + = link_to namespace_project_services_path(@project.namespace, @project), title: 'Services', data: {placement: 'right'} do + = icon('cogs') + %span + Services + = nav_link(controller: :protected_branches) do + = link_to namespace_project_protected_branches_path(@project.namespace, @project), title: 'Protected Branches', data: {placement: 'right'} do + = icon('lock') + %span + Protected branches + = nav_link(controller: :audit_events) do + = link_to namespace_project_audit_events_path(@project.namespace, @project) do + %i.fa.fa-file-text-o + %span + Audit Events diff --git a/app/views/layouts/nav/_snippets.html.haml b/app/views/layouts/nav/_snippets.html.haml index 0de3a9e5bb..458b76a2c9 100644 --- a/app/views/layouts/nav/_snippets.html.haml +++ b/app/views/layouts/nav/_snippets.html.haml @@ -1,9 +1,10 @@ %ul.nav.nav-sidebar - = nav_link(path: user_snippets_path(current_user), html_options: {class: 'home'}) do - = link_to user_snippets_path(current_user), title: 'Your snippets', data: {placement: 'right'} do - = icon('dashboard fw') - %span - Your Snippets + - if current_user + = nav_link(path: user_snippets_path(current_user), html_options: {class: 'home'}) do + = link_to user_snippets_path(current_user), title: 'Your snippets', data: {placement: 'right'} do + = icon('dashboard fw') + %span + Your Snippets = nav_link(path: snippets_path) do = link_to snippets_path, title: 'Discover snippets', data: {placement: 'right'} do = icon('globe fw') diff --git a/app/views/layouts/navless.html.haml b/app/views/layouts/navless.html.haml deleted file mode 100644 index 10a0fcea2f..0000000000 --- a/app/views/layouts/navless.html.haml +++ /dev/null @@ -1,7 +0,0 @@ -!!! 5 -%html{ lang: "en"} - = render "layouts/head", title: @title - %body{class: "#{app_theme} application", :'data-page' => body_data_page} - = render "layouts/broadcast" - = render "layouts/head_panel", title: defined?(@title_url) ? link_to(@title, @title_url) : @title - = render 'layouts/page' diff --git a/app/views/layouts/profile.html.haml b/app/views/layouts/profile.html.haml index 2b5be7fc37..9799b4cc4d 100644 --- a/app/views/layouts/profile.html.haml +++ b/app/views/layouts/profile.html.haml @@ -1,6 +1,5 @@ -!!! 5 -%html{ lang: "en"} - = render "layouts/head", title: "Profile" - %body{class: "#{app_theme} profile", :'data-page' => body_data_page} - = render "layouts/head_panel", title: link_to("Profile", profile_path) - = render 'layouts/page', sidebar: 'layouts/nav/profile' +- page_title "Profile" +- header_title "Profile", profile_path +- sidebar "profile" + += render template: "layouts/application" diff --git a/app/views/layouts/project.html.haml b/app/views/layouts/project.html.haml new file mode 100644 index 0000000000..4aeb9d397d --- /dev/null +++ b/app/views/layouts/project.html.haml @@ -0,0 +1,8 @@ +- page_title @project.name_with_namespace +- header_title project_title(@project) +- sidebar "project" unless sidebar + +- content_for :embedded_scripts do + = render "layouts/init_auto_complete" if current_user + += render template: "layouts/application" diff --git a/app/views/layouts/project_settings.html.haml b/app/views/layouts/project_settings.html.haml index 0a0039dec1..4340166833 100644 --- a/app/views/layouts/project_settings.html.haml +++ b/app/views/layouts/project_settings.html.haml @@ -1,8 +1,4 @@ -!!! 5 -%html{ lang: "en"} - = render "layouts/head", title: @project.name_with_namespace - %body{class: "#{app_theme} project", :'data-page' => body_data_page, :'data-project-id' => @project.id } - = render "layouts/head_panel", title: project_title(@project) - = render "layouts/init_auto_complete" - - @project_settings_nav = true - = render 'layouts/page', sidebar: 'layouts/nav/project' +- page_title "Settings" +- sidebar "project_settings" + += render template: "layouts/project" diff --git a/app/views/layouts/projects.html.haml b/app/views/layouts/projects.html.haml deleted file mode 100644 index dde0964f47..0000000000 --- a/app/views/layouts/projects.html.haml +++ /dev/null @@ -1,7 +0,0 @@ -!!! 5 -%html{ lang: "en"} - = render "layouts/head", title: project_head_title - %body{class: "#{app_theme} project", :'data-page' => body_data_page, :'data-project-id' => @project.id } - = render "layouts/head_panel", title: project_title(@project) - = render "layouts/init_auto_complete" - = render 'layouts/page', sidebar: 'layouts/nav/project' diff --git a/app/views/layouts/public_group.html.haml b/app/views/layouts/public_group.html.haml deleted file mode 100644 index b9b1d03e08..0000000000 --- a/app/views/layouts/public_group.html.haml +++ /dev/null @@ -1,6 +0,0 @@ -!!! 5 -%html{ lang: "en"} - = render "layouts/head", title: group_head_title - %body{class: "#{app_theme} application", :'data-page' => body_data_page} - = render "layouts/public_head_panel", title: link_to(@group.name, group_path(@group)) - = render 'layouts/page', sidebar: 'layouts/nav/group' diff --git a/app/views/layouts/public_projects.html.haml b/app/views/layouts/public_projects.html.haml deleted file mode 100644 index 04fa7c84e7..0000000000 --- a/app/views/layouts/public_projects.html.haml +++ /dev/null @@ -1,6 +0,0 @@ -!!! 5 -%html{ lang: "en"} - = render "layouts/head", title: @project.name_with_namespace - %body{class: "#{app_theme} application", :'data-page' => body_data_page} - = render "layouts/public_head_panel", title: project_title(@project) - = render 'layouts/page', sidebar: 'layouts/nav/project' diff --git a/app/views/layouts/public_users.html.haml b/app/views/layouts/public_users.html.haml deleted file mode 100644 index 71c16bd168..0000000000 --- a/app/views/layouts/public_users.html.haml +++ /dev/null @@ -1,6 +0,0 @@ -!!! 5 -%html{ lang: "en"} - = render "layouts/head", title: @title - %body{class: "#{app_theme} application", :'data-page' => body_data_page} - = render "layouts/public_head_panel", title: defined?(@title_url) ? link_to(@title, @title_url) : @title - = render 'layouts/page' diff --git a/app/views/layouts/search.html.haml b/app/views/layouts/search.html.haml index f9d8db06e1..fd4c7ad21a 100644 --- a/app/views/layouts/search.html.haml +++ b/app/views/layouts/search.html.haml @@ -1,10 +1,4 @@ -!!! 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 +- page_title "Search" +- header_title "Search", search_path + += render template: "layouts/application" diff --git a/app/views/layouts/snippets.html.haml b/app/views/layouts/snippets.html.haml index fbd29eb23a..9b0f40073a 100644 --- a/app/views/layouts/snippets.html.haml +++ b/app/views/layouts/snippets.html.haml @@ -1,6 +1,5 @@ -!!! 5 -%html{ lang: "en"} - = render "layouts/head", title: "Dashboard" - %body{class: "#{app_theme} application", :'data-page' => body_data_page } - = render "layouts/head_panel", title: link_to("Snippets", snippets_path) - = render 'layouts/page', sidebar: 'layouts/nav/snippets' +- page_title 'Snippets' +- header_title 'Snippets', snippets_path +- sidebar "snippets" + += render template: "layouts/application" diff --git a/app/views/profiles/accounts/show.html.haml b/app/views/profiles/accounts/show.html.haml index 5bffb4acc1..1c3a3d68ac 100644 --- a/app/views/profiles/accounts/show.html.haml +++ b/app/views/profiles/accounts/show.html.haml @@ -1,3 +1,4 @@ +- page_title "Account" - if current_user.ldap_user? .alert.alert-info Some options are unavailable for LDAP accounts diff --git a/app/views/profiles/applications.html.haml b/app/views/profiles/applications.html.haml index 97e98948f3..c4f6f59624 100644 --- a/app/views/profiles/applications.html.haml +++ b/app/views/profiles/applications.html.haml @@ -1,3 +1,4 @@ +- page_title "Applications" %h3.page-title Application Settings %p.light diff --git a/app/views/profiles/design.html.haml b/app/views/profiles/design.html.haml index 646576c316..af284f6040 100644 --- a/app/views/profiles/design.html.haml +++ b/app/views/profiles/design.html.haml @@ -1,3 +1,4 @@ +- page_title "Design" %h3.page-title Design Settings %p.light diff --git a/app/views/profiles/emails/index.html.haml b/app/views/profiles/emails/index.html.haml index 09f290429e..2c0d0e10a4 100644 --- a/app/views/profiles/emails/index.html.haml +++ b/app/views/profiles/emails/index.html.haml @@ -1,14 +1,19 @@ +- page_title "Emails" %h3.page-title Email Settings %p.light Your %b Primary Email will be used for avatar detection and web based operations, such as edits and merges. - %br +%p.light Your %b Notification Email will be used for account notifications. - %br +%p.light + Your + %b Public Email + will be displayed on your public profile. +%p.light All email addresses will be used to identify your commits. %hr @@ -20,13 +25,17 @@ %li %strong= @primary %span.label.label-success Primary Email - - if @primary === @public_email + - if @primary === current_user.public_email %span.label.label-info Public Email + - if @primary === current_user.notification_email + %span.label.label-info Notification Email - @emails.each do |email| %li %strong= email.email - - if email.email === @public_email + - if email.email === current_user.public_email %span.label.label-info Public Email + - if email.email === current_user.notification_email + %span.label.label-info Notification Email %span.cgray added #{time_ago_with_tooltip(email.created_at)} = link_to 'Remove', profile_email_path(email), data: { confirm: 'Are you sure?'}, method: :delete, class: 'btn btn-sm btn-remove pull-right' diff --git a/app/views/profiles/history.html.haml b/app/views/profiles/history.html.haml index b1ab433f48..b414fb69f4 100644 --- a/app/views/profiles/history.html.haml +++ b/app/views/profiles/history.html.haml @@ -1,3 +1,4 @@ +- page_title "History" %h3.page-title Your Account History %p.light diff --git a/app/views/profiles/keys/index.html.haml b/app/views/profiles/keys/index.html.haml index 0904c50c88..e3af0d4e18 100644 --- a/app/views/profiles/keys/index.html.haml +++ b/app/views/profiles/keys/index.html.haml @@ -1,3 +1,4 @@ +- page_title "SSH Keys" %h3.page-title SSH Keys Settings .pull-right diff --git a/app/views/profiles/keys/new.html.haml b/app/views/profiles/keys/new.html.haml index ccec716d0c..2bf207a322 100644 --- a/app/views/profiles/keys/new.html.haml +++ b/app/views/profiles/keys/new.html.haml @@ -1,3 +1,4 @@ +- page_title "Add SSH Keys" %h3.page-title Add an SSH Key %p.light Paste your public key here. Read more about how to generate a key on #{link_to "the SSH help page", help_page_path("ssh", "README")}. diff --git a/app/views/profiles/keys/show.html.haml b/app/views/profiles/keys/show.html.haml index cfd5329896..89f6f01581 100644 --- a/app/views/profiles/keys/show.html.haml +++ b/app/views/profiles/keys/show.html.haml @@ -1 +1,2 @@ +- page_title @key.title, "SSH Keys" = render "key_details" diff --git a/app/views/profiles/notifications/show.html.haml b/app/views/profiles/notifications/show.html.haml index 273e72f8a4..a74d97dac3 100644 --- a/app/views/profiles/notifications/show.html.haml +++ b/app/views/profiles/notifications/show.html.haml @@ -1,3 +1,4 @@ +- page_title "Notifications" %h3.page-title Notifications Settings %p.light diff --git a/app/views/profiles/passwords/edit.html.haml b/app/views/profiles/passwords/edit.html.haml index 4b04b113e8..21dabbdfe2 100644 --- a/app/views/profiles/passwords/edit.html.haml +++ b/app/views/profiles/passwords/edit.html.haml @@ -1,3 +1,4 @@ +- page_title "Password" %h3.page-title Password Settings %p.light - if @user.password_automatically_set? diff --git a/app/views/profiles/passwords/new.html.haml b/app/views/profiles/passwords/new.html.haml index 8bed6e0dbe..9c6204963e 100644 --- a/app/views/profiles/passwords/new.html.haml +++ b/app/views/profiles/passwords/new.html.haml @@ -1,3 +1,5 @@ +- page_title "New Password" +- header_title "New Password" %h3.page-title Setup new password %hr = form_for @user, url: profile_password_path, method: :post, html: { class: 'form-horizontal '} do |f| diff --git a/app/views/profiles/show.html.haml b/app/views/profiles/show.html.haml index 6c745e69e4..29c3090511 100644 --- a/app/views/profiles/show.html.haml +++ b/app/views/profiles/show.html.haml @@ -1,3 +1,4 @@ +- page_title "Settings" %h3.page-title Profile Settings %p.light diff --git a/app/views/projects/_settings_nav.html.haml b/app/views/projects/_settings_nav.html.haml deleted file mode 100644 index 299c8ad713..0000000000 --- a/app/views/projects/_settings_nav.html.haml +++ /dev/null @@ -1,46 +0,0 @@ -%ul.project-settings-nav.sidebar-subnav - = nav_link(path: 'projects#edit') do - = link_to edit_project_path(@project), title: 'Project', class: 'stat-tab tab', data: {placement: 'right'} do - = icon('pencil-square-o') - %span - Project - = nav_link(controller: [:project_members, :teams]) do - = link_to namespace_project_project_members_path(@project.namespace, @project), title: 'Members', class: 'team-tab tab', data: {placement: 'right'} do - = icon('users') - %span - Members - = nav_link(controller: :group_links) do - = link_to namespace_project_group_links_path(@project.namespace, @project) do - %i.fa.fa-share-square-o - %span - Groups - = nav_link(controller: :deploy_keys) do - = link_to namespace_project_deploy_keys_path(@project.namespace, @project), title: 'Deploy Keys', data: {placement: 'right'} do - = icon('key') - %span - Deploy Keys - = nav_link(controller: :hooks) do - = link_to namespace_project_hooks_path(@project.namespace, @project), title: 'Web Hooks', data: {placement: 'right'} do - = icon('link') - %span - Web Hooks - = nav_link(controller: :git_hooks) do - = link_to namespace_project_git_hooks_path(@project.namespace, @project) do - %i.fa.fa-git-square - %span - Git Hooks - = nav_link(controller: :services) do - = link_to namespace_project_services_path(@project.namespace, @project), title: 'Services', data: {placement: 'right'} do - = icon('cogs') - %span - Services - = nav_link(controller: :protected_branches) do - = link_to namespace_project_protected_branches_path(@project.namespace, @project), title: 'Protected Branches', data: {placement: 'right'} do - = icon('lock') - %span - Protected branches - = nav_link(controller: :audit_events) do - = link_to namespace_project_audit_events_path(@project.namespace, @project) do - %i.fa.fa-file-text-o - %span - Audit Events diff --git a/app/views/projects/blame/show.html.haml b/app/views/projects/blame/show.html.haml index 89dd68d647..462f5b7afb 100644 --- a/app/views/projects/blame/show.html.haml +++ b/app/views/projects/blame/show.html.haml @@ -1,3 +1,4 @@ +- page_title "Blame", @blob.path, @ref %h3.page-title Blame view #tree-holder.tree-holder diff --git a/app/views/projects/blob/edit.html.haml b/app/views/projects/blob/edit.html.haml index 1f61a0b940..e78181f880 100644 --- a/app/views/projects/blob/edit.html.haml +++ b/app/views/projects/blob/edit.html.haml @@ -1,3 +1,4 @@ +- page_title "Edit", @blob.path, @ref .file-editor %ul.nav.nav-tabs.js-edit-mode %li.active diff --git a/app/views/projects/blob/new.html.haml b/app/views/projects/blob/new.html.haml index d78a01f642..9b1d03b820 100644 --- a/app/views/projects/blob/new.html.haml +++ b/app/views/projects/blob/new.html.haml @@ -1,3 +1,4 @@ +- page_title "New File", @ref %h3.page-title New file .file-editor = form_tag(namespace_project_create_blob_path(@project.namespace, @project, @id), method: :post, class: 'form-horizontal form-new-file') do diff --git a/app/views/projects/blob/show.html.haml b/app/views/projects/blob/show.html.haml index 69167654c3..a1d464bac5 100644 --- a/app/views/projects/blob/show.html.haml +++ b/app/views/projects/blob/show.html.haml @@ -1,3 +1,4 @@ +- page_title @blob.path, @ref %div.tree-ref-holder = render 'shared/ref_switcher', destination: 'blob', path: @path diff --git a/app/views/projects/branches/index.html.haml b/app/views/projects/branches/index.html.haml index a313ffcf27..80acc93790 100644 --- a/app/views/projects/branches/index.html.haml +++ b/app/views/projects/branches/index.html.haml @@ -1,3 +1,4 @@ +- page_title "Branches" = render "projects/commits/head" %h3.page-title Branches diff --git a/app/views/projects/branches/new.html.haml b/app/views/projects/branches/new.html.haml index e5fcb98c68..cac5dc91af 100644 --- a/app/views/projects/branches/new.html.haml +++ b/app/views/projects/branches/new.html.haml @@ -1,3 +1,4 @@ +- page_title "New Branch" - if @error .alert.alert-danger %button{ type: "button", class: "close", "data-dismiss" => "alert"} × diff --git a/app/views/projects/commit/show.html.haml b/app/views/projects/commit/show.html.haml index fc721067ed..fc91f71e8d 100644 --- a/app/views/projects/commit/show.html.haml +++ b/app/views/projects/commit/show.html.haml @@ -1,3 +1,4 @@ +- page_title "#{@commit.title} (#{@commit.short_id})", "Commits" = render "commit_box" = render "projects/diffs/diffs", diffs: @diffs, project: @project = render "projects/notes/notes_with_form" diff --git a/app/views/projects/commits/show.html.haml b/app/views/projects/commits/show.html.haml index fb1012deb7..c8531b090a 100644 --- a/app/views/projects/commits/show.html.haml +++ b/app/views/projects/commits/show.html.haml @@ -1,3 +1,4 @@ +- page_title "Commits", @ref = content_for :meta_tags do - if current_user = auto_discovery_link_tag(:atom, namespace_project_commits_url(@project.namespace, @project, @ref, format: :atom, private_token: current_user.private_token), title: "#{@project.name}:#{@ref} commits") diff --git a/app/views/projects/compare/index.html.haml b/app/views/projects/compare/index.html.haml index 4745bfbeaa..d1e579a2ed 100644 --- a/app/views/projects/compare/index.html.haml +++ b/app/views/projects/compare/index.html.haml @@ -1,3 +1,4 @@ +- page_title "Compare" = render "projects/commits/head" %h3.page-title diff --git a/app/views/projects/compare/show.html.haml b/app/views/projects/compare/show.html.haml index 214b5bd337..3670dd5c13 100644 --- a/app/views/projects/compare/show.html.haml +++ b/app/views/projects/compare/show.html.haml @@ -1,3 +1,4 @@ +- page_title "#{params[:from]}...#{params[:to]}" = render "projects/commits/head" %h3.page-title diff --git a/app/views/projects/deploy_keys/index.html.haml b/app/views/projects/deploy_keys/index.html.haml index 472a13a852..2e9c5dc08c 100644 --- a/app/views/projects/deploy_keys/index.html.haml +++ b/app/views/projects/deploy_keys/index.html.haml @@ -1,3 +1,4 @@ +- page_title "Deploy Keys" %h3.page-title Deploy keys allow read-only access to the repository diff --git a/app/views/projects/deploy_keys/new.html.haml b/app/views/projects/deploy_keys/new.html.haml index 186d6b5897..01c810aee1 100644 --- a/app/views/projects/deploy_keys/new.html.haml +++ b/app/views/projects/deploy_keys/new.html.haml @@ -1,3 +1,4 @@ +- page_title "New Deploy Key" %h3.page-title New Deploy key %hr diff --git a/app/views/projects/deploy_keys/show.html.haml b/app/views/projects/deploy_keys/show.html.haml index 405b5bcd0d..7d44652af7 100644 --- a/app/views/projects/deploy_keys/show.html.haml +++ b/app/views/projects/deploy_keys/show.html.haml @@ -1,3 +1,4 @@ +- page_title @key.title, "Deploy Keys" %h3.page-title Deploy key: = @key.title diff --git a/app/views/projects/diffs/_file.html.haml b/app/views/projects/diffs/_file.html.haml index 672a663532..d4b019780f 100644 --- a/app/views/projects/diffs/_file.html.haml +++ b/app/views/projects/diffs/_file.html.haml @@ -11,7 +11,7 @@ = view_file_btn(@commit.parent_id, diff_file, project) - elsif diff_file.diff.submodule? - submodule_item = project.repository.blob_at(@commit.id, diff_file.file_path) - = submodule_link(submodule_item, @commit.id) + = submodule_link(submodule_item, @commit.id, project.repository) - else %span - if diff_file.renamed_file diff --git a/app/views/projects/forks/error.html.haml b/app/views/projects/forks/error.html.haml index 8eb4f79597..3d0ab5b85d 100644 --- a/app/views/projects/forks/error.html.haml +++ b/app/views/projects/forks/error.html.haml @@ -1,3 +1,4 @@ +- page_title "Fork project" - if @forked_project && !@forked_project.saved? .alert.alert-danger.alert-block %h4 diff --git a/app/views/projects/forks/new.html.haml b/app/views/projects/forks/new.html.haml index 5a6c46f320..b7a2ed68e2 100644 --- a/app/views/projects/forks/new.html.haml +++ b/app/views/projects/forks/new.html.haml @@ -1,3 +1,4 @@ +- page_title "Fork project" %h3.page-title Fork project %p.lead Click to fork the project to a user or group diff --git a/app/views/projects/git_hooks/index.html.haml b/app/views/projects/git_hooks/index.html.haml index e4e6194217..03446506fc 100644 --- a/app/views/projects/git_hooks/index.html.haml +++ b/app/views/projects/git_hooks/index.html.haml @@ -1,3 +1,4 @@ +- page_title "Git Hooks" %h3.page-title Git hooks %p.light diff --git a/app/views/projects/graphs/commits.html.haml b/app/views/projects/graphs/commits.html.haml index 78b4c1923d..254a76e108 100644 --- a/app/views/projects/graphs/commits.html.haml +++ b/app/views/projects/graphs/commits.html.haml @@ -1,3 +1,4 @@ +- page_title "Commit statistics" = render 'head' %p.lead diff --git a/app/views/projects/graphs/show.html.haml b/app/views/projects/graphs/show.html.haml index e3d5094ddc..3a8dc89f84 100644 --- a/app/views/projects/graphs/show.html.haml +++ b/app/views/projects/graphs/show.html.haml @@ -1,3 +1,4 @@ +- page_title "Contributor statistics" = render 'head' .loading-graph .center diff --git a/app/views/projects/group_links/index.html.haml b/app/views/projects/group_links/index.html.haml index 0ec482700a..13f5fc141f 100644 --- a/app/views/projects/group_links/index.html.haml +++ b/app/views/projects/group_links/index.html.haml @@ -1,3 +1,4 @@ +- page_title "Groups" %h3.page_title Share project with other groups %p.light Projects can be stored in only one group at once. However you can share a project with other groups here. diff --git a/app/views/projects/hooks/index.html.haml b/app/views/projects/hooks/index.html.haml index bbaddba31b..808c03148f 100644 --- a/app/views/projects/hooks/index.html.haml +++ b/app/views/projects/hooks/index.html.haml @@ -1,3 +1,4 @@ +- page_title "Web Hooks" %h3.page-title Web hooks diff --git a/app/views/projects/imports/new.html.haml b/app/views/projects/imports/new.html.haml index 934b6b8c01..f8f2e192e2 100644 --- a/app/views/projects/imports/new.html.haml +++ b/app/views/projects/imports/new.html.haml @@ -1,3 +1,4 @@ +- page_title "Import repository" %h3.page-title - if @project.import_failed? Import failed. Retry? diff --git a/app/views/projects/imports/show.html.haml b/app/views/projects/imports/show.html.haml index 2d1fdafed2..39fe0fc1c4 100644 --- a/app/views/projects/imports/show.html.haml +++ b/app/views/projects/imports/show.html.haml @@ -1,3 +1,4 @@ +- page_title "Import in progress" .save-project-loader .center %h2 diff --git a/app/views/projects/issues/_discussion.html.haml b/app/views/projects/issues/_discussion.html.haml index 288b48f458..ceca265301 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/issues/edit.html.haml b/app/views/projects/issues/edit.html.haml index b1bc3ba0eb..53b6f0879c 100644 --- a/app/views/projects/issues/edit.html.haml +++ b/app/views/projects/issues/edit.html.haml @@ -1 +1,2 @@ +- page_title "Edit", "#{@issue.title} (##{@issue.iid})", "Issues" = render "form" diff --git a/app/views/projects/issues/index.html.haml b/app/views/projects/issues/index.html.haml index c2522816f3..709ea1f789 100644 --- a/app/views/projects/issues/index.html.haml +++ b/app/views/projects/issues/index.html.haml @@ -1,3 +1,4 @@ +- page_title "Issues" = content_for :meta_tags do - if current_user = auto_discovery_link_tag(:atom, namespace_project_issues_url(@project.namespace, @project, :atom, private_token: current_user.private_token), title: "#{@project.name} issues") diff --git a/app/views/projects/issues/new.html.haml b/app/views/projects/issues/new.html.haml index b1bc3ba0eb..da6edd5c2d 100644 --- a/app/views/projects/issues/new.html.haml +++ b/app/views/projects/issues/new.html.haml @@ -1 +1,2 @@ +- page_title "New Issue" = render "form" diff --git a/app/views/projects/issues/show.html.haml b/app/views/projects/issues/show.html.haml index bd28d8a1db..81478dfe56 100644 --- a/app/views/projects/issues/show.html.haml +++ b/app/views/projects/issues/show.html.haml @@ -1,3 +1,4 @@ +- page_title "#{@issue.title} (##{@issue.iid})", "Issues" .issue .issue-details %h4.page-title diff --git a/app/views/projects/labels/edit.html.haml b/app/views/projects/labels/edit.html.haml index e003d1dfe7..645402667f 100644 --- a/app/views/projects/labels/edit.html.haml +++ b/app/views/projects/labels/edit.html.haml @@ -1,3 +1,4 @@ +- page_title "Edit", @label.name, "Labels" %h3 Edit label %span.light #{@label.name} diff --git a/app/views/projects/labels/index.html.haml b/app/views/projects/labels/index.html.haml index 0700e72d39..7d19415a7f 100644 --- a/app/views/projects/labels/index.html.haml +++ b/app/views/projects/labels/index.html.haml @@ -1,3 +1,4 @@ +- page_title "Labels" - if can? current_user, :admin_label, @project = link_to new_namespace_project_label_path(@project.namespace, @project), class: "pull-right btn btn-new" do New label diff --git a/app/views/projects/labels/new.html.haml b/app/views/projects/labels/new.html.haml index 0683ed5d4f..b3ef17025c 100644 --- a/app/views/projects/labels/new.html.haml +++ b/app/views/projects/labels/new.html.haml @@ -1,3 +1,4 @@ +- page_title "New Label" %h3 New label .back-link = link_to namespace_project_labels_path(@project.namespace, @project) do diff --git a/app/views/projects/merge_requests/_discussion.html.haml b/app/views/projects/merge_requests/_discussion.html.haml index eb72eaabd8..9a2aa9c3de 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 cec02de84c..c2f5cdacae 100644 --- a/app/views/projects/merge_requests/_show.html.haml +++ b/app/views/projects/merge_requests/_show.html.haml @@ -1,3 +1,4 @@ +- page_title "#{@merge_request.title} (##{@merge_request.iid})", "Merge Requests" .merge-request{'data-url' => merge_request_path(@merge_request)} .merge-request-details = render "projects/merge_requests/show/mr_title" @@ -72,6 +73,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/edit.html.haml b/app/views/projects/merge_requests/edit.html.haml index 839c63986a..7e5cb07f24 100644 --- a/app/views/projects/merge_requests/edit.html.haml +++ b/app/views/projects/merge_requests/edit.html.haml @@ -1,3 +1,4 @@ +- page_title "Edit", "#{@merge_request.title} (##{@merge_request.iid})", "Merge Requests" %h3.page-title = "Edit merge request ##{@merge_request.iid}" %hr diff --git a/app/views/projects/merge_requests/index.html.haml b/app/views/projects/merge_requests/index.html.haml index d7992bdd19..ab845a7e71 100644 --- a/app/views/projects/merge_requests/index.html.haml +++ b/app/views/projects/merge_requests/index.html.haml @@ -1,3 +1,4 @@ +- page_title "Merge Requests" .append-bottom-10 .pull-right = render 'shared/issuable_search_form', path: namespace_project_merge_requests_path(@project.namespace, @project) diff --git a/app/views/projects/merge_requests/invalid.html.haml b/app/views/projects/merge_requests/invalid.html.haml index b9c466657d..15bd4e2faf 100644 --- a/app/views/projects/merge_requests/invalid.html.haml +++ b/app/views/projects/merge_requests/invalid.html.haml @@ -1,3 +1,4 @@ +- page_title "#{@merge_request.title} (##{@merge_request.iid})", "Merge Requests" .merge-request = render "projects/merge_requests/show/mr_title" = render "projects/merge_requests/show/mr_box" diff --git a/app/views/projects/merge_requests/new.html.haml b/app/views/projects/merge_requests/new.html.haml index 4756903d0e..b038a640f6 100644 --- a/app/views/projects/merge_requests/new.html.haml +++ b/app/views/projects/merge_requests/new.html.haml @@ -1,3 +1,4 @@ +- page_title "New Merge Request" - if @merge_request.can_be_created = render 'new_submit' - else 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 ae15eb902c..8461bda2b4 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 @@ -62,6 +64,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 Work In Progress. + + %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/milestones/edit.html.haml b/app/views/projects/milestones/edit.html.haml index b1bc3ba0eb..c09815a212 100644 --- a/app/views/projects/milestones/edit.html.haml +++ b/app/views/projects/milestones/edit.html.haml @@ -1 +1,2 @@ +- page_title "Edit", @milestone.title, "Milestones" = render "form" diff --git a/app/views/projects/milestones/index.html.haml b/app/views/projects/milestones/index.html.haml index d3eab8d6d7..995eecd783 100644 --- a/app/views/projects/milestones/index.html.haml +++ b/app/views/projects/milestones/index.html.haml @@ -1,3 +1,4 @@ +- page_title "Milestones" .pull-right - if can? current_user, :admin_milestone, @project = link_to new_namespace_project_milestone_path(@project.namespace, @project), class: "pull-right btn btn-new", title: "New Milestone" do diff --git a/app/views/projects/milestones/new.html.haml b/app/views/projects/milestones/new.html.haml index b1bc3ba0eb..47149dfea4 100644 --- a/app/views/projects/milestones/new.html.haml +++ b/app/views/projects/milestones/new.html.haml @@ -1 +1,2 @@ +- page_title "New Milestone" = render "form" diff --git a/app/views/projects/milestones/show.html.haml b/app/views/projects/milestones/show.html.haml index 25cc003096..bba2b8764a 100644 --- a/app/views/projects/milestones/show.html.haml +++ b/app/views/projects/milestones/show.html.haml @@ -1,3 +1,4 @@ +- page_title @milestone.title, "Milestones" %h4.page-title .issue-box{ class: issue_box_class(@milestone) } - if @milestone.closed? diff --git a/app/views/projects/network/show.html.haml b/app/views/projects/network/show.html.haml index c36bad1e94..c67a7d256a 100644 --- a/app/views/projects/network/show.html.haml +++ b/app/views/projects/network/show.html.haml @@ -1,3 +1,4 @@ +- page_title "Network", @ref = render "head" .project-network .controls diff --git a/app/views/projects/new.html.haml b/app/views/projects/new.html.haml index 47c69f89a9..e56d861513 100644 --- a/app/views/projects/new.html.haml +++ b/app/views/projects/new.html.haml @@ -1,3 +1,5 @@ +- page_title 'New Project' +- header_title 'New Project' .project-edit-container .project-edit-errors = render 'projects/errors' diff --git a/app/views/projects/project_members/import.html.haml b/app/views/projects/project_members/import.html.haml index 293754cd0c..6914543f6d 100644 --- a/app/views/projects/project_members/import.html.haml +++ b/app/views/projects/project_members/import.html.haml @@ -1,3 +1,4 @@ +- page_title "Import members" %h3.page-title Import members from another project %p.light diff --git a/app/views/projects/project_members/index.html.haml b/app/views/projects/project_members/index.html.haml index be4b94b54d..c619af0a8e 100644 --- a/app/views/projects/project_members/index.html.haml +++ b/app/views/projects/project_members/index.html.haml @@ -1,3 +1,4 @@ +- page_title "Members" %h3.page-title Users with access to this project diff --git a/app/views/projects/protected_branches/index.html.haml b/app/views/projects/protected_branches/index.html.haml index a3464c0e5e..52b3a50c1e 100644 --- a/app/views/projects/protected_branches/index.html.haml +++ b/app/views/projects/protected_branches/index.html.haml @@ -1,3 +1,4 @@ +- page_title "Protected branches" %h3.page-title Protected branches %p.light Keep stable branches secure and force developers to use Merge Requests %hr diff --git a/app/views/projects/services/_form.html.haml b/app/views/projects/services/_form.html.haml index 1b465e3add..e1823b5119 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/services/edit.html.haml b/app/views/projects/services/edit.html.haml index bcc5832792..50ed78286d 100644 --- a/app/views/projects/services/edit.html.haml +++ b/app/views/projects/services/edit.html.haml @@ -1 +1,2 @@ +- page_title @service.title, "Services" = render 'form' diff --git a/app/views/projects/services/index.html.haml b/app/views/projects/services/index.html.haml index 0d3ccb6bb8..1065def693 100644 --- a/app/views/projects/services/index.html.haml +++ b/app/views/projects/services/index.html.haml @@ -1,3 +1,4 @@ +- page_title "Services" %h3.page-title Project services %p.light Project services allow you to integrate GitLab with other applications diff --git a/app/views/projects/show.html.haml b/app/views/projects/show.html.haml index 1787caa243..cd18ae0c8d 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/projects/snippets/edit.html.haml b/app/views/projects/snippets/edit.html.haml index 7baddebde4..945f0084df 100644 --- a/app/views/projects/snippets/edit.html.haml +++ b/app/views/projects/snippets/edit.html.haml @@ -1,3 +1,4 @@ +- page_title "Edit", @snippet.title, "Snippets" %h3.page-title Edit snippet %hr diff --git a/app/views/projects/snippets/index.html.haml b/app/views/projects/snippets/index.html.haml index e2d8ec673a..da9401bd8c 100644 --- a/app/views/projects/snippets/index.html.haml +++ b/app/views/projects/snippets/index.html.haml @@ -1,3 +1,4 @@ +- page_title "Snippets" %h3.page-title Snippets - if can? current_user, :write_project_snippet, @project diff --git a/app/views/projects/snippets/new.html.haml b/app/views/projects/snippets/new.html.haml index 5efe662665..e38d95c45e 100644 --- a/app/views/projects/snippets/new.html.haml +++ b/app/views/projects/snippets/new.html.haml @@ -1,3 +1,4 @@ +- page_title "New Snippets" %h3.page-title New snippet %hr diff --git a/app/views/projects/snippets/show.html.haml b/app/views/projects/snippets/show.html.haml index d19689a105..5725d804df 100644 --- a/app/views/projects/snippets/show.html.haml +++ b/app/views/projects/snippets/show.html.haml @@ -1,3 +1,4 @@ +- page_title @snippet.title, "Snippets" %h3.page-title = @snippet.title diff --git a/app/views/projects/tags/index.html.haml b/app/views/projects/tags/index.html.haml index f1bc2bc9a2..d4652a47cb 100644 --- a/app/views/projects/tags/index.html.haml +++ b/app/views/projects/tags/index.html.haml @@ -1,3 +1,4 @@ +- page_title "Tags" = render "projects/commits/head" %h3.page-title diff --git a/app/views/projects/tags/new.html.haml b/app/views/projects/tags/new.html.haml index 655044438d..172fafdeef 100644 --- a/app/views/projects/tags/new.html.haml +++ b/app/views/projects/tags/new.html.haml @@ -1,3 +1,4 @@ +- page_title "New Tag" - if @error .alert.alert-danger %button{ type: "button", class: "close", "data-dismiss" => "alert"} × diff --git a/app/views/projects/tree/show.html.haml b/app/views/projects/tree/show.html.haml index a8a580944e..72916cad18 100644 --- a/app/views/projects/tree/show.html.haml +++ b/app/views/projects/tree/show.html.haml @@ -1,3 +1,4 @@ +- page_title @path.presence || "Files", @ref = content_for :meta_tags do - if current_user = auto_discovery_link_tag(:atom, namespace_project_commits_url(@project.namespace, @project, @ref, format: :atom, private_token: current_user.private_token), title: "#{@project.name}:#{@ref} commits") diff --git a/app/views/projects/wikis/edit.html.haml b/app/views/projects/wikis/edit.html.haml index 566850cb78..3f1dce1050 100644 --- a/app/views/projects/wikis/edit.html.haml +++ b/app/views/projects/wikis/edit.html.haml @@ -1,3 +1,4 @@ +- page_title "Edit", @page.title, "Wiki" = render 'nav' .pull-right = render 'main_links' diff --git a/app/views/projects/wikis/empty.html.haml b/app/views/projects/wikis/empty.html.haml index 48058124f9..ead9941240 100644 --- a/app/views/projects/wikis/empty.html.haml +++ b/app/views/projects/wikis/empty.html.haml @@ -1,3 +1,4 @@ +- page_title "Wiki" %h3.page-title Empty page %hr .error_message diff --git a/app/views/projects/wikis/git_access.html.haml b/app/views/projects/wikis/git_access.html.haml index 365edb524f..825f2a161c 100644 --- a/app/views/projects/wikis/git_access.html.haml +++ b/app/views/projects/wikis/git_access.html.haml @@ -1,3 +1,4 @@ +- page_title "Git Access", "Wiki" = render 'nav' .row .col-sm-6 diff --git a/app/views/projects/wikis/history.html.haml b/app/views/projects/wikis/history.html.haml index 91291f753f..673ec2d20e 100644 --- a/app/views/projects/wikis/history.html.haml +++ b/app/views/projects/wikis/history.html.haml @@ -1,3 +1,4 @@ +- page_title "History", @page.title, "Wiki" = render 'nav' %h3.page-title %span.light History for diff --git a/app/views/projects/wikis/pages.html.haml b/app/views/projects/wikis/pages.html.haml index ee233d9086..890ff1aed7 100644 --- a/app/views/projects/wikis/pages.html.haml +++ b/app/views/projects/wikis/pages.html.haml @@ -1,3 +1,4 @@ +- page_title "All Pages", "Wiki" = render 'nav' %h3.page-title All Pages diff --git a/app/views/projects/wikis/show.html.haml b/app/views/projects/wikis/show.html.haml index a6263e93f6..83cd4c6667 100644 --- a/app/views/projects/wikis/show.html.haml +++ b/app/views/projects/wikis/show.html.haml @@ -1,3 +1,4 @@ +- page_title @page.title, "Wiki" = render 'nav' %h3.page-title = @page.title diff --git a/app/views/search/_category.html.haml b/app/views/search/_category.html.haml new file mode 100644 index 0000000000..154332cb9a --- /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 ffc145497a..e2d0cab9e7 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 0000000000..47016daf1f --- /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 442bd84f93..0000000000 --- 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 ad933502a2..0000000000 --- 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 796dd752a4..741c780ad9 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 95d23fa9f4..0000000000 --- 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 01fb8cd9b8..05a63016c0 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 5b4816e4c4..60f9e9ac9d 100644 --- a/app/views/search/show.html.haml +++ b/app/views/search/show.html.haml @@ -1,22 +1,7 @@ -= 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' +- page_title @search_term += render 'search/form' +%hr +- if @search_term + = render 'search/category' + %hr + = render 'search/results' diff --git a/app/views/shared/_issuable_filter.html.haml b/app/views/shared/_issuable_filter.html.haml index f9eb2dcfa2..fa8b4eae31 100644 --- a/app/views/shared/_issuable_filter.html.haml +++ b/app/views/shared/_issuable_filter.html.haml @@ -15,7 +15,7 @@ #{state_filters_text_for(:all, @project)} .issues-details-filters - = form_tag page_filter_path(without: [:assignee_id, :author_id, :milestone_id, :label_name]), method: :get, class: 'filter-form' do + = form_tag page_filter_path(without: [:assignee_id, :author_id, :milestone_title, :label_name]), method: :get, class: 'filter-form' do - if controller.controller_name == 'issues' .check-all-holder = check_box_tag "check_all_issues", nil, false, @@ -31,7 +31,7 @@ placeholder: 'Author', class: 'trigger-submit', any_user: true, first_user: true) .filter-item.inline.milestone-filter - = select_tag('milestone_id', projects_milestones_options, class: "select2 trigger-submit", prompt: 'Milestone') + = select_tag('milestone_title', projects_milestones_options, class: "select2 trigger-submit", prompt: 'Milestone') - if @project .filter-item.inline.labels-filter diff --git a/app/views/shared/_service_settings.html.haml b/app/views/shared/_service_settings.html.haml new file mode 100644 index 0000000000..16a98a7233 --- /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 0000000000..3ac9b11b4f --- /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/snippets/current_user_index.html.haml b/app/views/snippets/current_user_index.html.haml index 6bb2237a75..0718f74382 100644 --- a/app/views/snippets/current_user_index.html.haml +++ b/app/views/snippets/current_user_index.html.haml @@ -1,3 +1,4 @@ +- page_title "Your Snippets" %h3.page-title Your Snippets .pull-right diff --git a/app/views/snippets/edit.html.haml b/app/views/snippets/edit.html.haml index 30aa174edf..1a38003566 100644 --- a/app/views/snippets/edit.html.haml +++ b/app/views/snippets/edit.html.haml @@ -1,3 +1,4 @@ +- page_title "Edit", @snippet.title, "Snippets" %h3.page-title Edit snippet %hr diff --git a/app/views/snippets/index.html.haml b/app/views/snippets/index.html.haml index 108dd0cca3..e9bb6a908d 100644 --- a/app/views/snippets/index.html.haml +++ b/app/views/snippets/index.html.haml @@ -1,3 +1,4 @@ +- page_title "Public Snippets" %h3.page-title Public snippets diff --git a/app/views/snippets/new.html.haml b/app/views/snippets/new.html.haml index 77cfd9af33..a74d5e792a 100644 --- a/app/views/snippets/new.html.haml +++ b/app/views/snippets/new.html.haml @@ -1,3 +1,4 @@ +- page_title "New Snippet" %h3.page-title New snippet %hr diff --git a/app/views/snippets/show.html.haml b/app/views/snippets/show.html.haml index 5204fb9a90..70a95abde6 100644 --- a/app/views/snippets/show.html.haml +++ b/app/views/snippets/show.html.haml @@ -1,3 +1,4 @@ +- page_title @snippet.title, "Snippets" %h3.page-title = @snippet.title diff --git a/app/views/snippets/user_index.html.haml b/app/views/snippets/user_index.html.haml index df524cd18b..23700eb39d 100644 --- a/app/views/snippets/user_index.html.haml +++ b/app/views/snippets/user_index.html.haml @@ -1,3 +1,4 @@ +- page_title "Snippets", @user.name %h3.page-title = image_tag avatar_icon(@user.email), class: "avatar s24" = @user.name diff --git a/app/views/unsubscribes/show.html.haml b/app/views/unsubscribes/show.html.haml index c2ea4e9e1f..b30ba13504 100644 --- a/app/views/unsubscribes/show.html.haml +++ b/app/views/unsubscribes/show.html.haml @@ -1,3 +1,4 @@ +- page_title "Unsubscribe", "Admin Notifications" %h3.page-title Unsubscribe from Admin notifications %hr diff --git a/app/views/users/show.html.haml b/app/views/users/show.html.haml index 15a3f741e6..6ed45fedfa 100644 --- a/app/views/users/show.html.haml +++ b/app/views/users/show.html.haml @@ -1,9 +1,12 @@ +- page_title @user.name +- header_title @user.name, user_path(@user) + = 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/app/workers/project_web_hook_worker.rb b/app/workers/project_web_hook_worker.rb index fb87896528..73085c046b 100644 --- a/app/workers/project_web_hook_worker.rb +++ b/app/workers/project_web_hook_worker.rb @@ -3,8 +3,8 @@ class ProjectWebHookWorker sidekiq_options queue: :project_web_hook - def perform(hook_id, data, hook_name) + def perform(hook_id, data) data = data.with_indifferent_access - WebHook.find(hook_id).execute(data, hook_name) + WebHook.find(hook_id).execute(data) end end diff --git a/app/workers/system_hook_worker.rb b/app/workers/system_hook_worker.rb index a122c27476..3ebc62b7e7 100644 --- a/app/workers/system_hook_worker.rb +++ b/app/workers/system_hook_worker.rb @@ -3,7 +3,7 @@ class SystemHookWorker sidekiq_options queue: :system_hook - def perform(hook_id, data, hook_name) - SystemHook.find(hook_id).execute(data, hook_name) + def perform(hook_id, data) + SystemHook.find(hook_id).execute data end end diff --git a/config/gitlab.yml.example b/config/gitlab.yml.example index 84271f2c30..3e89f40576 100644 --- a/config/gitlab.yml.example +++ b/config/gitlab.yml.example @@ -12,6 +12,9 @@ # 2. Update gitlab -> host with your fully qualified domain name # 3. Update gitlab -> email_from # 4. If you installed Git from source, change git -> bin_path to /usr/local/bin/git +# IMPORTANT: If Git was installed in a different location use that instead. +# You can check with `which git`. If a wrong path of Git is specified, it will +# result in various issues such as failures of GitLab CI builds. # 5. Review this configuration file for other settings you may want to adjust production: &base diff --git a/config/initializers/1_settings.rb b/config/initializers/1_settings.rb index 7cbf635c81..cceb26cf51 100644 --- a/config/initializers/1_settings.rb +++ b/config/initializers/1_settings.rb @@ -165,6 +165,7 @@ Settings.gitlab.default_projects_features['wiki'] = true if Settings.g Settings.gitlab.default_projects_features['snippets'] = false if Settings.gitlab.default_projects_features['snippets'].nil? Settings.gitlab.default_projects_features['visibility_level'] = Settings.send(:verify_constant, Gitlab::VisibilityLevel, Settings.gitlab.default_projects_features['visibility_level'], Gitlab::VisibilityLevel::PRIVATE) Settings.gitlab['repository_downloads_path'] = File.absolute_path(Settings.gitlab['repository_downloads_path'] || 'tmp/repositories', Rails.root) +Settings.gitlab['restricted_signup_domains'] ||= [] # # Gravatar diff --git a/config/initializers/8_default_url_options.rb b/config/initializers/8_default_url_options.rb index 8c1b56846d..8fd27b1d88 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/initializers/devise.rb b/config/initializers/devise.rb index 94b9fd4477..9434f4fd7a 100644 --- a/config/initializers/devise.rb +++ b/config/initializers/devise.rb @@ -2,13 +2,8 @@ # four configuration values can also be set straight in your models. Devise.setup do |config| # ==> Mailer Configuration - # Configure the e-mail address which will be shown in Devise::Mailer, - # note that it will be overwritten if you use your own mailer class with default "from" parameter. - config.mailer_sender = "GitLab <#{Gitlab.config.gitlab.email_from}>" - - # Configure the class responsible to send e-mails. - # config.mailer = "Devise::Mailer" + config.mailer = "DeviseMailer" # ==> ORM configuration # Load and configure the ORM. Supports :active_record (default) and diff --git a/config/routes.rb b/config/routes.rb index 81d8cac102..c65139aed7 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -468,7 +468,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/20150425164648_add_missing_unique_indices.acts_as_taggable_on_engine.rb b/db/migrate/20150425164648_add_missing_unique_indices.acts_as_taggable_on_engine.rb new file mode 100644 index 0000000000..4ca676f6c7 --- /dev/null +++ b/db/migrate/20150425164648_add_missing_unique_indices.acts_as_taggable_on_engine.rb @@ -0,0 +1,20 @@ +# This migration comes from acts_as_taggable_on_engine (originally 2) +class AddMissingUniqueIndices < ActiveRecord::Migration + def self.up + add_index :tags, :name, unique: true + + remove_index :taggings, :tag_id + remove_index :taggings, [:taggable_id, :taggable_type, :context] + add_index :taggings, + [:tag_id, :taggable_id, :taggable_type, :context, :tagger_id, :tagger_type], + unique: true, name: 'taggings_idx' + end + + def self.down + remove_index :tags, :name + + remove_index :taggings, name: 'taggings_idx' + add_index :taggings, :tag_id + add_index :taggings, [:taggable_id, :taggable_type, :context] + end +end diff --git a/db/migrate/20150425164649_add_taggings_counter_cache_to_tags.acts_as_taggable_on_engine.rb b/db/migrate/20150425164649_add_taggings_counter_cache_to_tags.acts_as_taggable_on_engine.rb new file mode 100644 index 0000000000..8edb508078 --- /dev/null +++ b/db/migrate/20150425164649_add_taggings_counter_cache_to_tags.acts_as_taggable_on_engine.rb @@ -0,0 +1,15 @@ +# This migration comes from acts_as_taggable_on_engine (originally 3) +class AddTaggingsCounterCacheToTags < ActiveRecord::Migration + def self.up + add_column :tags, :taggings_count, :integer, default: 0 + + ActsAsTaggableOn::Tag.reset_column_information + ActsAsTaggableOn::Tag.find_each do |tag| + ActsAsTaggableOn::Tag.reset_counters(tag.id, :taggings) + end + end + + def self.down + remove_column :tags, :taggings_count + end +end diff --git a/db/migrate/20150425164650_add_missing_taggable_index.acts_as_taggable_on_engine.rb b/db/migrate/20150425164650_add_missing_taggable_index.acts_as_taggable_on_engine.rb new file mode 100644 index 0000000000..71f2d7f433 --- /dev/null +++ b/db/migrate/20150425164650_add_missing_taggable_index.acts_as_taggable_on_engine.rb @@ -0,0 +1,10 @@ +# This migration comes from acts_as_taggable_on_engine (originally 4) +class AddMissingTaggableIndex < ActiveRecord::Migration + def self.up + add_index :taggings, [:taggable_id, :taggable_type, :context] + end + + def self.down + remove_index :taggings, [:taggable_id, :taggable_type, :context] + end +end diff --git a/db/migrate/20150425164651_change_collation_for_tag_names.acts_as_taggable_on_engine.rb b/db/migrate/20150425164651_change_collation_for_tag_names.acts_as_taggable_on_engine.rb new file mode 100644 index 0000000000..bfb06bc7cd --- /dev/null +++ b/db/migrate/20150425164651_change_collation_for_tag_names.acts_as_taggable_on_engine.rb @@ -0,0 +1,10 @@ +# This migration comes from acts_as_taggable_on_engine (originally 5) +# This migration is added to circumvent issue #623 and have special characters +# work properly +class ChangeCollationForTagNames < ActiveRecord::Migration + def up + if ActsAsTaggableOn::Utils.using_mysql? + execute("ALTER TABLE tags MODIFY name varchar(255) CHARACTER SET utf8 COLLATE utf8_bin;") + end + end +end 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 0000000000..6013605bb3 --- /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/migrate/20150502064022_add_restricted_signup_domains_to_application_settings.rb b/db/migrate/20150502064022_add_restricted_signup_domains_to_application_settings.rb new file mode 100644 index 0000000000..184e265361 --- /dev/null +++ b/db/migrate/20150502064022_add_restricted_signup_domains_to_application_settings.rb @@ -0,0 +1,5 @@ +class AddRestrictedSignupDomainsToApplicationSettings < ActiveRecord::Migration + def change + add_column :application_settings, :restricted_signup_domains, :text + end +end diff --git a/db/schema.rb b/db/schema.rb index 6728c211ab..630367db3d 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: 20150502064022) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -43,6 +43,7 @@ ActiveRecord::Schema.define(version: 20150425173433) do t.integer "max_attachment_size", default: 10, null: false t.integer "default_project_visibility" t.integer "default_snippet_visibility" + t.text "restricted_signup_domains" end create_table "audit_events", force: true do |t| @@ -302,7 +303,7 @@ ActiveRecord::Schema.define(version: 20150425173433) do end add_index "namespaces", ["created_at", "id"], name: "index_namespaces_on_created_at_and_id", using: :btree - add_index "namespaces", ["name"], name: "index_namespaces_on_name", unique: true, using: :btree + add_index "namespaces", ["name"], name: "index_namespaces_on_name", using: :btree add_index "namespaces", ["owner_id"], name: "index_namespaces_on_owner_id", using: :btree add_index "namespaces", ["path"], name: "index_namespaces_on_path", unique: true, using: :btree add_index "namespaces", ["type"], name: "index_namespaces_on_type", using: :btree @@ -410,11 +411,11 @@ ActiveRecord::Schema.define(version: 20150425173433) do t.string "avatar" t.string "import_status" t.float "repository_size", default: 0.0 - t.text "merge_requests_template" t.integer "star_count", default: 0, null: false - t.boolean "merge_requests_rebase_enabled", default: false t.string "import_type" t.string "import_source" + t.text "merge_requests_template" + t.boolean "merge_requests_rebase_enabled", default: false t.boolean "merge_requests_rebase_default", default: true end @@ -494,13 +495,16 @@ ActiveRecord::Schema.define(version: 20150425173433) do t.datetime "created_at" end - add_index "taggings", ["tag_id"], name: "index_taggings_on_tag_id", using: :btree + add_index "taggings", ["tag_id", "taggable_id", "taggable_type", "context", "tagger_id", "tagger_type"], name: "taggings_idx", unique: true, using: :btree add_index "taggings", ["taggable_id", "taggable_type", "context"], name: "index_taggings_on_taggable_id_and_taggable_type_and_context", using: :btree create_table "tags", force: true do |t| - t.string "name" + t.string "name" + t.integer "taggings_count", default: 0 end + add_index "tags", ["name"], name: "index_tags_on_name", unique: true, using: :btree + create_table "users", force: true do |t| t.string "email", default: "", null: false t.string "encrypted_password", default: "", null: false @@ -541,7 +545,6 @@ 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 "admin_email_unsubscribed_at" t.string "github_access_token" t.string "gitlab_access_token" t.string "notification_email" @@ -549,6 +552,7 @@ ActiveRecord::Schema.define(version: 20150425173433) do t.boolean "password_automatically_set", default: false t.string "bitbucket_access_token" t.string "bitbucket_access_token_secret" + t.datetime "admin_email_unsubscribed_at" t.string "location" t.string "public_email", default: "", null: false end diff --git a/doc/api/README.md b/doc/api/README.md index dec530d0b8..f6757b0a6a 100644 --- a/doc/api/README.md +++ b/doc/api/README.md @@ -6,6 +6,7 @@ - [Session](session.md) - [Projects](projects.md) - [Project Snippets](project_snippets.md) +- [Services](services.md) - [Repositories](repositories.md) - [Repository Files](repository_files.md) - [Commits](commits.md) diff --git a/doc/api/groups.md b/doc/api/groups.md index b5a4b05cca..c903a850fd 100644 --- a/doc/api/groups.md +++ b/doc/api/groups.md @@ -35,7 +35,7 @@ Parameters: ## New group -Creates a new project group. Available only for admin. +Creates a new project group. Available only for users who can create groups. ``` POST /groups diff --git a/doc/api/issues.md b/doc/api/issues.md index a7dd8b74c3..d407bc35d7 100644 --- a/doc/api/issues.md +++ b/doc/api/issues.md @@ -99,11 +99,13 @@ GET /projects/:id/issues?labels=foo,bar GET /projects/:id/issues?labels=foo,bar&state=opened GET /projects/:id/issues?milestone=1.0.0 GET /projects/:id/issues?milestone=1.0.0&state=opened +GET /projects/:id/issues?iid=42 ``` Parameters: - `id` (required) - The ID of a project +- `iid` (optional) - Return the issue having the given `iid` - `state` (optional) - Return `all` issues or just those that are `opened` or `closed` - `labels` (optional) - Comma-separated list of label names - `milestone` (optional) - Milestone title diff --git a/doc/api/merge_requests.md b/doc/api/merge_requests.md index 6a272539e4..c1d82ad957 100644 --- a/doc/api/merge_requests.md +++ b/doc/api/merge_requests.md @@ -10,11 +10,13 @@ The pagination parameters `page` and `per_page` can be used to restrict the list GET /projects/:id/merge_requests GET /projects/:id/merge_requests?state=opened GET /projects/:id/merge_requests?state=all +GET /projects/:id/merge_requests?iid=42 ``` Parameters: - `id` (required) - The ID of a project +- `iid` (optional) - Return the request having the given `iid` - `state` (optional) - Return `all` requests or just those that are `merged`, `opened` or `closed` - `order_by` (optional) - Return requests ordered by `created_at` or `updated_at` fields. Default is `created_at` - `sort` (optional) - Return requests sorted in `asc` or `desc` order. Default is `desc` @@ -388,6 +390,6 @@ Parameters: ] ``` -## Comments on issues +## Comments on merge requets Comments are done via the notes resource. diff --git a/doc/api/milestones.md b/doc/api/milestones.md index d48b3bcce8..a682872826 100644 --- a/doc/api/milestones.md +++ b/doc/api/milestones.md @@ -6,6 +6,7 @@ Returns a list of project milestones. ``` GET /projects/:id/milestones +GET /projects/:id/milestones?iid=42 ``` ```json @@ -27,6 +28,7 @@ GET /projects/:id/milestones Parameters: - `id` (required) - The ID of a project +- `iid` (optional) - Return the milestone having the given `iid` ## Get single milestone diff --git a/doc/api/project_snippets.md b/doc/api/project_snippets.md index 50e134847c..a7acf37b5b 100644 --- a/doc/api/project_snippets.md +++ b/doc/api/project_snippets.md @@ -1,5 +1,18 @@ # Project snippets +### Snippet visibility level + +Snippets in GitLab can be either private, internal or public. +You can set it with the `visibility_level` field in the snippet. + +Constants for snippet visibility levels are: + +| Visibility | visibility_level | Description | +| ---------- | ---------------- | ----------- | +| Private | `0` | The snippet is visible only the snippet creator | +| Internal | `10` | The snippet is visible for any logged in user | +| Public | `20` | The snippet can be accessed without any authentication | + ## List snippets Get a list of project snippets. @@ -58,6 +71,7 @@ Parameters: - `title` (required) - The title of a snippet - `file_name` (required) - The name of a snippet file - `code` (required) - The content of a snippet +- `visibility_level` (required) - The snippet's visibility ## Update snippet @@ -74,6 +88,7 @@ Parameters: - `title` (optional) - The title of a snippet - `file_name` (optional) - The name of a snippet file - `code` (optional) - The content of a snippet +- `visibility_level` (optional) - The snippet's visibility ## Delete snippet diff --git a/doc/api/users.md b/doc/api/users.md index a8b7685b50..cd141daadc 100644 --- a/doc/api/users.md +++ b/doc/api/users.md @@ -57,7 +57,8 @@ GET /users "color_scheme_id": 2, "is_admin": false, "avatar_url": "http://localhost:3000/uploads/user/avatar/1/cd8.jpeg", - "can_create_group": true + "can_create_group": true, + "current_sign_in_at": "2014-03-19T13:12:15Z" }, { "id": 2, @@ -79,7 +80,8 @@ GET /users "avatar_url": "http://localhost:3000/uploads/user/avatar/1/cd8.jpeg", "can_create_group": true, "can_create_project": true, - "projects_limit": 100 + "projects_limit": 100, + "current_sign_in_at": "2014-03-19T17:54:13Z" } ] ``` diff --git a/doc/customization/issue_closing.md b/doc/customization/issue_closing.md index aa65a082a5..64f128f5a6 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/integration/external-issue-tracker.md b/doc/integration/external-issue-tracker.md index 96755707de..3e660cfba1 100644 --- a/doc/integration/external-issue-tracker.md +++ b/doc/integration/external-issue-tracker.md @@ -36,4 +36,9 @@ In GitLab Admin section, navigate to `Service Templates` and choose the service After the template is created, the template details will be pre-filled on the project service page. +NOTE: For each project, you will still need to configure the issue tracking URLs by replacing `:issues_tracker_id` in the above screenshot +with the ID used by your external issue tracker. Prior to GitLab v7.8, this ID was configured in the project settings, and GitLab would automatically +update the URL configured in `gitlab.yml`. This behavior is now depecated, and all issue tracker URLs must be configured directly +within the project's Services settings. + Support to add your commits to the Jira ticket automatically is [available in GitLab EE](http://doc.gitlab.com/ee/integration/jira.html). diff --git a/doc/logs/logs.md b/doc/logs/logs.md index ec0109a426..83c32b0925 100644 --- a/doc/logs/logs.md +++ b/doc/logs/logs.md @@ -5,7 +5,7 @@ In addition to system log files, GitLab Enterprise Edition comes with Audit Even System log files are typically plain text in a standard log file format. This guide talks about how to read and use these system log files. #### production.log -This file lives in `/var/log/gitlab/gitlab-rails/production.log` for omnibus package or in `/home/git/gitlab/logs/production.log` for installations from the source. +This file lives in `/var/log/gitlab/gitlab-rails/production.log` for omnibus package or in `/home/git/gitlab/log/production.log` for installations from the source. This file contains information about all performed requests. You can see url and type of request, IP address and what exactly parts of code were involved to service this particular request. Also you can see all SQL request that have been performed and how much time it took. This task is more useful for GitLab contributors and developers. Use part of this log file when you are going to report bug. @@ -30,7 +30,7 @@ Completed 200 OK in 166ms (Views: 117.4ms | ActiveRecord: 27.2ms) In this example we can see that server processed HTTP request with url `/gitlabhq/yaml_db/tree/master` from IP 168.111.56.1 at 2015-02-12 19:34:53 +0200. Also we can see that request was processed by Projects::TreeController. #### application.log -This file lives in `/var/log/gitlab/gitlab-rails/application.log` for omnibus package or in `/home/git/gitlab/logs/application.log` for installations from the source. +This file lives in `/var/log/gitlab/gitlab-rails/application.log` for omnibus package or in `/home/git/gitlab/log/application.log` for installations from the source. This log file helps you discover events happening in your instance such as user creation, project removing and so on. @@ -42,7 +42,7 @@ October 07, 2014 11:25: User "Claudie Hodkiewicz" (nasir_stehr@olson.co.uk) was October 07, 2014 11:25: Project "project133" was removed ``` #### githost.log -This file lives in `/var/log/gitlab/gitlab-rails/githost.log` for omnibus package or in `/home/git/gitlab/logs/githost.log` for installations from the source. +This file lives in `/var/log/gitlab/gitlab-rails/githost.log` for omnibus package or in `/home/git/gitlab/log/githost.log` for installations from the source. The GitLab has to interact with git repositories but in some rare cases something can go wrong and in this case you will know what exactly happened. This log file contains all failed requests from GitLab to git repository. In majority of cases this file will be useful for developers only. ``` @@ -52,7 +52,7 @@ error: failed to push some refs to '/Users/vsizov/gitlab-development-kit/reposit ``` #### satellites.log -This file lives in `/var/log/gitlab/gitlab-rails/satellites.log` for omnibus package or in `/home/git/gitlab/logs/satellites.log` for installations from the source. +This file lives in `/var/log/gitlab/gitlab-rails/satellites.log` for omnibus package or in `/home/git/gitlab/log/satellites.log` for installations from the source. In some cases GitLab should perform write actions to git repository, for example when it is needed to merge the merge request or edit a file with online editor. If something went wrong you can look into this file to find out what exactly happened. ``` @@ -62,7 +62,7 @@ October 07, 2014 11:36: PID: 1872: -> fatal: repository '/Users/vsizov/gitlab-de ``` #### sidekiq.log -This file lives in `/var/log/gitlab/gitlab-rails/sidekiq.log` for omnibus package or in `/home/git/gitlab/logs/sidekiq.log` for installations from the source. +This file lives in `/var/log/gitlab/gitlab-rails/sidekiq.log` for omnibus package or in `/home/git/gitlab/log/sidekiq.log` for installations from the source. GitLab uses background jobs for processing tasks which can take a long time. All information about processing these jobs are writing down to this file. ``` @@ -71,7 +71,7 @@ GitLab uses background jobs for processing tasks which can take a long time. All ``` #### gitlab-shell.log -This file lives in `/var/log/gitlab/gitlab-shell/gitlab-shell.log` for omnibus package or in `/home/git/gitlab-shell/logs/sidekiq.log` for installations from the source. +This file lives in `/var/log/gitlab/gitlab-shell/gitlab-shell.log` for omnibus package or in `/home/git/gitlab-shell/gitlab-shell.log` for installations from the source. gitlab-shell is using by Gitlab for executing git commands and provide ssh access to git repositories. @@ -81,7 +81,7 @@ I, [2015-02-13T06:17:00.679433 #9291] INFO -- : Moving existing hooks directory ``` #### unicorn_stderr.log -This file lives in `/var/log/gitlab/unicorn/unicorn_stderr.log` for omnibus package or in `/home/git/gitlab/logs/unicorn_stderr.log` for installations from the source. +This file lives in `/var/log/gitlab/unicorn/unicorn_stderr.log` for omnibus package or in `/home/git/gitlab/log/unicorn_stderr.log` for installations from the source. Unicorn is a high-performance forking Web server which is used for serving GitLab application. You can look at this log, for example, if your application does not respond. This log cantains all information about state of unicorn processes at any given time. @@ -99,4 +99,4 @@ W, [2015-02-13T07:16:01.313000 #9094] WARN -- : Unicorn::WorkerKiller send SIGQ I, [2015-02-13T07:16:01.530733 #9047] INFO -- : reaped # worker=1 I, [2015-02-13T07:16:01.534501 #13379] INFO -- : worker=1 spawned pid=13379 I, [2015-02-13T07:16:01.534848 #13379] INFO -- : worker=1 ready -``` +``` \ No newline at end of file diff --git a/doc/raketasks/user_management.md b/doc/raketasks/user_management.md index 80b01ca404..4fbd20762d 100644 --- a/doc/raketasks/user_management.md +++ b/doc/raketasks/user_management.md @@ -47,3 +47,12 @@ sudo gitlab-rake gitlab:import:all_users_to_all_groups # installation from source bundle exec rake gitlab:import:all_users_to_all_groups RAILS_ENV=production ``` + +## Maintain tight control over the number of active users on your GitLab installation + +- Enable this setting to keep new users blocked until they have been cleared by the admin (default: false). + + +``` +block_auto_created_users: false +``` diff --git a/doc/update/7.6-to-7.7.md b/doc/update/7.6-to-7.7.md index 5924371315..910c7dcdd3 100644 --- a/doc/update/7.6-to-7.7.md +++ b/doc/update/7.6-to-7.7.md @@ -67,7 +67,7 @@ sudo cp lib/support/init.d/gitlab /etc/init.d/gitlab #### 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 to your current `gitlab.yml`. +There are new configuration options available for [`gitlab.yml`](/config/gitlab.yml.example). View them with the command below and apply them to your current `gitlab.yml`. ``` git diff origin/7-6-stable:config/gitlab.yml.example origin/7-7-stable:config/gitlab.yml.example diff --git a/doc/update/7.9-to-7.10.md b/doc/update/7.9-to-7.10.md index 0512e7cde7..d1179dc2ec 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/doc/update/upgrader.md b/doc/update/upgrader.md index e32984c4e6..2cca46c86a 100644 --- a/doc/update/upgrader.md +++ b/doc/update/upgrader.md @@ -27,10 +27,10 @@ If you have local changes to your GitLab repository the script will stash them a Note: GitLab 7.9 adds `nodejs` as a dependency. GitLab 7.6 adds `libkrb5-dev` as a dependency (installed by default on Ubuntu and OSX). GitLab 7.2 adds `pkg-config` and `cmake` as dependency. Please check the dependencies in the [installation guide.](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/doc/install/installation.md#1-packages-dependencies) cd /home/git/gitlab - sudo -u git -H ruby -Ilib -e 'require "gitlab/upgrader"' -e 'class Gitlab::Upgrader' -e 'def latest_version_raw' -e '"v7.10.0"' -e 'end' -e 'end' -e 'Gitlab::Upgrader.new.execute' + sudo -u git -H ruby -Ilib -e 'require "gitlab/upgrader"' -e 'class Gitlab::Upgrader' -e 'def latest_version_raw' -e '"v7.10.1"' -e 'end' -e 'end' -e 'Gitlab::Upgrader.new.execute' # to perform a non-interactive install (no user input required) you can add -y - # sudo -u git -H ruby -Ilib -e 'require "gitlab/upgrader"' -e 'class Gitlab::Upgrader' -e 'def latest_version_raw' -e '"v7.10.0"' -e 'end' -e 'end' -e 'Gitlab::Upgrader.new.execute' -- -y + # sudo -u git -H ruby -Ilib -e 'require "gitlab/upgrader"' -e 'class Gitlab::Upgrader' -e 'def latest_version_raw' -e '"v7.10.1"' -e 'end' -e 'end' -e 'Gitlab::Upgrader.new.execute' -- -y ## 3. Start application @@ -65,7 +65,7 @@ Here is a one line command with step 1 to 5 for the next time you upgrade: cd /home/git/gitlab; \ sudo -u git -H bundle exec rake gitlab:backup:create RAILS_ENV=production; \ sudo service gitlab stop; \ - sudo -u git -H ruby -Ilib -e 'require "gitlab/upgrader"' -e 'class Gitlab::Upgrader' -e 'def latest_version_raw' -e '"v7.10.0"' -e 'end' -e 'end' -e 'Gitlab::Upgrader.new.execute' -- -y; \ + sudo -u git -H ruby -Ilib -e 'require "gitlab/upgrader"' -e 'class Gitlab::Upgrader' -e 'def latest_version_raw' -e '"v7.10.1"' -e 'end' -e 'end' -e 'Gitlab::Upgrader.new.execute' -- -y; \ cd /home/git/gitlab-shell; \ sudo -u git -H git fetch; \ sudo -u git -H git checkout v`cat /home/git/gitlab/GITLAB_SHELL_VERSION`; \ diff --git a/docker/Dockerfile b/docker/Dockerfile index bb25bb677c..df828a2a34 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -11,7 +11,7 @@ RUN apt-get update -q \ # If the Omnibus package version below is outdated please contribute a merge request to update it. # If you run GitLab Enterprise Edition point it to a location where you have downloaded it. RUN TMP_FILE=$(mktemp); \ - wget -q -O $TMP_FILE https://downloads-packages.s3.amazonaws.com/ubuntu-14.04/gitlab_7.9.2-omnibus-1_amd64.deb \ + wget -q -O $TMP_FILE https://downloads-packages.s3.amazonaws.com/ubuntu-14.04/gitlab-ce_7.10.1~omnibus.2-1_amd64.deb \ && dpkg -i $TMP_FILE \ && rm -f $TMP_FILE @@ -30,4 +30,4 @@ EXPOSE 80 22 COPY assets/wrapper /usr/local/bin/ # Wrapper to handle signal, trigger runit and reconfigure GitLab -CMD ["/usr/local/bin/wrapper"] +CMD ["/usr/local/bin/wrapper"] \ No newline at end of file diff --git a/docker/README.md b/docker/README.md index b7e8b0db7e..a54739ae3d 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. - - -![GitLab Logo](https://gitlab.com/uploads/appearance/logo/1/brand_logo-c37eb221b456bb4b472cc1084480991f.png) +Learn more on [https://about.gitlab.com](https://about.gitlab.com) -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/project/project.feature b/features/project/project.feature index cf488ccea7..3aad2b4421 100644 --- a/features/project/project.feature +++ b/features/project/project.feature @@ -72,3 +72,10 @@ Feature: Project And I change "Pete" access level to master And I go to "Audit Events" Then I should see the audit event listed + + Scenario: I tag a project + When I visit edit project "Shop" page + Then I should see project settings + And I add project tags + And I save project + Then I should see project tags diff --git a/features/search.feature b/features/search.feature index def21e0092..1608e82467 100644 --- a/features/search.feature +++ b/features/search.feature @@ -44,3 +44,9 @@ Feature: Search Then I should see "Foo" link in the search results And I should not see "Bar" link in the search results + Scenario: I should see Wiki blobs + And project has Wiki content + When I click project "Shop" link + And I search for "Wiki content" + And I click "Wiki" link + Then I should see "test_wiki" link in the search results diff --git a/features/steps/project/project.rb b/features/steps/project/project.rb index 7421c91e07..f6138296da 100644 --- a/features/steps/project/project.rb +++ b/features/steps/project/project.rb @@ -154,4 +154,12 @@ class Spinach::Features::Project < Spinach::FeatureSteps page.should have_content('Pete') end end + + step 'I add project tags' do + fill_in 'Tags', with: 'tag1, tag2' + end + + step 'I should see project tags' do + expect(find_field('Tags').value).to eq 'tag1, tag2' + end end diff --git a/features/steps/project/source/search_code.rb b/features/steps/project/source/search_code.rb index 9c2864cc93..b66c5a4123 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/features/steps/project/wiki.rb b/features/steps/project/wiki.rb index bb93e582a1..717132da45 100644 --- a/features/steps/project/wiki.rb +++ b/features/steps/project/wiki.rb @@ -159,6 +159,11 @@ class Spinach::Features::ProjectWiki < Spinach::FeatureSteps page.should have_content('History for') end + step 'I search for Wiki content' do + fill_in "Search in this project", with: "wiki_content" + click_button "Search" + end + def wiki @project_wiki = ProjectWiki.new(project, current_user) end diff --git a/features/steps/search.rb b/features/steps/search.rb index 6f0e038c4d..8197cd410a 100644 --- a/features/steps/search.rb +++ b/features/steps/search.rb @@ -18,6 +18,11 @@ class Spinach::Features::Search < Spinach::FeatureSteps click_button "Search" end + step 'I search for "Wiki content"' do + fill_in "dashboard_search", with: "content" + click_button "Search" + end + step 'I click "Issues" link' do within '.search-filter' do click_link 'Issues' @@ -36,6 +41,12 @@ class Spinach::Features::Search < Spinach::FeatureSteps end end + step 'I click "Wiki" link' do + within '.search-filter' do + click_link 'Wiki' + end + end + step 'I should see "Shop" project link' do page.should have_link "Shop" end @@ -66,4 +77,13 @@ class Spinach::Features::Search < Spinach::FeatureSteps step 'I should not see "Bar" link in the search results' do find(:css, '.search-results').should_not have_link 'Bar' end + + step 'I should see "test_wiki" link in the search results' do + find(:css, '.search-results').should have_link 'test_wiki.md' + end + + step 'project has Wiki content' do + @wiki = ::ProjectWiki.new(project, current_user) + @wiki.create_page("test_wiki", "Some Wiki content", :markdown, "first commit") + end end diff --git a/features/steps/shared/markdown.rb b/features/steps/shared/markdown.rb index e71700880c..a7231c47d1 100644 --- a/features/steps/shared/markdown.rb +++ b/features/steps/shared/markdown.rb @@ -2,8 +2,12 @@ module SharedMarkdown include Spinach::DSL def header_should_have_correct_id_and_link(level, text, id, parent = ".wiki") - find(:css, "#{parent} h#{level}##{id}").text.should == text - find(:css, "#{parent} h#{level}##{id} > :last-child")[:href].should =~ /##{id}$/ + node = find("#{parent} h#{level} a##{id}") + node[:href].should == "##{id}" + + # Work around a weird Capybara behavior where calling `parent` on a node + # returns the whole document, not the node's actual parent element + find(:xpath, "#{node.path}/..").text.should == text end def create_taskable(type, title) diff --git a/lib/api/api.rb b/lib/api/api.rb index 01a583fecd..ac5c969661 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/entities.rb b/lib/api/entities.rb index fa9aab2900..860ec01cfd 100644 --- a/lib/api/entities.rb +++ b/lib/api/entities.rb @@ -20,7 +20,7 @@ module API class UserFull < User expose :email - expose :theme_id, :color_scheme_id, :projects_limit + expose :theme_id, :color_scheme_id, :projects_limit, :current_sign_in_at expose :identities, using: Entities::Identity expose :can_create_group?, as: :can_create_group expose :can_create_project?, as: :can_create_project diff --git a/lib/api/groups.rb b/lib/api/groups.rb index 84df6d7249..3f4ee3fef8 100644 --- a/lib/api/groups.rb +++ b/lib/api/groups.rb @@ -20,7 +20,7 @@ module API present @groups, with: Entities::Group end - # Create group. Available only for admin + # Create group. Available only for users who can create groups. # # Parameters: # name (required) - The name of the group @@ -28,7 +28,7 @@ module API # Example Request: # POST /groups post do - authenticated_as_admin! + authorize! :create_group, current_user required_attributes! [:name, :path] attrs = attributes_for_keys [:name, :path, :description] diff --git a/lib/api/helpers.rb b/lib/api/helpers.rb index be133a2920..85e9081680 100644 --- a/lib/api/helpers.rb +++ b/lib/api/helpers.rb @@ -173,6 +173,10 @@ module API end end + def filter_by_iid(items, iid) + items.where(iid: iid) + end + # error helpers def forbidden!(reason = nil) diff --git a/lib/api/issues.rb b/lib/api/issues.rb index ff062be604..c8db93eb77 100644 --- a/lib/api/issues.rb +++ b/lib/api/issues.rb @@ -51,6 +51,7 @@ module API # # Parameters: # id (required) - The ID of a project + # iid (optional) - Return the project issue having the given `iid` # state (optional) - Return "opened" or "closed" issues # labels (optional) - Comma-separated list of label names # milestone (optional) - Milestone title @@ -66,10 +67,12 @@ module API # GET /projects/:id/issues?labels=foo,bar&state=opened # GET /projects/:id/issues?milestone=1.0.0 # GET /projects/:id/issues?milestone=1.0.0&state=closed + # GET /issues?iid=42 get ":id/issues" do issues = user_project.issues issues = filter_issues_state(issues, params[:state]) unless params[:state].nil? issues = filter_issues_labels(issues, params[:labels]) unless params[:labels].nil? + issues = filter_by_iid(issues, params[:iid]) unless params[:iid].nil? unless params[:milestone].nil? issues = filter_issues_milestone(issues, params[:milestone]) diff --git a/lib/api/merge_requests.rb b/lib/api/merge_requests.rb index f3765f5ab0..2216a12a87 100644 --- a/lib/api/merge_requests.rb +++ b/lib/api/merge_requests.rb @@ -24,6 +24,7 @@ module API # # Parameters: # id (required) - The ID of a project + # iid (optional) - Return the project MR having the given `iid` # state (optional) - Return requests "merged", "opened" or "closed" # order_by (optional) - Return requests ordered by `created_at` or `updated_at` fields. Default is `created_at` # sort (optional) - Return requests sorted in `asc` or `desc` order. Default is `desc` @@ -36,11 +37,16 @@ module API # GET /projects/:id/merge_requests?order_by=updated_at # GET /projects/:id/merge_requests?sort=desc # GET /projects/:id/merge_requests?sort=asc + # GET /projects/:id/merge_requests?iid=42 # get ":id/merge_requests" do authorize! :read_merge_request, user_project merge_requests = user_project.merge_requests + unless params[:iid].nil? + merge_requests = filter_by_iid(merge_requests, params[:iid]) + end + merge_requests = case params["state"] when "opened" then merge_requests.opened @@ -169,8 +175,8 @@ module API # Merge MR # # Parameters: - # id (required) - The ID of a project - # merge_request_id (required) - ID of MR + # id (required) - The ID of a project + # merge_request_id (required) - ID of MR # merge_commit_message (optional) - Custom merge commit message # Example: # PUT /projects/:id/merge_request/:merge_request_id/merge @@ -186,7 +192,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 +201,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 @@ -209,7 +215,7 @@ module API # Get a merge request's comments # # Parameters: - # id (required) - The ID of a project + # id (required) - The ID of a project # merge_request_id (required) - ID of MR # Examples: # GET /projects/:id/merge_request/:merge_request_id/comments @@ -225,9 +231,9 @@ module API # Post comment to merge request # # Parameters: - # id (required) - The ID of a project + # id (required) - The ID of a project # merge_request_id (required) - ID of MR - # note (required) - Text of comment + # note (required) - Text of comment # Examples: # POST /projects/:id/merge_request/:merge_request_id/comments # diff --git a/lib/api/system_hooks.rb b/lib/api/system_hooks.rb index 22b8f90dc5..518964db50 100644 --- a/lib/api/system_hooks.rb +++ b/lib/api/system_hooks.rb @@ -47,7 +47,7 @@ module API owner_name: "Someone", owner_email: "example@gitlabhq.com" } - @hook.execute(data, 'system_hooks') + @hook.execute(data) data end diff --git a/lib/gitlab/google_code_import/client.rb b/lib/gitlab/google_code_import/client.rb index 02f31e45f8..890bd9a355 100644 --- a/lib/gitlab/google_code_import/client.rb +++ b/lib/gitlab/google_code_import/client.rb @@ -21,6 +21,10 @@ module Gitlab @repos ||= raw_data["projects"].map { |raw_repo| GoogleCodeImport::Repository.new(raw_repo) }.select(&:git?) end + def incompatible_repos + @incompatible_repos ||= raw_data["projects"].map { |raw_repo| GoogleCodeImport::Repository.new(raw_repo) }.reject(&:git?) + end + def repo(id) repos.find { |repo| repo.id == id } end diff --git a/lib/gitlab/ldap/authentication.rb b/lib/gitlab/ldap/authentication.rb index 649cf3194b..bad683c651 100644 --- a/lib/gitlab/ldap/authentication.rb +++ b/lib/gitlab/ldap/authentication.rb @@ -1,4 +1,4 @@ -# This calls helps to authenticate to LDAP by providing username and password +# These calls help to authenticate to LDAP by providing username and password # # Since multiple LDAP servers are supported, it will loop through all of them # until a valid bind is found diff --git a/lib/gitlab/markdown.rb b/lib/gitlab/markdown.rb index 44779d7fdd..8348e28d0f 100644 --- a/lib/gitlab/markdown.rb +++ b/lib/gitlab/markdown.rb @@ -3,33 +3,10 @@ require 'html/pipeline' module Gitlab # Custom parser for GitLab-flavored Markdown # - # It replaces references in the text with links to the appropriate items in - # GitLab. - # - # Supported reference formats are: - # * @foo for team members - # * #123 for issues - # * JIRA-123 for Jira issues - # * !123 for merge requests - # * $123 for snippets - # * 1c002d for specific commit - # * 1c002d...35cfb2 for commit ranges (comparisons) - # - # It also parses Emoji codes to insert images. See - # http://www.emoji-cheat-sheet.com/ for a list of the supported icons. - # - # Examples - # - # >> gfm("Hey @david, can you fix this?") - # => "Hey @david, can you fix this?" - # - # >> gfm("Commit 35d5f7c closes #1234") - # => "Commit 35d5f7c closes #1234" - # - # >> gfm(":trollface:") - # => "\":trollface:\" + # See the files in `lib/gitlab/markdown/` for specific processing information. module Markdown # Provide autoload paths for filters to prevent a circular dependency error + autoload :AutolinkFilter, 'gitlab/markdown/autolink_filter' autoload :CommitRangeReferenceFilter, 'gitlab/markdown/commit_range_reference_filter' autoload :CommitReferenceFilter, 'gitlab/markdown/commit_reference_filter' autoload :EmojiFilter, 'gitlab/markdown/emoji_filter' @@ -37,7 +14,9 @@ module Gitlab autoload :IssueReferenceFilter, 'gitlab/markdown/issue_reference_filter' autoload :LabelReferenceFilter, 'gitlab/markdown/label_reference_filter' autoload :MergeRequestReferenceFilter, 'gitlab/markdown/merge_request_reference_filter' + autoload :SanitizationFilter, 'gitlab/markdown/sanitization_filter' autoload :SnippetReferenceFilter, 'gitlab/markdown/snippet_reference_filter' + autoload :TableOfContentsFilter, 'gitlab/markdown/table_of_contents_filter' autoload :UserReferenceFilter, 'gitlab/markdown/user_reference_filter' # Public: Parse the provided text with GitLab-Flavored Markdown @@ -74,13 +53,13 @@ module Gitlab pipeline = HTML::Pipeline.new(filters) context = { - # SanitizationFilter - whitelist: sanitization_whitelist, - # EmojiFilter asset_root: Gitlab.config.gitlab.url, asset_host: Gitlab::Application.config.asset_host, + # TableOfContentsFilter + no_header_anchors: options[:no_header_anchors], + # ReferenceFilter current_user: current_user, only_path: options[:reference_only_path], @@ -111,12 +90,14 @@ module Gitlab # SanitizationFilter should come first so that all generated reference HTML # goes through untouched. # - # See https://gitlab.com/gitlab-org/html-pipeline-gitlab for more filters + # See https://github.com/jch/html-pipeline#filters for more filters. def filters [ - HTML::Pipeline::SanitizationFilter, + Gitlab::Markdown::SanitizationFilter, Gitlab::Markdown::EmojiFilter, + Gitlab::Markdown::TableOfContentsFilter, + Gitlab::Markdown::AutolinkFilter, Gitlab::Markdown::UserReferenceFilter, Gitlab::Markdown::IssueReferenceFilter, @@ -125,36 +106,10 @@ module Gitlab Gitlab::Markdown::SnippetReferenceFilter, Gitlab::Markdown::CommitRangeReferenceFilter, Gitlab::Markdown::CommitReferenceFilter, - Gitlab::Markdown::LabelReferenceFilter, + Gitlab::Markdown::LabelReferenceFilter ] end - # Customize the SanitizationFilter whitelist - # - # - Allow `class` and `id` attributes on all elements - # - Allow `span` elements - # - Remove `rel` attributes from `a` elements - # - Remove `a` nodes with `javascript:` in the `href` attribute - def sanitization_whitelist - whitelist = HTML::Pipeline::SanitizationFilter::WHITELIST - whitelist[:attributes][:all].push('class', 'id') - whitelist[:elements].push('span') - - fix_anchors = lambda do |env| - name, node = env[:node_name], env[:node] - if name == 'a' - node.remove_attribute('rel') - if node['href'] && node['href'].match('javascript:') - node.remove_attribute('href') - end - end - end - - whitelist[:transformers].push(fix_anchors) - - whitelist - end - # Turn list items that start with "[ ]" into HTML checkbox inputs. def parse_tasks(text) li_tag = '
  • ' diff --git a/lib/gitlab/markdown/autolink_filter.rb b/lib/gitlab/markdown/autolink_filter.rb new file mode 100644 index 0000000000..4e14a048cf --- /dev/null +++ b/lib/gitlab/markdown/autolink_filter.rb @@ -0,0 +1,100 @@ +require 'html/pipeline/filter' +require 'uri' + +module Gitlab + module Markdown + # HTML Filter for auto-linking URLs in HTML. + # + # Based on HTML::Pipeline::AutolinkFilter + # + # Context options: + # :autolink - Boolean, skips all processing done by this filter when false + # :link_attr - Hash of attributes for the generated links + # + class AutolinkFilter < HTML::Pipeline::Filter + include ActionView::Helpers::TagHelper + + # Pattern to match text that should be autolinked. + # + # A URI scheme begins with a letter and may contain letters, numbers, + # plus, period and hyphen. Schemes are case-insensitive but we're being + # picky here and allowing only lowercase for autolinks. + # + # See http://en.wikipedia.org/wiki/URI_scheme + # + # The negative lookbehind ensures that users can paste a URL followed by a + # period or comma for punctuation without those characters being included + # in the generated link. + # + # Rubular: http://rubular.com/r/cxjPyZc7Sb + LINK_PATTERN = %r{([a-z][a-z0-9\+\.-]+://\S+)(?#{project_ref}##{issue}) + class="#{klass}">#{project_ref}##{id}) else match end @@ -68,10 +67,6 @@ module Gitlab def url_for_issue(*args) IssuesHelper.url_for_issue(*args) end - - def title_for_issue(*args) - IssuesHelper.title_for_issue(*args) - end end end end diff --git a/lib/gitlab/markdown/merge_request_reference_filter.rb b/lib/gitlab/markdown/merge_request_reference_filter.rb index 7c28fe112e..740d72abb3 100644 --- a/lib/gitlab/markdown/merge_request_reference_filter.rb +++ b/lib/gitlab/markdown/merge_request_reference_filter.rb @@ -64,7 +64,6 @@ module Gitlab end end - # TODO (rspeicher): Cleanup def url_for_merge_request(mr, project) h = Rails.application.routes.url_helpers h.namespace_project_merge_request_url(project.namespace, project, mr, diff --git a/lib/gitlab/markdown/sanitization_filter.rb b/lib/gitlab/markdown/sanitization_filter.rb new file mode 100644 index 0000000000..9a154e0b2f --- /dev/null +++ b/lib/gitlab/markdown/sanitization_filter.rb @@ -0,0 +1,38 @@ +require 'html/pipeline/filter' +require 'html/pipeline/sanitization_filter' + +module Gitlab + module Markdown + # Sanitize HTML + # + # Extends HTML::Pipeline::SanitizationFilter with a custom whitelist. + class SanitizationFilter < HTML::Pipeline::SanitizationFilter + def whitelist + whitelist = HTML::Pipeline::SanitizationFilter::WHITELIST + + # Allow `class` and `id` on all elements + whitelist[:attributes][:all].push('class', 'id') + + # Allow table alignment + whitelist[:attributes]['th'] = %w(style) + whitelist[:attributes]['td'] = %w(style) + + # Allow span elements + whitelist[:elements].push('span') + + # Remove `rel` attribute from `a` elements + whitelist[:transformers].push(remove_rel) + + whitelist + end + + def remove_rel + lambda do |env| + if env[:node_name] == 'a' + env[:node].remove_attribute('rel') + end + end + end + end + end +end diff --git a/lib/gitlab/markdown/table_of_contents_filter.rb b/lib/gitlab/markdown/table_of_contents_filter.rb new file mode 100644 index 0000000000..c97612dafb --- /dev/null +++ b/lib/gitlab/markdown/table_of_contents_filter.rb @@ -0,0 +1,62 @@ +require 'html/pipeline/filter' + +module Gitlab + module Markdown + # HTML filter that adds an anchor child element to all Headers in a + # document, so that they can be linked to. + # + # Generates the Table of Contents with links to each header. See Results. + # + # Based on HTML::Pipeline::TableOfContentsFilter. + # + # Context options: + # :no_header_anchors - Skips all processing done by this filter. + # + # Results: + # :toc - String containing Table of Contents data as a `ul` element with + # `li` child elements. + class TableOfContentsFilter < HTML::Pipeline::Filter + PUNCTUATION_REGEXP = /[^\p{Word}\- ]/u + + def call + return doc if context[:no_header_anchors] + + result[:toc] = "" + + headers = Hash.new(0) + + doc.css('h1, h2, h3, h4, h5, h6').each do |node| + text = node.text + + id = text.downcase + id.gsub!(PUNCTUATION_REGEXP, '') # remove punctuation + id.gsub!(' ', '-') # replace spaces with dash + id.squeeze!(' -') # replace multiple spaces or dashes with one + + uniq = (headers[id] > 0) ? "-#{headers[id]}" : '' + headers[id] += 1 + + if header_content = node.children.first + href = "#{id}#{uniq}" + push_toc(href, text) + header_content.add_previous_sibling(anchor_tag(href)) + end + end + + result[:toc] = %Q{
      \n#{result[:toc]}
    } unless result[:toc].empty? + + doc + end + + private + + def anchor_tag(href) + %Q{} + end + + def push_toc(href, text) + result[:toc] << %Q{
  • #{text}
  • \n} + end + end + end +end diff --git a/lib/gitlab/o_auth/auth_hash.rb b/lib/gitlab/o_auth/auth_hash.rb index ce52beec78..0f16c92590 100644 --- a/lib/gitlab/o_auth/auth_hash.rb +++ b/lib/gitlab/o_auth/auth_hash.rb @@ -9,11 +9,11 @@ module Gitlab end def uid - auth_hash.uid.to_s + Gitlab::Utils.force_utf8(auth_hash.uid.to_s) end def provider - auth_hash.provider + Gitlab::Utils.force_utf8(auth_hash.provider.to_s) end def info @@ -21,23 +21,28 @@ module Gitlab end def name - (info.try(:name) || full_name).to_s.force_encoding('utf-8') + Gitlab::Utils.force_utf8((info.try(:name) || full_name).to_s) end def full_name - "#{info.first_name} #{info.last_name}" + Gitlab::Utils.force_utf8("#{info.first_name} #{info.last_name}") end def username - (info.try(:nickname) || generate_username).to_s.force_encoding('utf-8') + Gitlab::Utils.force_utf8( + (info.try(:nickname) || generate_username).to_s + ) end def email - (info.try(:email) || generate_temporarily_email).downcase + Gitlab::Utils.force_utf8( + (info.try(:email) || generate_temporarily_email).downcase + ) end def password - @password ||= Devise.friendly_token[0, 8].downcase + devise_friendly_token = Devise.friendly_token[0, 8].downcase + @password ||= Gitlab::Utils.force_utf8(devise_friendly_token) end # Get the first part of the email address (before @) diff --git a/lib/gitlab/regex.rb b/lib/gitlab/regex.rb index 0571574aa4..9f1adc860d 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/gitlab/theme.rb b/lib/gitlab/theme.rb index f0e61aa2e8..e5a1f1b44d 100644 --- a/lib/gitlab/theme.rb +++ b/lib/gitlab/theme.rb @@ -40,7 +40,7 @@ module Gitlab end # Convenience method to get a space-separated String of all the theme - # classes that mighty be applied to the `body` element + # classes that might be applied to the `body` element # # Returns a String def self.body_classes diff --git a/lib/gitlab/utils.rb b/lib/gitlab/utils.rb index bd184c2718..d13fe0ef8a 100644 --- a/lib/gitlab/utils.rb +++ b/lib/gitlab/utils.rb @@ -9,5 +9,9 @@ module Gitlab def system_silent(cmd) Popen::popen(cmd).last.zero? end + + def force_utf8(str) + str.force_encoding(Encoding::UTF_8) + end end end diff --git a/lib/redcarpet/render/gitlab_html.rb b/lib/redcarpet/render/gitlab_html.rb index 10efff2ae9..bea66e6cdc 100644 --- a/lib/redcarpet/render/gitlab_html.rb +++ b/lib/redcarpet/render/gitlab_html.rb @@ -1,5 +1,6 @@ -class Redcarpet::Render::GitlabHTML < Redcarpet::Render::HTML +require 'active_support/core_ext/string/output_safety' +class Redcarpet::Render::GitlabHTML < Redcarpet::Render::HTML attr_reader :template alias_method :h, :template @@ -8,24 +9,12 @@ class Redcarpet::Render::GitlabHTML < Redcarpet::Render::HTML @color_scheme = color_scheme @project = @template.instance_variable_get("@project") @options = options.dup - super options + + super(options) end - def preprocess(full_document) - # Redcarpet doesn't allow SMB links when `safe_links_only` is enabled. - # FTP links are allowed, so we trick Redcarpet. - full_document.gsub("smb://", "ftp://smb:") - end - - # If project has issue number 39, apostrophe will be linked in - # regular text to the issue as Redcarpet will convert apostrophe to - # #39; - # We replace apostrophe with right single quote before Redcarpet - # does the processing and put the apostrophe back in postprocessing. - # This only influences regular text, code blocks are untouched. def normal_text(text) - return text unless text.present? - text.gsub("'", "’") + ERB::Util.html_escape_once(text) end # Stolen from Rugments::Plugins::Redcarpet as this module is not required @@ -37,7 +26,7 @@ class Redcarpet::Render::GitlabHTML < Redcarpet::Render::HTML # so we assume you're not using leading spaces that aren't tabs, # and just replace them here. if lexer.tag == 'make' - code.gsub! /^ /, "\t" + code.gsub!(/^ /, "\t") end formatter = Rugments::Formatters::HTML.new( @@ -46,27 +35,11 @@ class Redcarpet::Render::GitlabHTML < Redcarpet::Render::HTML formatter.format(lexer.lex(code)) end - def link(link, title, content) - h.link_to_gfm(content, link, title: title) - end - - def header(text, level) - if @options[:no_header_anchors] - "#{text}" - else - id = ActionController::Base.helpers.strip_tags(h.gfm(text)).downcase() \ - .gsub(/[^a-z0-9_-]/, '-').gsub(/-+/, '-').gsub(/^-/, '').gsub(/-$/, '') - "#{text}" - end - end - def postprocess(full_document) - full_document.gsub!("ftp://smb:", "smb://") - - full_document.gsub!("’", "'") unless @template.instance_variable_get("@project_wiki") || @project.nil? full_document = h.create_relative_links(full_document) end + h.gfm_with_options(full_document, @options) end end diff --git a/lib/tasks/dev.rake b/lib/tasks/dev.rake index 058c741704..b22c631c8b 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/controllers/import/google_code_controller_spec.rb b/spec/controllers/import/google_code_controller_spec.rb index 037cddb460..78c0f5079c 100644 --- a/spec/controllers/import/google_code_controller_spec.rb +++ b/spec/controllers/import/google_code_controller_spec.rb @@ -27,21 +27,34 @@ describe Import::GoogleCodeController do it "assigns variables" do @project = create(:project, import_type: 'google_code', creator_id: user.id) controller.stub_chain(:client, :repos).and_return([@repo]) + controller.stub_chain(:client, :incompatible_repos).and_return([]) get :status expect(assigns(:already_added_projects)).to eq([@project]) expect(assigns(:repos)).to eq([@repo]) + expect(assigns(:incompatible_repos)).to eq([]) end it "does not show already added project" do @project = create(:project, import_type: 'google_code', creator_id: user.id, import_source: 'vim') controller.stub_chain(:client, :repos).and_return([@repo]) + controller.stub_chain(:client, :incompatible_repos).and_return([]) get :status expect(assigns(:already_added_projects)).to eq([@project]) expect(assigns(:repos)).to eq([]) end + + it "does not show any invalid projects" do + controller.stub_chain(:client, :repos).and_return([]) + controller.stub_chain(:client, :incompatible_repos).and_return([@repo]) + + get :status + + expect(assigns(:repos)).to be_empty + expect(assigns(:incompatible_repos)).to eq([@repo]) + end end end diff --git a/spec/controllers/merge_requests_controller_spec.rb b/spec/controllers/merge_requests_controller_spec.rb index d6f56ed33d..c94ef1629a 100644 --- a/spec/controllers/merge_requests_controller_spec.rb +++ b/spec/controllers/merge_requests_controller_spec.rb @@ -78,4 +78,24 @@ describe Projects::MergeRequestsController do end end end + + context '#diffs with forked projects with submodules' do + render_views + let(:project) { create(:project) } + let(:fork_project) { create(:forked_project_with_submodules) } + let(:merge_request) { create(:merge_request_with_diffs, source_project: fork_project, source_branch: 'add-submodule-version-bump', target_branch: 'master', target_project: project) } + + before do + fork_project.build_forked_project_link(forked_to_project_id: fork_project.id, forked_from_project_id: project.id) + fork_project.save + merge_request.reload + end + + it '#diffs' do + get(:diffs, namespace_id: project.namespace.to_param, + project_id: project.to_param, id: merge_request.iid, format: 'json') + expect(response).to be_success + expect(response.body).to have_content('Subproject commit') + end + end end diff --git a/spec/controllers/projects/compare_controller_spec.rb b/spec/controllers/projects/compare_controller_spec.rb new file mode 100644 index 0000000000..23e1566b8f --- /dev/null +++ b/spec/controllers/projects/compare_controller_spec.rb @@ -0,0 +1,22 @@ +require 'spec_helper' + +describe Projects::CompareController do + let(:project) { create(:project) } + let(:user) { create(:user) } + let(:ref_from) { "improve%2Fawesome" } + let(:ref_to) { "feature" } + + before do + sign_in(user) + project.team << [user, :master] + end + + it 'compare should show some diffs' do + get(:show, namespace_id: project.namespace.to_param, + project_id: project.to_param, from: ref_from, to: ref_to) + + expect(response).to be_success + expect(assigns(:diffs).length).to be >= 1 + expect(assigns(:commits).length).to be >= 1 + end +end diff --git a/spec/factories.rb b/spec/factories.rb index 759a502a97..a73ea193cf 100644 --- a/spec/factories.rb +++ b/spec/factories.rb @@ -22,6 +22,7 @@ FactoryGirl.define do password "12345678" confirmed_at { Time.now } confirmation_token { nil } + can_create_group true trait :admin do admin true diff --git a/spec/factories/projects.rb b/spec/factories/projects.rb index 1f58d430ed..102678a1d7 100644 --- a/spec/factories/projects.rb +++ b/spec/factories/projects.rb @@ -76,6 +76,14 @@ FactoryGirl.define do end end + factory :forked_project_with_submodules, parent: :empty_project do + path { 'forked-gitlabhq' } + + after :create do |project| + TestEnv.copy_forked_repo_with_submodules(project) + end + end + factory :redmine_project, parent: :project do after :create do |project| project.create_redmine_service( @@ -86,8 +94,7 @@ FactoryGirl.define do 'new_issue_url' => 'http://redmine/projects/project_name_in_redmine/issues/new' } ) - end - after :create do |project| + project.issues_tracker = 'redmine' project.issues_tracker_id = 'project_name_in_redmine' end diff --git a/spec/features/issues_spec.rb b/spec/features/issues_spec.rb index e217f0739d..66d73b2505 100644 --- a/spec/features/issues_spec.rb +++ b/spec/features/issues_spec.rb @@ -95,7 +95,7 @@ describe 'Issues', feature: true do let(:issue) { @issue } it 'should allow filtering by issues with no specified milestone' do - visit namespace_project_issues_path(project.namespace, project, milestone_id: IssuableFinder::NONE) + visit namespace_project_issues_path(project.namespace, project, milestone_title: IssuableFinder::NONE) expect(page).not_to have_content 'foobar' expect(page).to have_content 'barbaz' @@ -103,7 +103,7 @@ describe 'Issues', feature: true do end it 'should allow filtering by a specified milestone' do - visit namespace_project_issues_path(project.namespace, project, milestone_id: issue.milestone.id) + visit namespace_project_issues_path(project.namespace, project, milestone_title: issue.milestone.title) expect(page).to have_content 'foobar' expect(page).not_to have_content 'barbaz' diff --git a/spec/features/markdown_spec.rb b/spec/features/markdown_spec.rb new file mode 100644 index 0000000000..3528200e12 --- /dev/null +++ b/spec/features/markdown_spec.rb @@ -0,0 +1,391 @@ +require 'spec_helper' +require 'erb' + +# This feature spec is intended to be a comprehensive exercising of all of +# GitLab's non-standard Markdown parsing and the integration thereof. +# +# These tests should be very high-level. Anything low-level belongs in the specs +# for the corresponding HTML::Pipeline filter or helper method. +# +# The idea is to pass a Markdown document through our entire processing stack. +# +# The process looks like this: +# +# Raw Markdown +# -> `markdown` helper +# -> Redcarpet::Render::GitlabHTML converts Markdown to HTML +# -> Post-process HTML +# -> `gfm_with_options` helper +# -> HTML::Pipeline +# -> Sanitize +# -> Emoji +# -> Table of Contents +# -> Autolinks +# -> Rinku (http, https, ftp) +# -> Other schemes +# -> References +# -> `html_safe` +# -> Template +# +# See the MarkdownFeature class for setup details. + +describe 'GitLab Markdown' do + include ActionView::Helpers::TagHelper + include ActionView::Helpers::UrlHelper + include Capybara::Node::Matchers + include GitlabMarkdownHelper + + # `markdown` calls these two methods + def current_user + @feat.user + end + + def user_color_scheme_class + :white + end + + # Let's only parse this thing once + before(:all) do + @feat = MarkdownFeature.new + + # `markdown` expects a `@project` variable + @project = @feat.project + + @md = markdown(@feat.raw_markdown) + @doc = Nokogiri::HTML::DocumentFragment.parse(@md) + end + + after(:all) do + @feat.teardown + end + + # Given a header ID, goes to that element's parent (the header), then to its + # second sibling (the body). + def get_section(id) + @doc.at_css("##{id}").parent.next.next + end + + # it 'writes to a file' do + # File.open(Rails.root.join('tmp/capybara/markdown_spec.html'), 'w') do |file| + # file.puts @md + # end + # end + + describe 'Markdown' do + describe 'No Intra Emphasis' do + it 'does not parse emphasis inside of words' do + body = get_section('no-intra-emphasis') + expect(body.to_html).not_to match('foobarbaz') + end + end + + describe 'Tables' do + it 'parses table Markdown' do + body = get_section('tables') + expect(body).to have_selector('th:contains("Header")') + expect(body).to have_selector('th:contains("Row")') + expect(body).to have_selector('th:contains("Example")') + end + + it 'allows Markdown in tables' do + expect(@doc.at_css('td:contains("Baz")').children.to_html). + to eq 'Baz' + end + end + + describe 'Fenced Code Blocks' do + it 'parses fenced code blocks' do + expect(@doc).to have_selector('pre.code.highlight.white.c') + expect(@doc).to have_selector('pre.code.highlight.white.python') + end + end + + describe 'Strikethrough' do + it 'parses strikethroughs' do + expect(@doc).to have_selector(%{del:contains("and this text doesn't")}) + end + end + + describe 'Superscript' do + it 'parses superscript' do + body = get_section('superscript') + expect(body.to_html).to match('1st') + expect(body.to_html).to match('2nd') + end + end + end + + describe 'HTML::Pipeline' do + describe 'SanitizationFilter' do + it 'uses a permissive whitelist' do + expect(@doc).to have_selector('b#manual-b') + expect(@doc).to have_selector('em#manual-em') + expect(@doc).to have_selector("code#manual-code") + expect(@doc).to have_selector('kbd:contains("s")') + expect(@doc).to have_selector('strike:contains(Emoji)') + expect(@doc).to have_selector('img#manual-img') + expect(@doc).to have_selector('br#manual-br') + expect(@doc).to have_selector('hr#manual-hr') + end + + it 'permits span elements' do + expect(@doc).to have_selector('span#span-class-light.light') + end + + it 'permits table alignment' do + expect(@doc.at_css('th:contains("Header")')['style']).to eq 'text-align: center' + expect(@doc.at_css('th:contains("Row")')['style']).to eq 'text-align: right' + expect(@doc.at_css('th:contains("Example")')['style']).to eq 'text-align: left' + + expect(@doc.at_css('td:contains("Foo")')['style']).to eq 'text-align: center' + expect(@doc.at_css('td:contains("Bar")')['style']).to eq 'text-align: right' + expect(@doc.at_css('td:contains("Baz")')['style']).to eq 'text-align: left' + end + + it 'removes `rel` attribute from links' do + expect(@doc).to have_selector('a#a-rel-nofollow') + expect(@doc).not_to have_selector('a#a-rel-nofollow[rel]') + end + + it "removes `href` from `a` elements if it's fishy" do + expect(@doc).to have_selector('a#a-href-javascript') + expect(@doc).not_to have_selector('a#a-href-javascript[href]') + end + end + + describe 'Escaping' do + let(:table) { @doc.css('table').last.at_css('tbody') } + + it 'escapes non-tag angle brackets' do + expect(table.at_xpath('.//tr[1]/td[3]').inner_html).to eq '1 < 3 & 5' + end + end + + describe 'EmojiFilter' do + it 'parses Emoji' do + expect(@doc).to have_selector('img.emoji', count: 10) + end + end + + describe 'TableOfContentsFilter' do + it 'creates anchors inside header elements' do + expect(@doc).to have_selector('h1 a#gitlab-markdown') + expect(@doc).to have_selector('h2 a#markdown') + expect(@doc).to have_selector('h3 a#autolinkfilter') + end + end + + describe 'AutolinkFilter' do + let(:list) { get_section('autolinkfilter').parent.search('ul') } + + def item(index) + list.at_css("li:nth-child(#{index})") + end + + it 'autolinks http://' do + expect(item(1).children.first.name).to eq 'a' + expect(item(1).children.first['href']).to eq 'http://about.gitlab.com/' + end + + it 'autolinks https://' do + expect(item(2).children.first.name).to eq 'a' + expect(item(2).children.first['href']).to eq 'https://google.com/' + end + + it 'autolinks ftp://' do + expect(item(3).children.first.name).to eq 'a' + expect(item(3).children.first['href']).to eq 'ftp://ftp.us.debian.org/debian/' + end + + it 'autolinks smb://' do + expect(item(4).children.first.name).to eq 'a' + expect(item(4).children.first['href']).to eq 'smb://foo/bar/baz' + end + + it 'autolinks irc://' do + expect(item(5).children.first.name).to eq 'a' + expect(item(5).children.first['href']).to eq 'irc://irc.freenode.net/git' + end + + it 'autolinks short, invalid URLs' do + expect(item(6).children.first.name).to eq 'a' + expect(item(6).children.first['href']).to eq 'http://localhost:3000' + end + + %w(code a kbd).each do |elem| + it "ignores links inside '#{elem}' element" do + expect(@doc.at_css("#{elem}#autolink-#{elem}").child).to be_text + end + end + end + + describe 'ReferenceFilter' do + it 'handles references in headers' do + header = @doc.at_css('#reference-filters-eg-1').parent + + expect(header.css('a').size).to eq 2 + end + + it "handles references in Markdown" do + body = get_section('reference-filters-eg-1') + expect(body).to have_selector('em a.gfm-merge_request', count: 1) + end + + it 'parses user references' do + body = get_section('userreferencefilter') + expect(body).to have_selector('a.gfm.gfm-project_member', count: 3) + end + + it 'parses issue references' do + body = get_section('issuereferencefilter') + expect(body).to have_selector('a.gfm.gfm-issue', count: 2) + end + + it 'parses merge request references' do + body = get_section('mergerequestreferencefilter') + expect(body).to have_selector('a.gfm.gfm-merge_request', count: 2) + end + + it 'parses snippet references' do + body = get_section('snippetreferencefilter') + expect(body).to have_selector('a.gfm.gfm-snippet', count: 2) + end + + it 'parses commit range references' do + body = get_section('commitrangereferencefilter') + expect(body).to have_selector('a.gfm.gfm-commit_range', count: 2) + end + + it 'parses commit references' do + body = get_section('commitreferencefilter') + expect(body).to have_selector('a.gfm.gfm-commit', count: 2) + end + + it 'parses label references' do + body = get_section('labelreferencefilter') + expect(body).to have_selector('a.gfm.gfm-label', count: 3) + end + end + end +end + +# This is a helper class used by the GitLab Markdown feature spec +# +# Because the feature spec only cares about the output of the Markdown, and the +# test setup and teardown and parsing is fairly expensive, we only want to do it +# once. Unfortunately RSpec will not let you access `let`s in a `before(:all)` +# block, so we fake it by encapsulating all the shared setup in this class. +# +# The class contains the raw Markup used in the test, dynamically substituting +# real objects, created from factories and setup on-demand, when referenced in +# the Markdown. +class MarkdownFeature + include FactoryGirl::Syntax::Methods + + def initialize + DatabaseCleaner.start + end + + def teardown + DatabaseCleaner.clean + end + + def user + @user ||= create(:user) + end + + def group + unless @group + @group = create(:group) + @group.add_user(user, Gitlab::Access::DEVELOPER) + end + + @group + end + + # Direct references ---------------------------------------------------------- + + def project + @project ||= create(:project) + end + + def issue + @issue ||= create(:issue, project: project) + end + + def merge_request + @merge_request ||= create(:merge_request, :simple, source_project: project) + end + + def snippet + @snippet ||= create(:project_snippet, project: project) + end + + def commit + @commit ||= project.repository.commit + end + + def commit_range + unless @commit_range + commit2 = project.repository.commit('HEAD~3') + @commit_range = CommitRange.new("#{commit.id}...#{commit2.id}") + end + + @commit_range + end + + def simple_label + @simple_label ||= create(:label, name: 'gfm', project: project) + end + + def label + @label ||= create(:label, name: 'awaiting feedback', project: project) + end + + # Cross-references ----------------------------------------------------------- + + def xproject + unless @xproject + namespace = create(:namespace, name: 'cross-reference') + @xproject = create(:project, namespace: namespace) + @xproject.team << [user, :developer] + end + + @xproject + end + + # Shortcut to "cross-reference/project" + def xref + xproject.path_with_namespace + end + + def xissue + @xissue ||= create(:issue, project: xproject) + end + + def xmerge_request + @xmerge_request ||= create(:merge_request, :simple, source_project: xproject) + end + + def xsnippet + @xsnippet ||= create(:project_snippet, project: xproject) + end + + def xcommit + @xcommit ||= xproject.repository.commit + end + + def xcommit_range + unless @xcommit_range + xcommit2 = xproject.repository.commit('HEAD~2') + @xcommit_range = CommitRange.new("#{xcommit.id}...#{xcommit2.id}") + end + + @xcommit_range + end + + def raw_markdown + fixture = Rails.root.join('spec/fixtures/markdown.md.erb') + ERB.new(File.read(fixture)).result(binding) + end +end diff --git a/spec/features/users_spec.rb b/spec/features/users_spec.rb index 4cfaab03ca..93d2b18b5f 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/finders/issues_finder_spec.rb b/spec/finders/issues_finder_spec.rb index 479fa95038..69bac387d2 100644 --- a/spec/finders/issues_finder_spec.rb +++ b/spec/finders/issues_finder_spec.rb @@ -43,7 +43,7 @@ describe IssuesFinder do end it 'should filter by milestone id' do - params = { scope: "all", milestone_id: milestone.id, state: 'opened' } + params = { scope: "all", milestone_title: milestone.title, state: 'opened' } issues = IssuesFinder.new.execute(user, params) expect(issues).to eq([issue1]) end diff --git a/spec/fixtures/markdown.md.erb b/spec/fixtures/markdown.md.erb new file mode 100644 index 0000000000..0c14075855 --- /dev/null +++ b/spec/fixtures/markdown.md.erb @@ -0,0 +1,178 @@ +# GitLab Markdown + +This document is intended to be a comprehensive example of custom GitLab +Markdown usage. It will be parsed and then tested for accuracy. Let's get +started. + +## Markdown + +GitLab uses [Redcarpet](http://git.io/ld_NVQ) to parse all Markdown into +HTML. + +It has some special features. Let's try 'em out! + +### No Intra Emphasis + +This string should have no emphasis: foo_bar_baz + +### Tables + +| Header | Row | Example | +| :------: | ---: | :------ | +| Foo | Bar | **Baz** | + +### Fenced Code Blocks + +```c +#include + +main() +{ + printf("Hello World"); + +} +``` + +```python +print "Hello, World!" +``` + +### Strikethrough + +This text says this, ~~and this text doesn't~~. + +### Superscript + +This is my 1^(st) time using superscript in Markdown. Now this is my +2^(nd). + +### Next step + +After the Markdown has been turned into HTML, it gets passed through... + +## HTML::Pipeline + +### SanitizationFilter + +GitLab uses HTML::Pipeline::SanitizationFilter +to sanitize the generated HTML, stripping dangerous or unwanted tags. + +Its default whitelist is pretty permissive. Check it: + +This text is bold and this text is emphasized. + +echo "Hello, world!" + +Press s to search. + +Emoji Plain old images! + +Here comes a line break: + +
    + +And a horizontal rule: + +
    + +As permissive as it is, we've allowed even more stuff: + +Span elements + +This is a link with a defined rel attribute, which should be removed + +This is a link trying to be sneaky. It gets its link removed entirely. + +### Escaping + +The problem with SanitizationFilter is that it can be too aggressive. + +| Input | Expected | Actual | +| ----------- | ---------------- | --------- | +| `1 < 3 & 5` | 1 < 3 & 5 | 1 < 3 & 5 | +| `` | <foo> | | + +### EmojiFilter + +Because life would be :zzz: without Emoji, right? :rocket: + +Get ready for the Emoji :bomb:: :+1::-1::ok_hand::wave::v::raised_hand::muscle: + +### TableOfContentsFilter + +All headers in this document should be linkable. Try it. + +### AutolinkFilter + +These are all plain text that should get turned into links: + +- http://about.gitlab.com/ +- https://google.com/ +- ftp://ftp.us.debian.org/debian/ +- smb://foo/bar/baz +- irc://irc.freenode.net/git +- http://localhost:3000 + +But it shouldn't autolink text inside certain tags: + +- http://about.gitlab.com/ +- http://about.gitlab.com/ +- http://about.gitlab.com/ + +### Reference Filters (e.g., #<%= issue.iid %>) + +References should be parseable even inside _!<%= merge_request.iid %>_ emphasis. + +#### UserReferenceFilter + +- All: @all +- User: @<%= user.username %> +- Group: @<%= group.name %> +- Ignores invalid: @fake_user +- Ignored in code: `@<%= user.username %>` +- Ignored in links: [Link to @<%= user.username %>](#user-link) + +#### IssueReferenceFilter + +- Issue: #<%= issue.iid %> +- Issue in another project: <%= xref %>#<%= xissue.iid %> +- Ignored in code: `#<%= issue.iid %>` +- Ignored in links: [Link to #<%= issue.iid %>](#issue-link) + +#### MergeRequestReferenceFilter + +- Merge request: !<%= merge_request.iid %> +- Merge request in another project: <%= xref %>!<%= xmerge_request.iid %> +- Ignored in code: `!<%= merge_request.iid %>` +- Ignored in links: [Link to !<%= merge_request.iid %>](#merge-request-link) + +#### SnippetReferenceFilter + +- Snippet: $<%= snippet.id %> +- Snippet in another project: <%= xref %>$<%= xsnippet.id %> +- Ignored in code: `$<%= snippet.id %>` +- Ignored in links: [Link to $<%= snippet.id %>](#snippet-link) + +#### CommitRangeReferenceFilter + +- Range: <%= commit_range %> +- Range in another project: <%= xref %>@<%= xcommit_range %> +- Ignored in code: `<%= commit_range %>` +- Ignored in links: [Link to <%= commit_range %>](#commit-range-link) + +#### CommitReferenceFilter + +- Commit: <%= commit.id %> +- Commit in another project: <%= xref %>@<%= xcommit.id %> +- Ignored in code: `<%= commit.id %>` +- Ignored in links: [Link to <%= commit.id %>](#commit-link) + +#### LabelReferenceFilter + +- Label by ID: ~<%= simple_label.id %> +- Label by name: ~<%= simple_label.name %> +- Label by name in quotes: ~"<%= label.name %>" +- Ignored in code: `~<%= simple_label.name %>` +- Ignored in links: [Link to ~<%= simple_label.id %>](#label-link) diff --git a/spec/helpers/gitlab_markdown_helper_spec.rb b/spec/helpers/gitlab_markdown_helper_spec.rb index e309dbb6a2..b6be82e410 100644 --- a/spec/helpers/gitlab_markdown_helper_spec.rb +++ b/spec/helpers/gitlab_markdown_helper_spec.rb @@ -107,8 +107,7 @@ describe GitlabMarkdownHelper do end it 'should not be confused by whitespace before bullets' do - rendered_text_asterisk = markdown(@source_text_asterisk, - parse_tasks: true) + rendered_text_asterisk = markdown(@source_text_asterisk, parse_tasks: true) rendered_text_dash = markdown(@source_text_dash, parse_tasks: true) expect(rendered_text_asterisk).to match( @@ -207,78 +206,7 @@ describe GitlabMarkdownHelper do end describe "#markdown" do - # TODO (rspeicher) - This block tests multiple different contexts. Break this up! - - it "should add ids and links to headers" do - # Test every rule except nested tags. - text = '..Ab_c-d. e..' - id = 'ab_c-d-e' - expect(markdown("# #{text}")). - to match(%r{

    #{text}

    }) - expect(markdown("# #{text}", {no_header_anchors:true})). - to eq("

    #{text}

    ") - - id = 'link-text' - expect(markdown("# [link text](url) ![img alt](url)")).to match( - %r{

    link text ]*>

    } - ) - end - - # REFERENCES (PART TWO: THE REVENGE) --------------------------------------- - - it "should handle references in headers" do - actual = "\n# Working around ##{issue.iid}\n## Apply !#{merge_request.iid}" - - expect(markdown(actual, no_header_anchors: true)). - to match(%r{Working around ##{issue.iid}}) - expect(markdown(actual, no_header_anchors: true)). - to match(%r{Apply !#{merge_request.iid}}) - end - - it "should handle references in " do - actual = "Apply _!#{merge_request.iid}_ ASAP" - - expect(markdown(actual)). - to match(%r{Apply !#{merge_request.iid}}) - end - - # CODE BLOCKS ------------------------------------------------------------- - - it "should leave code blocks untouched" do - allow(helper).to receive(:current_user).and_return(user) - allow(helper).to receive(:user_color_scheme_class).and_return(:white) - - target_html = "
    some code from $#{snippet.id}\nhere too\n
    \n" - - expect(markdown("\n some code from $#{snippet.id}\n here too\n")). - to eq(target_html) - expect(markdown("\n```\nsome code from $#{snippet.id}\nhere too\n```\n")). - to eq(target_html) - end - - it "should leave inline code untouched" do - expect(markdown("Don't use `$#{snippet.id}` here.")). - to eq "

    Don't use $#{snippet.id} here.

    \n" - end - - # REF-LIKE AUTOLINKS? ----------------------------------------------------- - # Basically: Don't parse references inside `` tags. - - it "should leave ref-like autolinks untouched" do - expect(markdown("look at http://example.tld/#!#{merge_request.iid}")).to eq("

    look at http://example.tld/#!#{merge_request.iid}

    \n") - end - - it "should leave ref-like href of 'manual' links untouched" do - expect(markdown("why not [inspect !#{merge_request.iid}](http://example.tld/#!#{merge_request.iid})")).to eq("

    why not inspect !#{merge_request.iid}

    \n") - end - - it "should leave ref-like src of images untouched" do - expect(markdown("screen shot: ![some image](http://example.tld/#!#{merge_request.iid})")).to eq("

    screen shot: \"some

    \n") - end - - # RELATIVE URLS ----------------------------------------------------------- # TODO (rspeicher): These belong in a relative link filter spec - context 'relative links' do context 'with a valid repository' do before do @@ -333,11 +261,6 @@ describe GitlabMarkdownHelper do expected = "" expect(markdown(actual)).to match(expected) end - - it 'should allow whitelisted HTML tags from the user' do - actual = '
    Term
    Definition
    ' - expect(markdown(actual)).to match(actual) - end end context 'with an empty repository' do @@ -353,34 +276,6 @@ describe GitlabMarkdownHelper do end end end - - # SANITIZATION ------------------------------------------------------------ - # TODO (rspeicher): These are testing SanitizationFilter, not `markdown` - - it 'should sanitize tags that are not whitelisted' do - actual = ' no blinks' - expected = 'no inputs allowed no blinks' - expect(markdown(actual)).to match(expected) - expect(markdown(actual)).not_to match('<.textarea>') - expect(markdown(actual)).not_to match('<.blink>') - end - - it 'should allow whitelisted tag attributes from the user' do - actual = 'link text' - expect(markdown(actual)).to match(actual) - end - - it 'should sanitize tag attributes that are not whitelisted' do - actual = 'link text' - expected = 'link text' - expect(markdown(actual)).to match(expected) - end - - it 'should sanitize javascript in attributes' do - actual = %q(link text) - expected = 'link text' - expect(markdown(actual)).to match(expected) - end end describe '#render_wiki_content' do diff --git a/spec/helpers/issues_helper_spec.rb b/spec/helpers/issues_helper_spec.rb index 54dd8d4aa6..c08ddb4cae 100644 --- a/spec/helpers/issues_helper_spec.rb +++ b/spec/helpers/issues_helper_spec.rb @@ -5,24 +5,6 @@ describe IssuesHelper do let(:issue) { create :issue, project: project } let(:ext_project) { create :redmine_project } - describe "title_for_issue" do - it "should return issue title if used internal tracker" do - @project = project - expect(title_for_issue(issue.iid)).to eq issue.title - end - - it "should always return empty string if used external tracker" do - @project = ext_project - expect(title_for_issue(rand(100))).to eq "" - end - - it "should always return empty string if project nil" do - @project = nil - - expect(title_for_issue(rand(100))).to eq "" - end - end - describe "url_for_project_issues" do let(:project_url) { ext_project.external_issue_tracker.project_url } let(:ext_expected) do diff --git a/spec/helpers/submodule_helper_spec.rb b/spec/helpers/submodule_helper_spec.rb index e99c3f5bc1..e98b75afab 100644 --- a/spec/helpers/submodule_helper_spec.rb +++ b/spec/helpers/submodule_helper_spec.rb @@ -117,34 +117,41 @@ describe SubmoduleHelper do context 'submodules with relative links' do let(:group) { create(:group) } let(:project) { create(:project, group: group) } + let(:commit_id) { sample_commit[:id] } before do self.instance_variable_set(:@project, project) end it 'one level down' do - commit_id = sample_commit[:id] result = relative_self_links('../test.git', commit_id) expect(result).to eq(["/#{group.path}/test", "/#{group.path}/test/tree/#{commit_id}"]) end it 'two levels down' do - commit_id = sample_commit[:id] result = relative_self_links('../../test.git', commit_id) expect(result).to eq(["/#{group.path}/test", "/#{group.path}/test/tree/#{commit_id}"]) end it 'one level down with namespace and repo' do - commit_id = sample_commit[:id] result = relative_self_links('../foobar/test.git', commit_id) expect(result).to eq(["/foobar/test", "/foobar/test/tree/#{commit_id}"]) end it 'two levels down with namespace and repo' do - commit_id = sample_commit[:id] result = relative_self_links('../foobar/baz/test.git', commit_id) expect(result).to eq(["/baz/test", "/baz/test/tree/#{commit_id}"]) end + + context 'personal project' do + let(:user) { create(:user) } + let(:project) { create(:project, namespace: user.namespace) } + + it 'one level down with personal project' do + result = relative_self_links('../test.git', commit_id) + expect(result).to eq(["/#{user.username}/test", "/#{user.username}/test/tree/#{commit_id}"]) + end + end end end diff --git a/spec/lib/extracts_path_spec.rb b/spec/lib/extracts_path_spec.rb index ac602eac15..05bcebaa3a 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/google_code_import/client_spec.rb b/spec/lib/gitlab/google_code_import/client_spec.rb index d2bf871daa..a66b811e0f 100644 --- a/spec/lib/gitlab/google_code_import/client_spec.rb +++ b/spec/lib/gitlab/google_code_import/client_spec.rb @@ -23,6 +23,7 @@ describe Gitlab::GoogleCodeImport::Client do describe "#repos" do it "returns only Git repositories" do expect(subject.repos.length).to eq(1) + expect(subject.incompatible_repos.length).to eq(1) end end diff --git a/spec/lib/gitlab/markdown/autolink_filter_spec.rb b/spec/lib/gitlab/markdown/autolink_filter_spec.rb new file mode 100644 index 0000000000..0bbdc11a97 --- /dev/null +++ b/spec/lib/gitlab/markdown/autolink_filter_spec.rb @@ -0,0 +1,106 @@ +require 'spec_helper' + +module Gitlab::Markdown + describe AutolinkFilter do + let(:link) { 'http://about.gitlab.com/' } + + def filter(html, options = {}) + described_class.call(html, options) + end + + it 'does nothing when :autolink is false' do + exp = act = link + expect(filter(act, autolink: false).to_html).to eq exp + end + + it 'does nothing with non-link text' do + exp = act = 'This text contains no links to autolink' + expect(filter(act).to_html).to eq exp + end + + context 'Rinku schemes' do + it 'autolinks http' do + doc = filter("See #{link}") + expect(doc.at_css('a').text).to eq link + expect(doc.at_css('a')['href']).to eq link + end + + it 'autolinks https' do + link = 'https://google.com/' + doc = filter("See #{link}") + + expect(doc.at_css('a').text).to eq link + expect(doc.at_css('a')['href']).to eq link + end + + it 'autolinks ftp' do + link = 'ftp://ftp.us.debian.org/debian/' + doc = filter("See #{link}") + + expect(doc.at_css('a').text).to eq link + expect(doc.at_css('a')['href']).to eq link + end + + it 'autolinks short URLs' do + link = 'http://localhost:3000/' + doc = filter("See #{link}") + + expect(doc.at_css('a').text).to eq link + expect(doc.at_css('a')['href']).to eq link + end + + it 'accepts link_attr options' do + doc = filter("See #{link}", link_attr: {class: 'custom'}) + + expect(doc.at_css('a')['class']).to eq 'custom' + end + + described_class::IGNORE_PARENTS.each do |elem| + it "ignores valid links contained inside '#{elem}' element" do + exp = act = "<#{elem}>See #{link}" + expect(filter(act).to_html).to eq exp + end + end + end + + context 'other schemes' do + let(:link) { 'foo://bar.baz/' } + + it 'autolinks smb' do + link = 'smb:///Volumes/shared/foo.pdf' + doc = filter("See #{link}") + + expect(doc.at_css('a').text).to eq link + expect(doc.at_css('a')['href']).to eq link + end + + it 'autolinks irc' do + link = 'irc://irc.freenode.net/git' + doc = filter("See #{link}") + + expect(doc.at_css('a').text).to eq link + expect(doc.at_css('a')['href']).to eq link + end + + it 'does not include trailing punctuation' do + doc = filter("See #{link}.") + expect(doc.at_css('a').text).to eq link + + doc = filter("See #{link}, ok?") + expect(doc.at_css('a').text).to eq link + end + + it 'accepts link_attr options' do + doc = filter("See #{link}", link_attr: {class: 'custom'}) + expect(doc.at_css('a')['class']).to eq 'custom' + end + + described_class::IGNORE_PARENTS.each do |elem| + it "ignores valid links contained inside '#{elem}' element" do + exp = act = "<#{elem}>See #{link}" + expect(filter(act).to_html).to eq exp + end + end + end + end +end diff --git a/spec/lib/gitlab/markdown/issue_reference_filter_spec.rb b/spec/lib/gitlab/markdown/issue_reference_filter_spec.rb index 393bf32e19..08382b3e7e 100644 --- a/spec/lib/gitlab/markdown/issue_reference_filter_spec.rb +++ b/spec/lib/gitlab/markdown/issue_reference_filter_spec.rb @@ -27,7 +27,7 @@ module Gitlab::Markdown let(:reference) { "##{issue.iid}" } it 'ignores valid references when using non-default tracker' do - expect(project).to receive(:issue_exists?).with(issue.iid).and_return(false) + expect(project).to receive(:get_issue).with(issue.iid).and_return(nil) exp = act = "Issue ##{issue.iid}" expect(filter(act).to_html).to eq exp @@ -48,7 +48,7 @@ module Gitlab::Markdown it 'ignores invalid issue IDs' do exp = act = "Fixed ##{issue.iid + 1}" - expect(project).to receive(:issue_exists?).with(issue.iid + 1) + expect(project).to receive(:get_issue).with(issue.iid + 1).and_return(nil) expect(filter(act).to_html).to eq exp end @@ -98,8 +98,8 @@ module Gitlab::Markdown before { allow_cross_reference! } it 'ignores valid references when cross-reference project uses external tracker' do - expect_any_instance_of(Project).to receive(:issue_exists?). - with(issue.iid).and_return(false) + expect_any_instance_of(Project).to receive(:get_issue). + with(issue.iid).and_return(nil) exp = act = "Issue ##{issue.iid}" expect(filter(act).to_html).to eq exp diff --git a/spec/lib/gitlab/markdown/sanitization_filter_spec.rb b/spec/lib/gitlab/markdown/sanitization_filter_spec.rb new file mode 100644 index 0000000000..ab909a6863 --- /dev/null +++ b/spec/lib/gitlab/markdown/sanitization_filter_spec.rb @@ -0,0 +1,81 @@ +require 'spec_helper' + +module Gitlab::Markdown + describe SanitizationFilter do + def filter(html, options = {}) + described_class.call(html, options) + end + + describe 'default whitelist' do + it 'sanitizes tags that are not whitelisted' do + act = %q{ and no blinks} + exp = 'no inputs and no blinks' + expect(filter(act).to_html).to eq exp + end + + it 'sanitizes tag attributes' do + act = %q{Text} + exp = %q{Text} + expect(filter(act).to_html).to eq exp + end + + it 'sanitizes javascript in attributes' do + act = %q(Text) + exp = 'Text' + expect(filter(act).to_html).to eq exp + end + + it 'allows whitelisted HTML tags from the user' do + exp = act = "
    \n
    Term
    \n
    Definition
    \n
    " + expect(filter(act).to_html).to eq exp + end + end + + describe 'custom whitelist' do + it 'allows `class` attribute on any element' do + exp = act = %q{Strong} + expect(filter(act).to_html).to eq exp + end + + it 'allows `id` attribute on any element' do + exp = act = %q{Emphasis} + expect(filter(act).to_html).to eq exp + end + + it 'allows `style` attribute on table elements' do + html = <<-HTML.strip_heredoc + + + +
    Head
    Body
    + HTML + + doc = filter(html) + + expect(doc.at_css('th')['style']).to eq 'text-align: center' + expect(doc.at_css('td')['style']).to eq 'text-align: right' + end + + it 'allows `span` elements' do + exp = act = %q{Hello} + expect(filter(act).to_html).to eq exp + end + + it 'removes `rel` attribute from `a` elements' do + doc = filter(%q{Link}) + + expect(doc.css('a').size).to eq 1 + expect(doc.at_css('a')['href']).to eq '#' + expect(doc.at_css('a')['rel']).to be_nil + end + + it 'removes script-like `href` attribute from `a` elements' do + html = %q{Hi} + doc = filter(html) + + expect(doc.css('a').size).to eq 1 + expect(doc.at_css('a')['href']).to be_nil + end + end + end +end diff --git a/spec/lib/gitlab/markdown/table_of_contents_filter_spec.rb b/spec/lib/gitlab/markdown/table_of_contents_filter_spec.rb new file mode 100644 index 0000000000..f383a5850d --- /dev/null +++ b/spec/lib/gitlab/markdown/table_of_contents_filter_spec.rb @@ -0,0 +1,101 @@ +# encoding: UTF-8 + +require 'spec_helper' + +module Gitlab::Markdown + describe TableOfContentsFilter do + def filter(html, options = {}) + described_class.call(html, options) + end + + def header(level, text) + "#{text}\n" + end + + it 'does nothing when :no_header_anchors is truthy' do + exp = act = header(1, 'Header') + expect(filter(act, no_header_anchors: 1).to_html).to eq exp + end + + it 'does nothing with empty headers' do + exp = act = header(1, nil) + expect(filter(act).to_html).to eq exp + end + + 1.upto(6) do |i| + it "processes h#{i} elements" do + html = header(i, "Header #{i}") + doc = filter(html) + + expect(doc.css("h#{i} a").first.attr('id')).to eq "header-#{i}" + end + end + + describe 'anchor tag' do + it 'has an `anchor` class' do + doc = filter(header(1, 'Header')) + expect(doc.css('h1 a').first.attr('class')).to eq 'anchor' + end + + it 'links to the id' do + doc = filter(header(1, 'Header')) + expect(doc.css('h1 a').first.attr('href')).to eq '#header' + end + + describe 'generated IDs' do + it 'translates spaces to dashes' do + doc = filter(header(1, 'This header has spaces in it')) + expect(doc.css('h1 a').first.attr('id')).to eq 'this-header-has-spaces-in-it' + end + + it 'squeezes multiple spaces and dashes' do + doc = filter(header(1, 'This---header is poorly-formatted')) + expect(doc.css('h1 a').first.attr('id')).to eq 'this-header-is-poorly-formatted' + end + + it 'removes punctuation' do + doc = filter(header(1, "This, header! is, filled. with @ punctuation?")) + expect(doc.css('h1 a').first.attr('id')).to eq 'this-header-is-filled-with-punctuation' + end + + it 'appends a unique number to duplicates' do + doc = filter(header(1, 'One') + header(2, 'One')) + + expect(doc.css('h1 a').first.attr('id')).to eq 'one' + expect(doc.css('h2 a').first.attr('id')).to eq 'one-1' + end + + it 'supports Unicode' do + doc = filter(header(1, '한글')) + expect(doc.css('h1 a').first.attr('id')).to eq '한글' + expect(doc.css('h1 a').first.attr('href')).to eq '#한글' + end + end + end + + describe 'result' do + def result(html) + HTML::Pipeline.new([described_class]).call(html) + end + + let(:results) { result(header(1, 'Header 1') + header(2, 'Header 2')) } + let(:doc) { Nokogiri::XML::DocumentFragment.parse(results[:toc]) } + + it 'is contained within a `ul` element' do + expect(doc.children.first.name).to eq 'ul' + expect(doc.children.first.attr('class')).to eq 'section-nav' + end + + it 'contains an `li` element for each header' do + expect(doc.css('li').length).to eq 2 + + links = doc.css('li a') + + expect(links.first.attr('href')).to eq '#header-1' + expect(links.first.text).to eq 'Header 1' + expect(links.last.attr('href')).to eq '#header-2' + expect(links.last.text).to eq 'Header 2' + end + end + end +end diff --git a/spec/lib/gitlab/o_auth/auth_hash_spec.rb b/spec/lib/gitlab/o_auth/auth_hash_spec.rb index 5eb77b492b..678086ffa1 100644 --- a/spec/lib/gitlab/o_auth/auth_hash_spec.rb +++ b/spec/lib/gitlab/o_auth/auth_hash_spec.rb @@ -2,54 +2,109 @@ require 'spec_helper' describe Gitlab::OAuth::AuthHash do let(:auth_hash) do - Gitlab::OAuth::AuthHash.new(double({ - provider: 'twitter', - uid: uid, - info: double(info_hash) - })) + Gitlab::OAuth::AuthHash.new( + double({ + provider: provider_ascii, + uid: uid_ascii, + info: double(info_hash) + }) + ) end - let(:uid) { 'my-uid' } - let(:email) { 'my-email@example.com' } - let(:nickname) { 'my-nickname' } + + let(:uid_raw) { + "CN=Onur K\xC3\xBC\xC3\xA7\xC3\xBCk,OU=Test,DC=example,DC=net" + } + let(:email_raw) { "onur.k\xC3\xBC\xC3\xA7\xC3\xBCk@example.net" } + let(:nickname_raw) { "ok\xC3\xBC\xC3\xA7\xC3\xBCk" } + let(:first_name_raw) { 'Onur' } + let(:last_name_raw) { "K\xC3\xBC\xC3\xA7\xC3\xBCk" } + let(:name_raw) { "Onur K\xC3\xBC\xC3\xA7\xC3\xBCk" } + + let(:provider_ascii) { 'ldap'.force_encoding(Encoding::ASCII_8BIT) } + let(:uid_ascii) { uid_raw.force_encoding(Encoding::ASCII_8BIT) } + let(:email_ascii) { email_raw.force_encoding(Encoding::ASCII_8BIT) } + let(:nickname_ascii) { nickname_raw.force_encoding(Encoding::ASCII_8BIT) } + let(:first_name_ascii) { first_name_raw.force_encoding(Encoding::ASCII_8BIT) } + let(:last_name_ascii) { last_name_raw.force_encoding(Encoding::ASCII_8BIT) } + let(:name_ascii) { name_raw.force_encoding(Encoding::ASCII_8BIT) } + + let(:provider_utf8) { provider_ascii.force_encoding(Encoding::UTF_8) } + let(:uid_utf8) { uid_ascii.force_encoding(Encoding::UTF_8) } + let(:email_utf8) { email_ascii.force_encoding(Encoding::UTF_8) } + let(:nickname_utf8) { nickname_ascii.force_encoding(Encoding::UTF_8) } + let(:name_utf8) { name_ascii.force_encoding(Encoding::UTF_8) } + let(:info_hash) { { - email: email, - nickname: nickname, - name: 'John', - first_name: "John", - last_name: "Who" + email: email_ascii, + first_name: first_name_ascii, + last_name: last_name_ascii, + name: name_ascii, + nickname: nickname_ascii, + uid: uid_ascii } } - context "defaults" do - it { expect(auth_hash.provider).to eql 'twitter' } - it { expect(auth_hash.uid).to eql uid } - it { expect(auth_hash.email).to eql email } - it { expect(auth_hash.username).to eql nickname } - it { expect(auth_hash.name).to eql "John" } + context 'defaults' do + it { expect(auth_hash.provider).to eql provider_utf8 } + it { expect(auth_hash.uid).to eql uid_utf8 } + it { expect(auth_hash.email).to eql email_utf8 } + it { expect(auth_hash.username).to eql nickname_utf8 } + it { expect(auth_hash.name).to eql name_utf8 } it { expect(auth_hash.password).to_not be_empty } end - context "email not provided" do + context 'email not provided' do before { info_hash.delete(:email) } - it "generates a temp email" do + + it 'generates a temp email' do expect( auth_hash.email).to start_with('temp-email-for-oauth') end end - context "username not provided" do + context 'username not provided' do before { info_hash.delete(:nickname) } - it "takes the first part of the email as username" do - expect( auth_hash.username ).to eql "my-email" + it 'takes the first part of the email as username' do + expect(auth_hash.username).to eql 'onur-kucuk' end end - context "name not provided" do + context 'name not provided' do before { info_hash.delete(:name) } - it "concats first and lastname as the name" do - expect( auth_hash.name ).to eql "John Who" + it 'concats first and lastname as the name' do + expect(auth_hash.name).to eql name_utf8 end end -end \ No newline at end of file + + context 'auth_hash constructed with ASCII-8BIT encoding' do + it 'forces utf8 encoding on uid' do + auth_hash.uid.encoding.should eql Encoding::UTF_8 + end + + it 'forces utf8 encoding on provider' do + auth_hash.provider.encoding.should eql Encoding::UTF_8 + end + + it 'forces utf8 encoding on name' do + auth_hash.name.encoding.should eql Encoding::UTF_8 + end + + it 'forces utf8 encoding on full_name' do + auth_hash.full_name.encoding.should eql Encoding::UTF_8 + end + + it 'forces utf8 encoding on username' do + auth_hash.username.encoding.should eql Encoding::UTF_8 + end + + it 'forces utf8 encoding on email' do + auth_hash.email.encoding.should eql Encoding::UTF_8 + end + + it 'forces utf8 encoding on password' do + auth_hash.password.encoding.should eql Encoding::UTF_8 + end + end +end diff --git a/spec/lib/gitlab/regex_spec.rb b/spec/lib/gitlab/regex_spec.rb index 727884c41c..7fdc8fa600 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/mailers/notify_spec.rb b/spec/mailers/notify_spec.rb index faa7ea7abe..51d0d9d7ab 100644 --- a/spec/mailers/notify_spec.rb +++ b/spec/mailers/notify_spec.rb @@ -11,9 +11,8 @@ describe Notify do let(:recipient) { create(:user, email: 'recipient@example.com') } let(:project) { create(:project) } - around(:each) { ActionMailer::Base.deliveries.clear } - before(:each) do + ActionMailer::Base.deliveries.clear email = recipient.emails.create(email: "notifications@example.com") recipient.update_attribute(:notification_email, email.email) end diff --git a/spec/models/application_setting_spec.rb b/spec/models/application_setting_spec.rb index b4f0b2c201..116c318121 100644 --- a/spec/models/application_setting_spec.rb +++ b/spec/models/application_setting_spec.rb @@ -4,7 +4,6 @@ # # id :integer not null, primary key # default_projects_limit :integer -# default_branch_protection :integer # signup_enabled :boolean # signin_enabled :boolean # gravatar_enabled :boolean @@ -15,10 +14,38 @@ # default_branch_protection :integer default(2) # twitter_sharing_enabled :boolean default(TRUE) # restricted_visibility_levels :text +# max_attachment_size :integer default(10), not null +# default_project_visibility :integer +# default_snippet_visibility :integer +# restricted_signup_domains :text # require 'spec_helper' describe ApplicationSetting, models: true do it { expect(ApplicationSetting.create_from_defaults).to be_valid } + + context 'restricted signup domains' do + let(:setting) { ApplicationSetting.create_from_defaults } + + it 'set single domain' do + setting.restricted_signup_domains_raw = 'example.com' + expect(setting.restricted_signup_domains).to eq(['example.com']) + end + + it 'set multiple domains with spaces' do + setting.restricted_signup_domains_raw = 'example.com *.example.com' + expect(setting.restricted_signup_domains).to eq(['example.com', '*.example.com']) + end + + it 'set multiple domains with newlines and a space' do + setting.restricted_signup_domains_raw = "example.com\n *.example.com" + expect(setting.restricted_signup_domains).to eq(['example.com', '*.example.com']) + end + + it 'set multiple domains with commas' do + setting.restricted_signup_domains_raw = "example.com, *.example.com" + expect(setting.restricted_signup_domains).to eq(['example.com', '*.example.com']) + end + end end diff --git a/spec/models/deploy_key_spec.rb b/spec/models/deploy_key_spec.rb index b32be8d7a7..9572993245 100644 --- a/spec/models/deploy_key_spec.rb +++ b/spec/models/deploy_key_spec.rb @@ -10,6 +10,7 @@ # title :string(255) # type :string(255) # fingerprint :string(255) +# public :boolean default(FALSE), not null # require 'spec_helper' diff --git a/spec/models/external_wiki_service_spec.rb b/spec/models/external_wiki_service_spec.rb index 78ef687d29..f2e77fc88c 100644 --- a/spec/models/external_wiki_service_spec.rb +++ b/spec/models/external_wiki_service_spec.rb @@ -1,3 +1,23 @@ +# == Schema Information +# +# Table name: services +# +# id :integer not null, primary key +# type :string(255) +# title :string(255) +# project_id :integer +# created_at :datetime +# updated_at :datetime +# active :boolean default(FALSE), not null +# properties :text +# template :boolean default(FALSE) +# push_events :boolean default(TRUE) +# issues_events :boolean default(TRUE) +# merge_requests_events :boolean default(TRUE) +# tag_push_events :boolean default(TRUE) +# note_events :boolean default(TRUE), not null +# + require 'spec_helper' describe ExternalWikiService do diff --git a/spec/models/hooks/web_hook_spec.rb b/spec/models/hooks/web_hook_spec.rb index 14f873e6b5..67ec9193ad 100644 --- a/spec/models/hooks/web_hook_spec.rb +++ b/spec/models/hooks/web_hook_spec.rb @@ -52,26 +52,22 @@ describe ProjectHook do end it "POSTs to the web hook URL" do - @project_hook.execute(@data, 'push_hooks') - expect(WebMock).to have_requested(:post, @project_hook.url). - with(headers: {'Content-Type'=>'application/json', 'X-Gitlab-Event'=>'Push Hook'}). - once + @project_hook.execute(@data) + expect(WebMock).to have_requested(:post, @project_hook.url).once end it "POSTs the data as JSON" do json = @data.to_json - @project_hook.execute(@data, 'push_hooks') - expect(WebMock).to have_requested(:post, @project_hook.url). - with(headers: {'Content-Type'=>'application/json', 'X-Gitlab-Event'=>'Push Hook'}). - once + @project_hook.execute(@data) + expect(WebMock).to have_requested(:post, @project_hook.url).with(body: json).once end it "catches exceptions" do expect(WebHook).to receive(:post).and_raise("Some HTTP Post error") expect { - @project_hook.execute(@data, 'push_hooks') + @project_hook.execute(@data) }.to raise_error end end diff --git a/spec/models/key_spec.rb b/spec/models/key_spec.rb index 2fb651bef1..6eb1208a7f 100644 --- a/spec/models/key_spec.rb +++ b/spec/models/key_spec.rb @@ -10,6 +10,7 @@ # title :string(255) # type :string(255) # fingerprint :string(255) +# public :boolean default(FALSE), not null # require 'spec_helper' diff --git a/spec/models/member_spec.rb b/spec/models/member_spec.rb index 56d030a03b..57f840c1e9 100644 --- a/spec/models/member_spec.rb +++ b/spec/models/member_spec.rb @@ -1,3 +1,22 @@ +# == Schema Information +# +# Table name: members +# +# id :integer not null, primary key +# access_level :integer not null +# source_id :integer not null +# source_type :string(255) not null +# user_id :integer +# notification_level :integer not null +# type :string(255) +# created_at :datetime +# updated_at :datetime +# created_by_id :integer +# invite_email :string(255) +# invite_token :string(255) +# invite_accepted_at :datetime +# + require 'spec_helper' describe Member do diff --git a/spec/models/members/group_member_spec.rb b/spec/models/members/group_member_spec.rb index e206c11f33..7c10c9f0f4 100644 --- a/spec/models/members/group_member_spec.rb +++ b/spec/models/members/group_member_spec.rb @@ -6,11 +6,15 @@ # access_level :integer not null # source_id :integer not null # source_type :string(255) not null -# user_id :integer not null +# user_id :integer # notification_level :integer not null # type :string(255) # created_at :datetime # updated_at :datetime +# created_by_id :integer +# invite_email :string(255) +# invite_token :string(255) +# invite_accepted_at :datetime # require 'spec_helper' diff --git a/spec/models/members/project_member_spec.rb b/spec/models/members/project_member_spec.rb index 521721f357..5c72cfe1d6 100644 --- a/spec/models/members/project_member_spec.rb +++ b/spec/models/members/project_member_spec.rb @@ -6,11 +6,15 @@ # access_level :integer not null # source_id :integer not null # source_type :string(255) not null -# user_id :integer not null +# user_id :integer # notification_level :integer not null # type :string(255) # created_at :datetime # updated_at :datetime +# created_by_id :integer +# invite_email :string(255) +# invite_token :string(255) +# invite_accepted_at :datetime # require 'spec_helper' diff --git a/spec/models/merge_request_spec.rb b/spec/models/merge_request_spec.rb index 15284a97f7..aff2d5ad8a 100644 --- a/spec/models/merge_request_spec.rb +++ b/spec/models/merge_request_spec.rb @@ -126,6 +126,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/models/project_services/asana_service_spec.rb b/spec/models/project_services/asana_service_spec.rb index 13c8d54a2a..cc1f99e0c7 100644 --- a/spec/models/project_services/asana_service_spec.rb +++ b/spec/models/project_services/asana_service_spec.rb @@ -15,6 +15,7 @@ # issues_events :boolean default(TRUE) # merge_requests_events :boolean default(TRUE) # tag_push_events :boolean default(TRUE) +# note_events :boolean default(TRUE), not null # require 'spec_helper' diff --git a/spec/models/project_services/assembla_service_spec.rb b/spec/models/project_services/assembla_service_spec.rb index 91730da1ee..9aee754dd6 100644 --- a/spec/models/project_services/assembla_service_spec.rb +++ b/spec/models/project_services/assembla_service_spec.rb @@ -15,6 +15,7 @@ # issues_events :boolean default(TRUE) # merge_requests_events :boolean default(TRUE) # tag_push_events :boolean default(TRUE) +# note_events :boolean default(TRUE), not null # require 'spec_helper' diff --git a/spec/models/project_services/buildkite_service_spec.rb b/spec/models/project_services/buildkite_service_spec.rb index e987241f3c..6db54243ea 100644 --- a/spec/models/project_services/buildkite_service_spec.rb +++ b/spec/models/project_services/buildkite_service_spec.rb @@ -15,6 +15,7 @@ # issues_events :boolean default(TRUE) # merge_requests_events :boolean default(TRUE) # tag_push_events :boolean default(TRUE) +# note_events :boolean default(TRUE), not null # require 'spec_helper' diff --git a/spec/models/project_services/flowdock_service_spec.rb b/spec/models/project_services/flowdock_service_spec.rb index 73f68301a3..e6e8fbba6a 100644 --- a/spec/models/project_services/flowdock_service_spec.rb +++ b/spec/models/project_services/flowdock_service_spec.rb @@ -15,6 +15,7 @@ # issues_events :boolean default(TRUE) # merge_requests_events :boolean default(TRUE) # tag_push_events :boolean default(TRUE) +# note_events :boolean default(TRUE), not null # require 'spec_helper' diff --git a/spec/models/project_services/gemnasium_service_spec.rb b/spec/models/project_services/gemnasium_service_spec.rb index d44064bbe6..1a7765e5c2 100644 --- a/spec/models/project_services/gemnasium_service_spec.rb +++ b/spec/models/project_services/gemnasium_service_spec.rb @@ -15,6 +15,7 @@ # issues_events :boolean default(TRUE) # merge_requests_events :boolean default(TRUE) # tag_push_events :boolean default(TRUE) +# note_events :boolean default(TRUE), not null # require 'spec_helper' diff --git a/spec/models/project_services/gitlab_ci_service_spec.rb b/spec/models/project_services/gitlab_ci_service_spec.rb index 6a557d839c..afacd4afaf 100644 --- a/spec/models/project_services/gitlab_ci_service_spec.rb +++ b/spec/models/project_services/gitlab_ci_service_spec.rb @@ -15,6 +15,7 @@ # issues_events :boolean default(TRUE) # merge_requests_events :boolean default(TRUE) # tag_push_events :boolean default(TRUE) +# note_events :boolean default(TRUE), not null # require 'spec_helper' diff --git a/spec/models/project_services/gitlab_issue_tracker_service_spec.rb b/spec/models/project_services/gitlab_issue_tracker_service_spec.rb index f94bef5c36..e34ca09bff 100644 --- a/spec/models/project_services/gitlab_issue_tracker_service_spec.rb +++ b/spec/models/project_services/gitlab_issue_tracker_service_spec.rb @@ -15,6 +15,7 @@ # issues_events :boolean default(TRUE) # merge_requests_events :boolean default(TRUE) # tag_push_events :boolean default(TRUE) +# note_events :boolean default(TRUE), not null # require 'spec_helper' diff --git a/spec/models/project_services/hipchat_service_spec.rb b/spec/models/project_services/hipchat_service_spec.rb index 348f83c56a..bbaf54488b 100644 --- a/spec/models/project_services/hipchat_service_spec.rb +++ b/spec/models/project_services/hipchat_service_spec.rb @@ -5,15 +5,17 @@ # id :integer not null, primary key # type :string(255) # title :string(255) -# project_id :integer not null +# project_id :integer # created_at :datetime # updated_at :datetime # active :boolean default(FALSE), not null # properties :text +# template :boolean default(FALSE) # push_events :boolean default(TRUE) # issues_events :boolean default(TRUE) # merge_requests_events :boolean default(TRUE) # tag_push_events :boolean default(TRUE) +# note_events :boolean default(TRUE), not null # require 'spec_helper' diff --git a/spec/models/project_services/irker_service_spec.rb b/spec/models/project_services/irker_service_spec.rb index d55399bc36..49face26bb 100644 --- a/spec/models/project_services/irker_service_spec.rb +++ b/spec/models/project_services/irker_service_spec.rb @@ -15,6 +15,7 @@ # issues_events :boolean default(TRUE) # merge_requests_events :boolean default(TRUE) # tag_push_events :boolean default(TRUE) +# note_events :boolean default(TRUE), not null # require 'spec_helper' diff --git a/spec/models/project_services/jira_service_spec.rb b/spec/models/project_services/jira_service_spec.rb index 6ebff9f21b..b0a826b37f 100644 --- a/spec/models/project_services/jira_service_spec.rb +++ b/spec/models/project_services/jira_service_spec.rb @@ -15,6 +15,7 @@ # issues_events :boolean default(TRUE) # merge_requests_events :boolean default(TRUE) # tag_push_events :boolean default(TRUE) +# note_events :boolean default(TRUE), not null # require 'spec_helper' diff --git a/spec/models/project_services/pushover_service_spec.rb b/spec/models/project_services/pushover_service_spec.rb index 5a18fd09bf..5f93703b50 100644 --- a/spec/models/project_services/pushover_service_spec.rb +++ b/spec/models/project_services/pushover_service_spec.rb @@ -15,6 +15,7 @@ # issues_events :boolean default(TRUE) # merge_requests_events :boolean default(TRUE) # tag_push_events :boolean default(TRUE) +# note_events :boolean default(TRUE), not null # require 'spec_helper' diff --git a/spec/models/project_services/slack_service_spec.rb b/spec/models/project_services/slack_service_spec.rb index c36506644b..e9105677d2 100644 --- a/spec/models/project_services/slack_service_spec.rb +++ b/spec/models/project_services/slack_service_spec.rb @@ -15,6 +15,7 @@ # issues_events :boolean default(TRUE) # merge_requests_events :boolean default(TRUE) # tag_push_events :boolean default(TRUE) +# note_events :boolean default(TRUE), not null # require 'spec_helper' diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb index 879a63dd9f..37e21a9081 100644 --- a/spec/models/project_spec.rb +++ b/spec/models/project_spec.rb @@ -129,6 +129,48 @@ describe Project do end end + describe '#get_issue' do + let(:project) { create(:empty_project) } + let(:issue) { create(:issue, project: project) } + + context 'with default issues tracker' do + it 'returns an issue' do + expect(project.get_issue(issue.iid)).to eq issue + end + + it 'returns nil when no issue found' do + expect(project.get_issue(999)).to be_nil + end + end + + context 'with external issues tracker' do + before do + allow(project).to receive(:default_issues_tracker?).and_return(false) + end + + it 'returns an ExternalIssue' do + issue = project.get_issue('FOO-1234') + expect(issue).to be_kind_of(ExternalIssue) + expect(issue.iid).to eq 'FOO-1234' + expect(issue.project).to eq project + end + end + end + + describe '#issue_exists?' do + let(:project) { create(:empty_project) } + + it 'is truthy when issue exists' do + expect(project).to receive(:get_issue).and_return(double) + expect(project.issue_exists?(1)).to be_truthy + end + + it 'is falsey when issue does not exist' do + expect(project).to receive(:get_issue).and_return(nil) + expect(project.issue_exists?(1)).to be_falsey + end + end + describe :update_merge_requests do let(:project) { create(:project) } let(:merge_request) { create(:merge_request, source_project: project, target_project: project) } @@ -180,25 +222,6 @@ describe Project do end end - describe :issue_exists? do - let(:project) { create(:project) } - let(:existed_issue) { create(:issue, project: project) } - let(:not_existed_issue) { create(:issue) } - let(:ext_project) { create(:redmine_project) } - - it 'should be true or if used internal tracker and issue exists' do - expect(project.issue_exists?(existed_issue.iid)).to be_truthy - end - - it 'should be false or if used internal tracker and issue not exists' do - expect(project.issue_exists?(not_existed_issue.iid)).to be_falsey - end - - it 'should always be true if used other tracker' do - expect(ext_project.issue_exists?(rand(100))).to be_truthy - end - end - describe :default_issues_tracker? do let(:project) { create(:project) } let(:ext_project) { create(:redmine_project) } diff --git a/spec/models/service_spec.rb b/spec/models/service_spec.rb index 633ead05b2..49cb340362 100644 --- a/spec/models/service_spec.rb +++ b/spec/models/service_spec.rb @@ -15,6 +15,7 @@ # issues_events :boolean default(TRUE) # merge_requests_events :boolean default(TRUE) # tag_push_events :boolean default(TRUE) +# note_events :boolean default(TRUE), not null # require 'spec_helper' diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb index 2ee185a69c..09331bf1de 100644 --- a/spec/models/user_spec.rb +++ b/spec/models/user_spec.rb @@ -49,11 +49,15 @@ # password_automatically_set :boolean default(FALSE) # bitbucket_access_token :string(255) # bitbucket_access_token_secret :string(255) +# location :string(255) +# public_email :string(255) default(""), not null # require 'spec_helper' describe User do + include Gitlab::CurrentSettings + describe "Associations" do it { is_expected.to have_one(:namespace) } it { is_expected.to have_many(:snippets).class_name('Snippet').dependent(:destroy) } @@ -112,6 +116,51 @@ describe User do user = build(:user, email: "lol!'+=?><#$%^&*()@gmail.com") expect(user).to be_invalid end + + context 'when no signup domains listed' do + before { allow(current_application_settings).to receive(:restricted_signup_domains).and_return([]) } + it 'accepts any email' do + user = build(:user, email: "info@example.com") + expect(user).to be_valid + end + end + + context 'when a signup domain is listed and subdomains are allowed' do + before { allow(current_application_settings).to receive(:restricted_signup_domains).and_return(['example.com', '*.example.com']) } + 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 'rejects example@test.com' do + user = build(:user, email: "example@test.com") + expect(user).to be_invalid + end + end + + context 'when a signup domain is listed and subdomains are not allowed' do + before { allow(current_application_settings).to receive(:restricted_signup_domains).and_return(['example.com']) } + + it 'accepts info@example.com' do + user = build(:user, email: "info@example.com") + expect(user).to be_valid + end + + it 'rejects info@test.example.com' do + user = build(:user, email: "info@test.example.com") + expect(user).to be_invalid + end + + it 'rejects example@test.com' do + user = build(:user, email: "example@test.com") + expect(user).to be_invalid + end + end end end diff --git a/spec/requests/api/groups_spec.rb b/spec/requests/api/groups_spec.rb index db46013b9f..53b729fb80 100644 --- a/spec/requests/api/groups_spec.rb +++ b/spec/requests/api/groups_spec.rb @@ -3,8 +3,9 @@ require 'spec_helper' describe API::API, api: true do include ApiHelpers - let(:user1) { create(:user) } + let(:user1) { create(:user, can_create_group: false) } let(:user2) { create(:user) } + let(:user3) { create(:user) } let(:admin) { create(:admin) } let!(:group1) { create(:group) } let!(:group2) { create(:group) } @@ -103,32 +104,32 @@ describe API::API, api: true do end describe "POST /groups" do - context "when authenticated as user" do + context "when authenticated as user without group permissions" do it "should not create group" do post api("/groups", user1), attributes_for(:group) expect(response.status).to eq(403) end end - context "when authenticated as admin" do + context "when authenticated as user with group permissions" do it "should create group" do - post api("/groups", admin), attributes_for(:group) + post api("/groups", user3), attributes_for(:group) expect(response.status).to eq(201) end it "should not create group, duplicate" do - post api("/groups", admin), {name: "Duplicate Test", path: group2.path} + post api("/groups", user3), {name: 'Duplicate Test', path: group2.path} expect(response.status).to eq(400) expect(response.message).to eq("Bad Request") end it "should return 400 bad request error if name not given" do - post api("/groups", admin), {path: group2.path} + post api("/groups", user3), {path: group2.path} expect(response.status).to eq(400) end it "should return 400 bad request error if path not given" do - post api("/groups", admin), { name: 'test' } + post api("/groups", user3), {name: 'test'} expect(response.status).to eq(400) end @@ -149,8 +150,8 @@ describe API::API, api: true do end it "should not remove a group if not an owner" do - user3 = create(:user) - group1.add_user(user3, Gitlab::Access::MASTER) + user4 = create(:user) + group1.add_user(user4, Gitlab::Access::MASTER) delete api("/groups/#{group1.id}", user3) expect(response.status).to eq(403) end diff --git a/spec/requests/api/issues_spec.rb b/spec/requests/api/issues_spec.rb index b6b0427deb..8770786f49 100644 --- a/spec/requests/api/issues_spec.rb +++ b/spec/requests/api/issues_spec.rb @@ -194,6 +194,14 @@ describe API::API, api: true do expect(json_response['iid']).to eq(issue.iid) end + it 'should return a project issue by iid' do + get api("/projects/#{project.id}/issues?iid=#{issue.iid}", user) + response.status.should == 200 + json_response.first['title'].should == issue.title + json_response.first['id'].should == issue.id + json_response.first['iid'].should == issue.iid + end + it "should return 404 if issue id not found" do get api("/projects/#{project.id}/issues/54321", user) expect(response.status).to eq(404) diff --git a/spec/requests/api/merge_requests_spec.rb b/spec/requests/api/merge_requests_spec.rb index 9e252441a4..dcd50f7332 100644 --- a/spec/requests/api/merge_requests_spec.rb +++ b/spec/requests/api/merge_requests_spec.rb @@ -115,6 +115,14 @@ describe API::API, api: true do expect(json_response['iid']).to eq(merge_request.iid) end + it 'should return merge_request by iid' do + url = "/projects/#{project.id}/merge_requests?iid=#{merge_request.iid}" + get api(url, user) + response.status.should == 200 + json_response.first['title'].should == merge_request.title + json_response.first['id'].should == merge_request.id + end + it "should return a 404 error if merge_request_id not found" do get api("/projects/#{project.id}/merge_request/999", user) expect(response.status).to eq(404) @@ -312,6 +320,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/requests/api/milestones_spec.rb b/spec/requests/api/milestones_spec.rb index effb072347..6890dd1f3a 100644 --- a/spec/requests/api/milestones_spec.rb +++ b/spec/requests/api/milestones_spec.rb @@ -30,6 +30,13 @@ describe API::API, api: true do expect(json_response['iid']).to eq(milestone.iid) end + it 'should return a project milestone by iid' do + get api("/projects/#{project.id}/milestones?iid=#{milestone.iid}", user) + response.status.should == 200 + json_response.first['title'].should == milestone.title + json_response.first['id'].should == milestone.id + end + it 'should return 401 error if user not authenticated' do get api("/projects/#{project.id}/milestones/#{milestone.id}") expect(response.status).to eq(401) diff --git a/spec/support/reference_filter_spec_helper.rb b/spec/support/reference_filter_spec_helper.rb index 4125381149..06c39e1ada 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 diff --git a/spec/support/test_env.rb b/spec/support/test_env.rb index 44d70e741b..6d4a806791 100644 --- a/spec/support/test_env.rb +++ b/spec/support/test_env.rb @@ -14,6 +14,10 @@ module TestEnv 'master' => '5937ac0' } + FORKED_BRANCH_SHA = BRANCH_SHA.merge({ + 'add-submodule-version-bump' => '3f547c08' + }) + # Test environment # # See gitlab.yml.example test section for paths @@ -31,6 +35,9 @@ module TestEnv # Create repository for FactoryGirl.create(:project) setup_factory_repo + + # Create repository for FactoryGirl.create(:forked_project_with_submodules) + setup_forked_repo end def disable_mailer @@ -48,7 +55,7 @@ module TestEnv tmp_test_path = Rails.root.join('tmp', 'tests', '**') Dir[tmp_test_path].each do |entry| - unless File.basename(entry) =~ /\Agitlab-(shell|test)\z/ + unless File.basename(entry) =~ /\Agitlab-(shell|test|test-fork)\z/ FileUtils.rm_rf(entry) end end @@ -61,14 +68,26 @@ module TestEnv end def setup_factory_repo - clone_url = "https://gitlab.com/gitlab-org/#{factory_repo_name}.git" + setup_repo(factory_repo_path, factory_repo_path_bare, factory_repo_name, + BRANCH_SHA) + end - unless File.directory?(factory_repo_path) - system(*%W(git clone -q #{clone_url} #{factory_repo_path})) + # This repo has a submodule commit that is not present in the main test + # repository. + def setup_forked_repo + setup_repo(forked_repo_path, forked_repo_path_bare, forked_repo_name, + FORKED_BRANCH_SHA) + end + + def setup_repo(repo_path, repo_path_bare, repo_name, branch_sha) + clone_url = "https://gitlab.com/gitlab-org/#{repo_name}.git" + + unless File.directory?(repo_path) + system(*%W(git clone -q #{clone_url} #{repo_path})) end - Dir.chdir(factory_repo_path) do - BRANCH_SHA.each do |branch, sha| + Dir.chdir(repo_path) do + branch_sha.each do |branch, sha| # Try to reset without fetching to avoid using the network. reset = %W(git update-ref refs/heads/#{branch} #{sha}) unless system(*reset) @@ -85,7 +104,7 @@ module TestEnv end # We must copy bare repositories because we will push to them. - system(git_env, *%W(git clone -q --bare #{factory_repo_path} #{factory_repo_path_bare})) + system(git_env, *%W(git clone -q --bare #{repo_path} #{repo_path_bare})) end def copy_repo(project) @@ -100,6 +119,14 @@ module TestEnv Gitlab.config.gitlab_shell.repos_path end + def copy_forked_repo_with_submodules(project) + base_repo_path = File.expand_path(forked_repo_path_bare) + target_repo_path = File.expand_path(repos_path + "/#{project.namespace.path}/#{project.path}.git") + FileUtils.mkdir_p(target_repo_path) + FileUtils.cp_r("#{base_repo_path}/.", target_repo_path) + FileUtils.chmod_R 0755, target_repo_path + end + private def factory_repo_path @@ -114,9 +141,22 @@ module TestEnv 'gitlab-test' end + def forked_repo_path + @forked_repo_path ||= Rails.root.join('tmp', 'tests', forked_repo_name) + end + + def forked_repo_path_bare + "#{forked_repo_path}_bare" + end + + def forked_repo_name + 'gitlab-test-fork' + end + + # Prevent developer git configurations from being persisted to test # repositories def git_env - {'GIT_TEMPLATE_DIR' => ''} + { 'GIT_TEMPLATE_DIR' => '' } end end