summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlfredo Sumaran <alfredo@gitlab.com>2016-02-29 12:04:45 -0500
committerAlfredo Sumaran <alfredo@gitlab.com>2016-02-29 12:04:45 -0500
commit4f529a88065b39a488814a87b08086be54a2037c (patch)
treeea6b59775427f5cd41adf825ed6103170a97bd41
parent45c29fa289bc27519a2fa076a155186d3ebf7b31 (diff)
parenteb9838d38bb38462b3f3f120c353817a4a09f6d6 (diff)
downloadgitlab-ce-issue_13212.tar.gz
Merge branch 'master' into issue_13212issue_13212
-rw-r--r--CHANGELOG9
-rw-r--r--Gemfile1
-rw-r--r--Gemfile.lock2
-rw-r--r--app/assets/javascripts/application.js.coffee2
-rw-r--r--app/assets/javascripts/logo.js.coffee2
-rw-r--r--app/assets/stylesheets/application.scss6
-rw-r--r--app/assets/stylesheets/framework.scss1
-rw-r--r--app/assets/stylesheets/framework/progress.scss5
-rw-r--r--app/assets/stylesheets/framework/variables.scss2
-rw-r--r--app/assets/stylesheets/pages/appearances.scss11
-rw-r--r--app/assets/stylesheets/pages/todos.scss35
-rw-r--r--app/controllers/admin/appearances_controller.rb57
-rw-r--r--app/controllers/projects/forks_controller.rb22
-rw-r--r--app/controllers/uploads_controller.rb5
-rw-r--r--app/helpers/appearances_helper.rb28
-rw-r--r--app/models/appearance.rb9
-rw-r--r--app/models/milestone.rb2
-rw-r--r--app/validators/url_validator.rb3
-rw-r--r--app/views/admin/appearances/_form.html.haml58
-rw-r--r--app/views/admin/appearances/preview.html.haml29
-rw-r--r--app/views/admin/appearances/show.html.haml7
-rw-r--r--app/views/dashboard/todos/_todo.html.haml6
-rw-r--r--app/views/layouts/nav/_admin.html.haml5
-rw-r--r--app/views/projects/diffs/_warning.html.haml11
-rw-r--r--app/views/projects/forks/index.html.haml14
-rw-r--r--config/routes.rb13
-rw-r--r--db/migrate/20160222153918_create_appearances_ce.rb14
-rw-r--r--db/schema.rb11
-rw-r--r--doc/README.md44
-rw-r--r--doc/ci/README.md72
-rw-r--r--doc/ci/examples/README.md16
-rw-r--r--doc/ci/examples/php.md (renamed from doc/ci/languages/php.md)0
-rw-r--r--doc/ci/languages/README.md7
-rw-r--r--doc/ci/quick_start/README.md6
-rw-r--r--doc/ci/services/README.md12
-rw-r--r--doc/ci/yaml/README.md7
-rw-r--r--doc/customization/branded_login_page.md19
-rw-r--r--doc/customization/branded_login_page/appearance.pngbin0 -> 365120 bytes
-rw-r--r--doc/customization/branded_login_page/custom_sign_in.pngbin0 -> 314111 bytes
-rw-r--r--doc/customization/branded_login_page/default_login_page.pngbin0 -> 292731 bytes
-rw-r--r--doc/customization/welcome_message.md8
-rw-r--r--doc/development/README.md11
-rw-r--r--doc/development/gotchas.md103
-rw-r--r--doc/permissions/permissions.md2
-rw-r--r--features/admin/appearance.feature37
-rw-r--r--features/project/milestone.feature1
-rw-r--r--features/steps/admin/appearance.rb72
-rw-r--r--features/steps/project/project_milestone.rb6
-rw-r--r--features/steps/shared/paths.rb8
-rw-r--r--lib/banzai/filter/sanitization_filter.rb10
-rw-r--r--spec/factories/appearances.rb8
-rw-r--r--spec/features/issues/filter_by_milestone_spec.rb4
-rw-r--r--spec/lib/banzai/filter/sanitization_filter_spec.rb16
-rw-r--r--spec/models/appearance_spec.rb10
-rw-r--r--spec/models/hooks/project_hook_spec.rb4
-rw-r--r--spec/models/hooks/web_hook_spec.rb20
56 files changed, 688 insertions, 185 deletions
diff --git a/CHANGELOG b/CHANGELOG
index 5521c1286a8..9e897644af0 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -3,6 +3,12 @@ Please view this file on the master branch, on stable branches it's out of date.
v 8.6.0 (unreleased)
- Improve the formatting for the user page bio (Connor Shea)
- Fix avatar stretching by providing a cropping feature (Johann Pardanaud)
+ - Strip leading and trailing spaces in URL validator (evuez)
+ - Update documentation to reflect Guest role not being enforced on internal projects
+
+v 8.5.2
+ - Fix sidebar overlapping content when screen width was below 1200px
+ - Fix error 500 when commenting on a commit
v 8.5.1
- Fix group projects styles
@@ -23,9 +29,6 @@ v 8.5.1
- Update sentry-raven gem to 0.15.6
- Add build coverage in project's builds page (Steffen Köhler)
-v 8.5.2
- - Fix error 500 when commenting on a commit
-
v 8.5.0
- Fix duplicate "me" in tooltip of the "thumbsup" awards Emoji (Stan Hu)
- Cache various Repository methods to improve performance (Yorick Peterse)
diff --git a/Gemfile b/Gemfile
index e37651f6fb3..e3607d9bed9 100644
--- a/Gemfile
+++ b/Gemfile
@@ -213,7 +213,6 @@ gem 'jquery-atwho-rails', '~> 1.3.2'
gem 'jquery-rails', '~> 4.0.0'
gem 'jquery-scrollto-rails', '~> 1.4.3'
gem 'jquery-ui-rails', '~> 5.0.0'
-gem 'nprogress-rails', '~> 0.1.6.7'
gem 'raphael-rails', '~> 2.1.2'
gem 'request_store', '~> 1.2.0'
gem 'select2-rails', '~> 3.5.9'
diff --git a/Gemfile.lock b/Gemfile.lock
index d0f780e9519..1ba062dd0d6 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -483,7 +483,6 @@ GEM
newrelic_rpm (3.14.1.311)
nokogiri (1.6.7.2)
mini_portile2 (~> 2.0.0.rc2)
- nprogress-rails (0.1.6.7)
oauth (0.4.7)
oauth2 (1.0.0)
faraday (>= 0.8, < 0.10)
@@ -964,7 +963,6 @@ DEPENDENCIES
net-ssh (~> 3.0.1)
newrelic_rpm (~> 3.14)
nokogiri (~> 1.6.7, >= 1.6.7.2)
- nprogress-rails (~> 0.1.6.7)
oauth2 (~> 1.0.0)
octokit (~> 3.8.0)
omniauth (~> 1.3.1)
diff --git a/app/assets/javascripts/application.js.coffee b/app/assets/javascripts/application.js.coffee
index 5463397f475..c17d2186e29 100644
--- a/app/assets/javascripts/application.js.coffee
+++ b/app/assets/javascripts/application.js.coffee
@@ -31,8 +31,6 @@
#= require ace/ace
#= require ace/ext-searchbox
#= require underscore
-#= require nprogress
-#= require nprogress-turbolinks
#= require dropzone
#= require mousetrap
#= require mousetrap/pause
diff --git a/app/assets/javascripts/logo.js.coffee b/app/assets/javascripts/logo.js.coffee
index 35b2fbbba07..d14b7139237 100644
--- a/app/assets/javascripts/logo.js.coffee
+++ b/app/assets/javascripts/logo.js.coffee
@@ -1,4 +1,4 @@
-NProgress.configure(showSpinner: false)
+Turbolinks.enableProgressBar();
defaultClass = 'tanuki-shape'
pieces = [
diff --git a/app/assets/stylesheets/application.scss b/app/assets/stylesheets/application.scss
index f51054f13dc..e2d590f4df4 100644
--- a/app/assets/stylesheets/application.scss
+++ b/app/assets/stylesheets/application.scss
@@ -26,12 +26,6 @@
@import "framework";
/*
- * NProgress load bar css
- */
-@import 'nprogress';
-@import 'nprogress-bootstrap';
-
-/*
* Font icons
*/
@import "font-awesome";
diff --git a/app/assets/stylesheets/framework.scss b/app/assets/stylesheets/framework.scss
index fa7641b1676..e2a30f5ed34 100644
--- a/app/assets/stylesheets/framework.scss
+++ b/app/assets/stylesheets/framework.scss
@@ -26,6 +26,7 @@
@import "framework/mobile.scss";
@import "framework/nav.scss";
@import "framework/pagination.scss";
+@import "framework/progress.scss";
@import "framework/panels.scss";
@import "framework/selects.scss";
@import "framework/sidebar.scss";
diff --git a/app/assets/stylesheets/framework/progress.scss b/app/assets/stylesheets/framework/progress.scss
new file mode 100644
index 00000000000..e9800bd24b5
--- /dev/null
+++ b/app/assets/stylesheets/framework/progress.scss
@@ -0,0 +1,5 @@
+html.turbolinks-progress-bar::before {
+ background-color: $progress-color!important;
+ height: 2px!important;
+ box-shadow: 0 0 10px $progress-color, 0 0 5px $progress-color;
+}
diff --git a/app/assets/stylesheets/framework/variables.scss b/app/assets/stylesheets/framework/variables.scss
index 2706d031d7b..7834cb0bfa5 100644
--- a/app/assets/stylesheets/framework/variables.scss
+++ b/app/assets/stylesheets/framework/variables.scss
@@ -7,7 +7,7 @@ $gl-header-color: #323232;
$gl-link-color: #333c48;
$md-text-color: #444;
$md-link-color: #3084bb;
-$nprogress-color: #c0392b;
+$progress-color: #c0392b;
$gl-font-size: 15px;
$list-font-size: 15px;
$sidebar_collapsed_width: 62px;
diff --git a/app/assets/stylesheets/pages/appearances.scss b/app/assets/stylesheets/pages/appearances.scss
new file mode 100644
index 00000000000..e2070f17c3b
--- /dev/null
+++ b/app/assets/stylesheets/pages/appearances.scss
@@ -0,0 +1,11 @@
+.appearance-logo-preview {
+ max-width: 400px;
+ margin-bottom: 20px;
+}
+
+.appearance-light-logo-preview {
+ background-color: $background-color;
+ max-width: 72px;
+ padding: 10px;
+ margin-bottom: 10px;
+}
diff --git a/app/assets/stylesheets/pages/todos.scss b/app/assets/stylesheets/pages/todos.scss
index 2f57f21963d..0dc5a905f99 100644
--- a/app/assets/stylesheets/pages/todos.scss
+++ b/app/assets/stylesheets/pages/todos.scss
@@ -12,29 +12,10 @@
}
}
-.todos {
- .panel {
- border-top: none;
- margin-bottom: 0;
- }
-}
-
.todo-item {
font-size: $gl-font-size;
- padding: $gl-padding-top 0 $gl-padding-top ($gl-avatar-size + $gl-padding-top);
- border-bottom: 1px solid $table-border-color;
- color: #7f8fa4;
-
- &.todo-inline {
- .avatar {
- position: relative;
- top: -2px;
- }
-
- .todo-title {
- line-height: 40px;
- }
- }
+ padding-left: $gl-avatar-size + $gl-padding-top;
+ color: $secondary-text;
a {
color: #4c4e54;
@@ -48,7 +29,7 @@
@include str-truncated(calc(100% - 174px));
font-weight: 600;
- .author_name {
+ .author-name {
color: #333;
}
}
@@ -88,17 +69,7 @@
margin-bottom: 0;
}
}
-
- .todo-note-icon {
- color: #777;
- float: left;
- font-size: $gl-font-size;
- line-height: 16px;
- margin-right: 5px;
- }
}
-
- &:last-child { border:none }
}
@media (max-width: $screen-xs-max) {
diff --git a/app/controllers/admin/appearances_controller.rb b/app/controllers/admin/appearances_controller.rb
new file mode 100644
index 00000000000..26cf74e4849
--- /dev/null
+++ b/app/controllers/admin/appearances_controller.rb
@@ -0,0 +1,57 @@
+class Admin::AppearancesController < Admin::ApplicationController
+ before_action :set_appearance, except: :create
+
+ def show
+ end
+
+ def preview
+ end
+
+ def create
+ @appearance = Appearance.new(appearance_params)
+
+ if @appearance.save
+ redirect_to admin_appearances_path, notice: 'Appearance was successfully created.'
+ else
+ render action: 'show'
+ end
+ end
+
+ def update
+ if @appearance.update(appearance_params)
+ redirect_to admin_appearances_path, notice: 'Appearance was successfully updated.'
+ else
+ render action: 'show'
+ end
+ end
+
+ def logo
+ @appearance.remove_logo!
+
+ @appearance.save
+
+ redirect_to admin_appearances_path, notice: 'Logo was succesfully removed.'
+ end
+
+ def header_logos
+ @appearance.remove_header_logo!
+ @appearance.save
+
+ redirect_to admin_appearances_path, notice: 'Header logo was succesfully removed.'
+ end
+
+ private
+
+ # Use callbacks to share common setup or constraints between actions.
+ def set_appearance
+ @appearance = Appearance.last || Appearance.new
+ end
+
+ # Only allow a trusted parameter "white list" through.
+ def appearance_params
+ params.require(:appearance).permit(
+ :title, :description, :logo, :logo_cache, :header_logo, :header_logo_cache,
+ :updated_by
+ )
+ end
+end
diff --git a/app/controllers/projects/forks_controller.rb b/app/controllers/projects/forks_controller.rb
index 0c551501ca4..a0835c9aad0 100644
--- a/app/controllers/projects/forks_controller.rb
+++ b/app/controllers/projects/forks_controller.rb
@@ -4,12 +4,22 @@ class Projects::ForksController < Projects::ApplicationController
before_action :authorize_download_code!
def index
- @sort = params[:sort] || 'id_desc'
- @all_forks = project.forks.includes(:creator).order_by(@sort)
-
- @public_forks, @protected_forks = @all_forks.partition do |project|
- can?(current_user, :read_project, project)
- end
+ base_query = project.forks.includes(:creator)
+
+ @forks = if current_user
+ base_query.where('projects.visibility_level IN (?) OR projects.id IN (?)',
+ Project.public_and_internal_levels,
+ current_user.authorized_projects.pluck(:id))
+ else
+ base_query.where('projects.visibility_level = ?', Project::PUBLIC)
+ end
+
+ @total_forks_count = base_query.size
+ @private_forks_count = @total_forks_count - @forks.size
+ @public_forks_count = @total_forks_count - @private_forks_count
+
+ @sort = params[:sort] || 'id_desc'
+ @forks = @forks.order_by(@sort).page(params[:page]).per(PER_PAGE)
end
def new
diff --git a/app/controllers/uploads_controller.rb b/app/controllers/uploads_controller.rb
index 868b05929d7..509f4f412ca 100644
--- a/app/controllers/uploads_controller.rb
+++ b/app/controllers/uploads_controller.rb
@@ -55,14 +55,15 @@ class UploadsController < ApplicationController
"user" => User,
"project" => Project,
"note" => Note,
- "group" => Group
+ "group" => Group,
+ "appearance" => Appearance
}
upload_models[params[:model]]
end
def upload_mount
- upload_mounts = %w(avatar attachment file)
+ upload_mounts = %w(avatar attachment file logo header_logo)
if upload_mounts.include?(params[:mounted_as])
params[:mounted_as]
diff --git a/app/helpers/appearances_helper.rb b/app/helpers/appearances_helper.rb
index c5820bf4c50..e0abc3a2869 100644
--- a/app/helpers/appearances_helper.rb
+++ b/app/helpers/appearances_helper.rb
@@ -1,21 +1,33 @@
module AppearancesHelper
- def brand_item
- nil
- end
-
def brand_title
- 'GitLab Community Edition'
+ if brand_item && brand_item.title
+ brand_item.title
+ else
+ 'GitLab Community Edition'
+ end
end
def brand_image
- nil
+ if brand_item.logo?
+ image_tag brand_item.logo
+ else
+ nil
+ end
end
def brand_text
- nil
+ markdown(brand_item.description)
+ end
+
+ def brand_item
+ @appearance ||= Appearance.first
end
def brand_header_logo
- render 'shared/logo.svg'
+ if brand_item && brand_item.header_logo?
+ image_tag brand_item.header_logo
+ else
+ render 'shared/logo.svg'
+ end
end
end
diff --git a/app/models/appearance.rb b/app/models/appearance.rb
new file mode 100644
index 00000000000..4cf8dd9a8ce
--- /dev/null
+++ b/app/models/appearance.rb
@@ -0,0 +1,9 @@
+class Appearance < ActiveRecord::Base
+ validates :title, presence: true
+ validates :description, presence: true
+ validates :logo, file_size: { maximum: 1.megabyte }
+ validates :header_logo, file_size: { maximum: 1.megabyte }
+
+ mount_uploader :logo, AttachmentUploader
+ mount_uploader :header_logo, AttachmentUploader
+end
diff --git a/app/models/milestone.rb b/app/models/milestone.rb
index cbe65d70997..8f99e3bef9b 100644
--- a/app/models/milestone.rb
+++ b/app/models/milestone.rb
@@ -27,7 +27,7 @@ class Milestone < ActiveRecord::Base
belongs_to :project
has_many :issues
- has_many :labels, through: :issues
+ has_many :labels, -> { distinct.reorder('labels.title') }, through: :issues
has_many :merge_requests
has_many :participants, through: :issues, source: :assignee
diff --git a/app/validators/url_validator.rb b/app/validators/url_validator.rb
index 2848b9cd33d..a77beb2683d 100644
--- a/app/validators/url_validator.rb
+++ b/app/validators/url_validator.rb
@@ -29,8 +29,11 @@ class UrlValidator < ActiveModel::EachValidator
end
def valid_url?(value)
+ return false if value.nil?
+
options = default_options.merge(self.options)
+ value.strip!
value =~ /\A#{URI.regexp(options[:protocols])}\z/
end
end
diff --git a/app/views/admin/appearances/_form.html.haml b/app/views/admin/appearances/_form.html.haml
new file mode 100644
index 00000000000..6f325914d14
--- /dev/null
+++ b/app/views/admin/appearances/_form.html.haml
@@ -0,0 +1,58 @@
+= form_for @appearance, url: admin_appearances_path, html: { class: 'form-horizontal'} do |f|
+ - if @appearance.errors.any?
+ .alert.alert-danger
+ - @appearance.errors.full_messages.each do |msg|
+ %p= msg
+
+ %fieldset.sign-in
+ %legend
+ Sign in/Sign up pages:
+ .form-group
+ = f.label :title, class: 'control-label'
+ .col-sm-10
+ = f.text_field :title, class: "form-control"
+ .form-group
+ = f.label :description, class: 'control-label'
+ .col-sm-10
+ = f.text_area :description, class: "form-control", rows: 10
+ .hint
+ Description parsed with #{link_to "GitLab Flavored Markdown", help_page_path('markdown', 'markdown'), target: '_blank'}.
+ .form-group
+ = f.label :logo, class: 'control-label'
+ .col-sm-10
+ - if @appearance.logo?
+ = image_tag @appearance.logo_url, class: 'appearance-logo-preview'
+ - if @appearance.persisted?
+ %br
+ = link_to 'Remove logo', logo_admin_appearances_path, data: { confirm: "Logo will be removed. Are you sure?"}, method: :delete, class: "btn btn-remove btn-small remove-logo"
+ %hr
+ = f.hidden_field :logo_cache
+ = f.file_field :logo, class: ""
+ .hint
+ Maximum file size is 1MB. Pages are optimized for a 640x360 px logo.
+
+ %fieldset.app_logo
+ %legend
+ Navigation bar:
+ .form-group
+ = f.label :header_logo, 'Header logo', class: 'control-label'
+ .col-sm-10
+ - if @appearance.header_logo?
+ = image_tag @appearance.header_logo_url, class: 'appearance-light-logo-preview'
+ - if @appearance.persisted?
+ %br
+ = link_to 'Remove header logo', header_logos_admin_appearances_path, data: { confirm: "Header logo will be removed. Are you sure?"}, method: :delete, class: "btn btn-remove btn-small remove-logo"
+ %hr
+ = f.hidden_field :header_logo_cache
+ = f.file_field :header_logo, class: ""
+ .hint
+ Maximum file size is 1MB. Pages are optimized for a 72x72 px header logo
+
+ .form-actions
+ = f.submit 'Save', class: 'btn btn-save'
+ - if @appearance.persisted?
+ = link_to 'Preview last save', preview_admin_appearances_path, class: 'btn', target: '_blank'
+
+ - if @appearance.updated_at
+ %span.pull-right
+ Last edit #{time_ago_with_tooltip(@appearance.updated_at)}
diff --git a/app/views/admin/appearances/preview.html.haml b/app/views/admin/appearances/preview.html.haml
new file mode 100644
index 00000000000..dd4a64e80bc
--- /dev/null
+++ b/app/views/admin/appearances/preview.html.haml
@@ -0,0 +1,29 @@
+- page_title "Preview | Appearance"
+%h3.page-title
+ Appearance settings - Preview
+%hr
+
+.ui-box
+ .title
+ Sign-in page
+ %div
+ .login-page
+ .container
+ .content
+ .login-title
+ %h1= brand_title
+ %hr
+ .container
+ .content
+ .row
+ .col-sm-7
+ .brand-image
+ = brand_image
+ .brand_text
+ = brand_text
+ .col-sm-4
+ .login-box
+ %h3.page-title Sign in
+ = text_field_tag :login, nil, class: "form-control top", placeholder: "Username or Email"
+ = password_field_tag :password, nil, class: "form-control bottom", placeholder: "Password"
+ = button_tag "Sign in", class: "btn-create btn"
diff --git a/app/views/admin/appearances/show.html.haml b/app/views/admin/appearances/show.html.haml
new file mode 100644
index 00000000000..089e8e4cb7a
--- /dev/null
+++ b/app/views/admin/appearances/show.html.haml
@@ -0,0 +1,7 @@
+- page_title "Appearance"
+%h3.page-title
+ Appearance settings
+%p.light
+ You can modify the look and feel of GitLab here
+
+= render 'form'
diff --git a/app/views/dashboard/todos/_todo.html.haml b/app/views/dashboard/todos/_todo.html.haml
index 6975f6ed0db..f878d36e739 100644
--- a/app/views/dashboard/todos/_todo.html.haml
+++ b/app/views/dashboard/todos/_todo.html.haml
@@ -1,11 +1,11 @@
%li{class: "todo todo-#{todo.done? ? 'done' : 'pending'}", id: dom_id(todo) }
- .todo-item{class: 'todo-block'}
+ .todo-item.todo-block
= image_tag avatar_icon(todo.author_email, 40), class: 'avatar s40', alt:''
.todo-title
- %span.author_name
+ %span.author-name
= link_to_author todo
- %span.todo_label
+ %span.todo-label
= todo_action_name(todo)
= todo_target_link(todo)
diff --git a/app/views/layouts/nav/_admin.html.haml b/app/views/layouts/nav/_admin.html.haml
index ac1d5429382..280a1b93729 100644
--- a/app/views/layouts/nav/_admin.html.haml
+++ b/app/views/layouts/nav/_admin.html.haml
@@ -56,6 +56,11 @@
= icon('cog fw')
%span
Background Jobs
+ = nav_link(controller: :appearances) do
+ = link_to admin_appearances_path, title: 'Appearances' do
+ = icon('image')
+ %span
+ Appearance
= nav_link(controller: :applications) do
= link_to admin_applications_path, title: 'Applications' do
diff --git a/app/views/projects/diffs/_warning.html.haml b/app/views/projects/diffs/_warning.html.haml
index f99bc9a85eb..63ede71e6f1 100644
--- a/app/views/projects/diffs/_warning.html.haml
+++ b/app/views/projects/diffs/_warning.html.haml
@@ -3,17 +3,16 @@
Too many changes to show.
.pull-right
- unless diff_hard_limit_enabled?
- = link_to "Reload with full diff", url_for(params.merge(force_show_diff: true, format: nil)), class: "btn btn-sm btn-warning"
+ = link_to "Reload with full diff", url_for(params.merge(force_show_diff: true, format: nil)), class: "btn btn-sm"
- if current_controller?(:commit) or current_controller?(:merge_requests)
- if current_controller?(:commit)
- = link_to "Plain diff", namespace_project_commit_path(@project.namespace, @project, @commit, format: :diff), class: "btn btn-warning btn-sm"
- = link_to "Email patch", namespace_project_commit_path(@project.namespace, @project, @commit, format: :patch), class: "btn btn-warning btn-sm"
+ = link_to "Plain diff", namespace_project_commit_path(@project.namespace, @project, @commit, format: :diff), class: "btn btn-sm"
+ = link_to "Email patch", namespace_project_commit_path(@project.namespace, @project, @commit, format: :patch), class: "btn btn-sm"
- elsif @merge_request && @merge_request.persisted?
- = link_to "Plain diff", merge_request_path(@merge_request, format: :diff), class: "btn btn-warning btn-sm"
- = link_to "Email patch", merge_request_path(@merge_request, format: :patch), class: "btn btn-warning btn-sm"
+ = link_to "Plain diff", merge_request_path(@merge_request, format: :diff), class: "btn btn-sm"
+ = link_to "Email patch", merge_request_path(@merge_request, format: :patch), class: "btn btn-sm"
%p
To preserve performance only
%strong #{shown_files_count} of #{diffs.size}
files are displayed.
-
diff --git a/app/views/projects/forks/index.html.haml b/app/views/projects/forks/index.html.haml
index 42fa6fdb782..ace22625d1d 100644
--- a/app/views/projects/forks/index.html.haml
+++ b/app/views/projects/forks/index.html.haml
@@ -1,9 +1,7 @@
.top-area
.nav-text
- - public_count = @public_forks.size
- - protected_count = @protected_forks.size
- - full_count_title = "#{public_count} public and #{protected_count} private"
- == #{pluralize(@all_forks.size, 'fork')}: #{full_count_title}
+ - full_count_title = "#{@public_forks_count} public and #{@private_forks_count} private"
+ == #{pluralize(@total_forks_count, 'fork')}: #{full_count_title}
.nav-controls
= search_field_tag :filter_projects, nil, placeholder: 'Search forks', class: 'projects-list-filter project-filter-form-field form-control input-short',
@@ -41,17 +39,17 @@
.projects-list-holder
- - if @public_forks.blank?
+ - if @forks.blank?
%ul.content-list
%li
.nothing-here-block No forks to show
- else
- = render 'shared/projects/list', projects: @public_forks, use_creator_avatar: true,
+ = render 'shared/projects/list', projects: @forks, use_creator_avatar: true,
forks: true, show_last_commit_as_description: true
- - if protected_count > 0
+ - if @private_forks_count > 0
%ul.projects-list.private-forks-notice
%li.project-row
= icon('lock fw', base: 'circle', class: 'fa-lg private-fork-icon')
- %strong= pluralize(protected_count, 'private fork')
+ %strong= pluralize(@private_forks_count, 'private fork')
%span you have no access to.
diff --git a/config/routes.rb b/config/routes.rb
index 1485b64da19..a2acf170a6b 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -156,6 +156,11 @@ Rails.application.routes.draw do
to: "uploads#show",
constraints: { model: /note|user|group|project/, mounted_as: /avatar|attachment/, filename: /[^\/]+/ }
+ # Appearance
+ get ":model/:mounted_as/:id/:filename",
+ to: "uploads#show",
+ constraints: { model: /appearance/, mounted_as: /logo|header_logo/, filename: /.+/ }
+
# Project markdown uploads
get ":namespace_id/:project_id/:secret/:filename",
to: "projects/uploads#show",
@@ -253,6 +258,14 @@ Rails.application.routes.draw do
end
end
+ resource :appearances, path: 'appearance' do
+ member do
+ get :preview
+ delete :logo
+ delete :header_logos
+ end
+ end
+
resource :application_settings, only: [:show, :update] do
resources :services
put :reset_runners_token
diff --git a/db/migrate/20160222153918_create_appearances_ce.rb b/db/migrate/20160222153918_create_appearances_ce.rb
new file mode 100644
index 00000000000..bec66bcc71e
--- /dev/null
+++ b/db/migrate/20160222153918_create_appearances_ce.rb
@@ -0,0 +1,14 @@
+class CreateAppearancesCe < ActiveRecord::Migration
+ def change
+ unless table_exists?(:appearances)
+ create_table :appearances do |t|
+ t.string :title
+ t.text :description
+ t.string :header_logo
+ t.string :logo
+
+ t.timestamps null: false
+ end
+ end
+ end
+end
diff --git a/db/schema.rb b/db/schema.rb
index 4708c29d9ae..53a941d30de 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: 20160220123949) do
+ActiveRecord::Schema.define(version: 20160222153918) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
@@ -24,6 +24,15 @@ ActiveRecord::Schema.define(version: 20160220123949) do
t.datetime "updated_at"
end
+ create_table "appearances", force: :cascade do |t|
+ t.string "title"
+ t.text "description"
+ t.string "header_logo"
+ t.string "logo"
+ t.datetime "created_at", null: false
+ t.datetime "updated_at", null: false
+ end
+
create_table "application_settings", force: :cascade do |t|
t.integer "default_projects_limit"
t.boolean "signup_enabled"
diff --git a/doc/README.md b/doc/README.md
index 5089e1e70f6..be6c5f96ea1 100644
--- a/doc/README.md
+++ b/doc/README.md
@@ -16,40 +16,42 @@
- [Web hooks](web_hooks/web_hooks.md) Let GitLab notify you when new code has been pushed to your project.
- [Workflow](workflow/README.md) Using GitLab functionality and importing projects from GitHub and SVN.
-## CI Documentation
+## CI User documentation
-- [Quick Start](ci/quick_start/README.md)
-- [Enable or disable GitLab CI](ci/enable_or_disable_ci.md)
-- [Configuring project (.gitlab-ci.yml)](ci/yaml/README.md)
-- [Configuring runner](ci/runners/README.md)
-- [Configuring deployment](ci/deployment/README.md)
-- [Using Docker Images](ci/docker/using_docker_images.md)
-- [Using Docker Build](ci/docker/using_docker_build.md)
-- [Using Variables](ci/variables/README.md)
-- [Using SSH keys](ci/ssh_keys/README.md)
+- [Get started with GitLab CI](ci/quick_start/README.md)
+- [Learn how to enable or disable GitLab CI](ci/enable_or_disable_ci.md)
+- [Learn how `.gitlab-ci.yml` works](ci/yaml/README.md)
+- [Configure a Runner, the application that runs your builds](ci/runners/README.md)
+- [Use Docker images with GitLab Runner](ci/docker/using_docker_images.md)
+- [Use CI to build Docker images](ci/docker/using_docker_build.md)
+- [Use variables in your `.gitlab-ci.yml`](ci/variables/README.md)
+- [Use SSH keys in your build environment](ci/ssh_keys/README.md)
+- [Trigger builds through the API](ci/triggers/README.md)
+- [Build artifacts](ci/build_artifacts/README.md)
- [User permissions](ci/permissions/README.md)
- [API](ci/api/README.md)
-- [Triggering builds through the API](ci/triggers/README.md)
-- [Build artifacts](ci/build_artifacts/README.md)
-### CI Languages
+### CI Examples
-- [Testing PHP](ci/languages/php.md)
+- [The .gitlab-ci.yml file for GitLab itself](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/.gitlab-ci.yml)
+- [Test your PHP applications](ci/examples/php.md)
+- [Test and deploy Ruby applications to Heroku](ci/examples/test-and-deploy-ruby-application-to-heroku.md)
+- [Test and deploy Python applications to Heroku](ci/examples/test-and-deploy-python-application-to-heroku.md)
+- [Test Clojure applications](ci/examples/test-clojure-application.md)
+- [Using `dpl` as deployment tool](ci/deployment/README.md)
+- Help your favorite programming language and GitLab by sending a merge request
+ with a guide for that language.
### CI Services
+GitLab CI uses the `services` keyword to define what docker containers should
+be linked with your base image. Below is a list of examples you may use:
+
- [Using MySQL](ci/services/mysql.md)
- [Using PostgreSQL](ci/services/postgres.md)
- [Using Redis](ci/services/redis.md)
- [Using Other Services](ci/docker/using_docker_images.md#how-to-use-other-images-as-services)
-### CI Examples
-
-- [Test and deploy Ruby applications to Heroku](ci/examples/test-and-deploy-ruby-application-to-heroku.md)
-- [Test and deploy Python applications to Heroku](ci/examples/test-and-deploy-python-application-to-heroku.md)
-- [Test Clojure applications](ci/examples/test-clojure-application.md)
-- Help your favorite programming language and GitLab by sending a merge request with a guide for that language.
-
## Administrator documentation
- [Custom git hooks](hooks/custom_hooks.md) Custom git hooks (on the filesystem) for when web hooks aren't enough.
diff --git a/doc/ci/README.md b/doc/ci/README.md
index 5886829be51..2120b5b2850 100644
--- a/doc/ci/README.md
+++ b/doc/ci/README.md
@@ -1,39 +1,37 @@
## GitLab CI Documentation
-### User documentation
-
-* [Quick Start](quick_start/README.md)
-* [Enable or disable GitLab CI](enable_or_disable_ci.md)
-* [Configuring project (.gitlab-ci.yml)](yaml/README.md)
-* [Configuring runner](runners/README.md)
-* [Configuring deployment](deployment/README.md)
-* [Using Docker Images](docker/using_docker_images.md)
-* [Using Docker Build](docker/using_docker_build.md)
-* [Using Variables](variables/README.md)
-* [Using SSH keys](ssh_keys/README.md)
-* [Triggering builds through the API](triggers/README.md)
-* [Build artifacts](build_artifacts/README.md)
-
-### Languages
-
-* [Testing PHP](languages/php.md)
-
-### Services
-
-* [Using MySQL](services/mysql.md)
-* [Using PostgreSQL](services/postgres.md)
-* [Using Redis](services/redis.md)
-* [Using Other Services](docker/using_docker_images.md#how-to-use-other-images-as-services)
-
-### Examples
-
-+ [The .gitlab-ci.yml file for GitLab itself](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/.gitlab-ci.yml)
-+ [Test and deploy Ruby applications to Heroku](examples/test-and-deploy-ruby-application-to-heroku.md)
-+ [Test and deploy Python applications to Heroku](examples/test-and-deploy-python-application-to-heroku.md)
-+ [Test Clojure applications](examples/test-clojure-application.md)
-+ Help your favorite programming language and GitLab by sending a merge request with a guide for that language.
-
-### Administrator documentation
-
-* [User permissions](permissions/README.md)
-* [API](api/README.md)
+### CI User documentation
+
+- [Get started with GitLab CI](quick_start/README.md)
+- [Learn how to enable or disable GitLab CI](enable_or_disable_ci.md)
+- [Learn how `.gitlab-ci.yml` works](yaml/README.md)
+- [Configure a Runner, the application that runs your builds](runners/README.md)
+- [Use Docker images with GitLab Runner](docker/using_docker_images.md)
+- [Use CI to build Docker images](docker/using_docker_build.md)
+- [Use variables in your `.gitlab-ci.yml`](variables/README.md)
+- [Use SSH keys in your build environment](ssh_keys/README.md)
+- [Trigger builds through the API](triggers/README.md)
+- [Build artifacts](build_artifacts/README.md)
+- [User permissions](permissions/README.md)
+- [API](api/README.md)
+
+### CI Examples
+
+- [The .gitlab-ci.yml file for GitLab itself](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/.gitlab-ci.yml)
+- [Test your PHP applications](examples/php.md)
+- [Test and deploy Ruby applications to Heroku](examples/test-and-deploy-ruby-application-to-heroku.md)
+- [Test and deploy Python applications to Heroku](examples/test-and-deploy-python-application-to-heroku.md)
+- [Test Clojure applications](examples/test-clojure-application.md)
+- [Using `dpl` as deployment tool](deployment/README.md)
+- Help your favorite programming language and GitLab by sending a merge request
+ with a guide for that language.
+
+### CI Services
+
+GitLab CI uses the `services` keyword to define what docker containers should
+be linked with your base image. Below is a list of examples you may use:
+
+- [Using MySQL](services/mysql.md)
+- [Using PostgreSQL](services/postgres.md)
+- [Using Redis](services/redis.md)
+- [Using Other Services](docker/using_docker_images.md#how-to-use-other-images-as-services)
diff --git a/doc/ci/examples/README.md b/doc/ci/examples/README.md
index 1cf41aea391..31f29f4a082 100644
--- a/doc/ci/examples/README.md
+++ b/doc/ci/examples/README.md
@@ -1,5 +1,13 @@
-# Build script examples
+## Build script examples
-+ [Test and deploy a Ruby application to Heroku](test-and-deploy-ruby-application-to-heroku.md)
-+ [Test and deploy a Python application to Heroku](test-and-deploy-python-application-to-heroku.md)
-+ [Test a Clojure application](test-clojure-application.md)
+- [Test and deploy a Ruby application to Heroku](test-and-deploy-ruby-application-to-heroku.md)
+- [Test and deploy a Python application to Heroku](test-and-deploy-python-application-to-heroku.md)
+- [Test a Clojure application](test-clojure-application.md)
+
+## Languages
+
+This is a list of languages you can test with GitLab CI. Each section has
+comprehensive documentation and comes with a test repository hosted on
+GitLab.com.
+
+- [Testing PHP](php.md)
diff --git a/doc/ci/languages/php.md b/doc/ci/examples/php.md
index aeadd6a448e..aeadd6a448e 100644
--- a/doc/ci/languages/php.md
+++ b/doc/ci/examples/php.md
diff --git a/doc/ci/languages/README.md b/doc/ci/languages/README.md
deleted file mode 100644
index 54b2343e08b..00000000000
--- a/doc/ci/languages/README.md
+++ /dev/null
@@ -1,7 +0,0 @@
-### Languages
-
-This is a list of languages you can test with GitLab CI. Each section has
-comprehensive documentation and comes with a test repository hosted on
-GitLab.com
-
-+ [Testing PHP](php.md)
diff --git a/doc/ci/quick_start/README.md b/doc/ci/quick_start/README.md
index 327c83bef72..5af7be5581e 100644
--- a/doc/ci/quick_start/README.md
+++ b/doc/ci/quick_start/README.md
@@ -201,6 +201,11 @@ You can access a builds badge image using following link:
http://example.gitlab.com/namespace/project/badges/branch/build.svg
```
+## Examples
+
+Visit the [examples README][examples] to see a list of examples using GitLab
+CI with various languages.
+
## Next steps
Awesome! You started using CI in GitLab!
@@ -212,3 +217,4 @@ Visit our various languages examples at <https://gitlab.com/groups/gitlab-exampl
[runner-install]: https://gitlab.com/gitlab-org/gitlab-ci-multi-runner/tree/master#installation
[blog-ci]: https://about.gitlab.com/2015/05/06/why-were-replacing-gitlab-ci-jobs-with-gitlab-ci-dot-yml/
+[examples]: ../examples/README.md
diff --git a/doc/ci/services/README.md b/doc/ci/services/README.md
index 1ebb0a4a250..4b79461d55c 100644
--- a/doc/ci/services/README.md
+++ b/doc/ci/services/README.md
@@ -1,9 +1,9 @@
## GitLab CI Services
-GitLab CI uses the `services` keyword to define what docker containers should be
-linked with your base image. Below is a list of examples you may use.
+GitLab CI uses the `services` keyword to define what docker containers should
+be linked with your base image. Below is a list of examples you may use.
-+ [Using MySQL](mysql.md)
-+ [Using PostgreSQL](postgres.md)
-+ [Using Redis](redis.md)
-+ [Using Other Services](../docker/using_docker_images.md#how-to-use-other-images-as-services)
+- [Using MySQL](mysql.md)
+- [Using PostgreSQL](postgres.md)
+- [Using Redis](redis.md)
+- [Using Other Services](../docker/using_docker_images.md#how-to-use-other-images-as-services)
diff --git a/doc/ci/yaml/README.md b/doc/ci/yaml/README.md
index 0edb56dc20e..051eaa04152 100644
--- a/doc/ci/yaml/README.md
+++ b/doc/ci/yaml/README.md
@@ -518,3 +518,10 @@ You can find the link under `/ci/lint` of your gitlab instance.
If your commit message contains `[ci skip]`, the commit will be created but the
builds will be skipped.
+
+## Examples
+
+Visit the [examples README][examples] to see a list of examples using GitLab
+CI with various languages.
+
+[examples]: ../examples/README.md
diff --git a/doc/customization/branded_login_page.md b/doc/customization/branded_login_page.md
new file mode 100644
index 00000000000..d4d9f5f7b5e
--- /dev/null
+++ b/doc/customization/branded_login_page.md
@@ -0,0 +1,19 @@
+# Changing the appearance of the login page
+
+GitLab Community Edition offers a way to put your company's identity on the login page of your GitLab server and make it a branded login page.
+
+By default, the page shows the GitLab logo and description.
+
+![default_login_page](branded_login_page/default_login_page.png)
+
+## Changing the appearance of the login page
+
+Navigate to the **Admin** area and go to the **Appearance** page.
+
+Fill in the required details like Title, Description and upload the company logo.
+
+![appearance](branded_login_page/appearance.png)
+
+After saving the page, your GitLab login page will have the details you filled in:
+
+![company_login_page](branded_login_page/custom_sign_in.png)
diff --git a/doc/customization/branded_login_page/appearance.png b/doc/customization/branded_login_page/appearance.png
new file mode 100644
index 00000000000..6bce1f0a287
--- /dev/null
+++ b/doc/customization/branded_login_page/appearance.png
Binary files differ
diff --git a/doc/customization/branded_login_page/custom_sign_in.png b/doc/customization/branded_login_page/custom_sign_in.png
new file mode 100644
index 00000000000..d6020b029a2
--- /dev/null
+++ b/doc/customization/branded_login_page/custom_sign_in.png
Binary files differ
diff --git a/doc/customization/branded_login_page/default_login_page.png b/doc/customization/branded_login_page/default_login_page.png
new file mode 100644
index 00000000000..795c7954d8e
--- /dev/null
+++ b/doc/customization/branded_login_page/default_login_page.png
Binary files differ
diff --git a/doc/customization/welcome_message.md b/doc/customization/welcome_message.md
index e993230bb88..a0cb234bea0 100644
--- a/doc/customization/welcome_message.md
+++ b/doc/customization/welcome_message.md
@@ -1,12 +1,12 @@
-# Customize the complete sign-in page (GitLab Enterprise Edition only)
+# Customize the complete sign-in page
-Please see [Branded login page](http://doc.gitlab.com/ee/customization/branded_login_page.html)
+Please see [Branded login page](branded_login_page.md)
# Add a welcome message to the sign-in page (GitLab Community Edition)
It is possible to add a markdown-formatted welcome message to your GitLab
sign-in page. Users of GitLab Enterprise Edition should use the [branded login
-page feature](/ee/customization/branded_login_page.html) instead.
+page feature](branded_login_page.md) instead.
The welcome message (extra_sign_in_text) can now be set/changed in the Admin UI.
-Admin area > Settings \ No newline at end of file
+Admin area > Settings
diff --git a/doc/development/README.md b/doc/development/README.md
index d5bf166ad32..b9a0d81e5ba 100644
--- a/doc/development/README.md
+++ b/doc/development/README.md
@@ -1,11 +1,12 @@
# Development
- [Architecture](architecture.md) of GitLab
-- [Shell commands](shell_commands.md) in the GitLab codebase
-- [Rake tasks](rake_tasks.md) for development
+- [Benchmarking](benchmarking.md)
- [CI setup](ci_setup.md) for testing GitLab
+- [Gotchas](gotchas.md) to avoid
+- [How to dump production data to staging](db_dump.md)
+- [Migration Style Guide](migration_style_guide.md) for creating safe migrations
+- [Rake tasks](rake_tasks.md) for development
+- [Shell commands](shell_commands.md) in the GitLab codebase
- [Sidekiq debugging](sidekiq_debugging.md)
- [UI guide](ui_guide.md) for building GitLab with existing css styles and elements
-- [Migration Style Guide](migration_style_guide.md) for creating safe migrations
-- [How to dump production data to staging](dump_db.md)
-- [Benchmarking](benchmarking.md)
diff --git a/doc/development/gotchas.md b/doc/development/gotchas.md
new file mode 100644
index 00000000000..21078c8d6f9
--- /dev/null
+++ b/doc/development/gotchas.md
@@ -0,0 +1,103 @@
+# Gotchas
+
+The purpose of this guide is to document potential "gotchas" that contributors
+might encounter or should avoid during development of GitLab CE and EE.
+
+## Don't `describe` symbols
+
+Consider the following model spec:
+
+```ruby
+require 'rails_helper'
+
+describe User do
+ describe :to_param do
+ it 'converts the username to a param' do
+ user = described_class.new(username: 'John Smith')
+
+ expect(user.to_param).to eq 'john-smith'
+ end
+ end
+end
+```
+
+When run, this spec doesn't do what we might expect:
+
+```sh
+spec/models/user_spec.rb|6 error| Failure/Error: u = described_class.new NoMethodError: undefined method `new' for :to_param:Symbol
+```
+
+### Solution
+
+Except for the top-level `describe` block, always provide a String argument to
+`describe`.
+
+## Don't `rescue Exception`
+
+See ["Why is it bad style to `rescue Exception => e` in Ruby?"][Exception].
+
+_**Note:** This rule is [enforced automatically by
+Rubocop](https://gitlab.com/gitlab-org/gitlab-ce/blob/8-4-stable/.rubocop.yml#L911-914)._
+
+[Exception]: http://stackoverflow.com/q/10048173/223897
+
+## Don't use inline CoffeeScript in views
+
+Using the inline `:coffee` or `:coffeescript` Haml filters comes with a
+performance overhead.
+
+_**Note:** We've [removed these two filters](https://gitlab.com/gitlab-org/gitlab-ce/blob/8-5-stable/config/initializers/haml.rb)
+in an initializer._
+
+### Further reading
+
+- Pull Request: [Replace CoffeeScript block into JavaScript in Views](https://git.io/vztMu)
+- Stack Overflow: [Performance implications of using :coffescript filter inside HAML templates?](http://stackoverflow.com/a/17571242/223897)
+
+## ID-based CSS selectors need to be a bit more specific
+
+Normally, because HTML `id` attributes need to be unique to the page, it's
+perfectly fine to write some JavaScript like the following:
+
+```javascript
+$('#js-my-selector').hide();
+```
+
+However, there's a feature of GitLab's Markdown processing that [automatically
+adds anchors to header elements][ToC Processing], with the `id` attribute being
+automatically generated based on the content of the header.
+
+Unfortunately, this feature makes it possible for user-generated content to
+create a header element with the same `id` attribute we're using in our
+selector, potentially breaking the JavaScript behavior. A user could break the
+above example with the following Markdown:
+
+```markdown
+## JS My Selector
+```
+
+Which gets converted to the following HTML:
+
+```html
+<h2>
+ <a id="js-my-selector" class="anchor" href="#js-my-selector" aria-hidden="true"></a>
+ JS My Selector
+</h2>
+```
+
+[ToC Processing]: https://gitlab.com/gitlab-org/gitlab-ce/blob/8-4-stable/lib/banzai/filter/table_of_contents_filter.rb#L31-37
+
+### Solution
+
+The current recommended fix for this is to make our selectors slightly more
+specific:
+
+```javascript
+$('div#js-my-selector').hide();
+```
+
+### Further reading
+
+- Issue: [Merge request ToC anchor conflicts with tabs](https://gitlab.com/gitlab-org/gitlab-ce/issues/3908)
+- Merge Request: [Make tab target selectors less naive](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/2023)
+- Merge Request: [Make cross-project reference's clipboard target less naive](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/2024)
diff --git a/doc/permissions/permissions.md b/doc/permissions/permissions.md
index f717b30c12e..ac0fd3d1756 100644
--- a/doc/permissions/permissions.md
+++ b/doc/permissions/permissions.md
@@ -6,7 +6,7 @@ If a user is both in a project group and in the project itself, the highest perm
If a user is a GitLab administrator they receive all permissions.
-On public projects the Guest role is not enforced.
+On public and internal projects the Guest role is not enforced.
All users will be able to create issues, leave comments, and pull or download the project code.
To add or import a user, you can follow the [project users and members
diff --git a/features/admin/appearance.feature b/features/admin/appearance.feature
new file mode 100644
index 00000000000..5c1dd7531c1
--- /dev/null
+++ b/features/admin/appearance.feature
@@ -0,0 +1,37 @@
+Feature: Admin Appearance
+ Scenario: Create new appearance
+ Given I sign in as an admin
+ And I visit admin appearance page
+ When submit form with new appearance
+ Then I should be redirected to admin appearance page
+ And I should see newly created appearance
+
+ Scenario: Preview appearance
+ Given application has custom appearance
+ And I sign in as an admin
+ When I visit admin appearance page
+ And I click preview button
+ Then I should see a customized appearance
+
+ Scenario: Custom sign-in page
+ Given application has custom appearance
+ When I visit login page
+ Then I should see a customized appearance
+
+ Scenario: Appearance logo
+ Given application has custom appearance
+ And I sign in as an admin
+ And I visit admin appearance page
+ When I attach a logo
+ Then I should see a logo
+ And I remove the logo
+ Then I should see logo removed
+
+ Scenario: Header logos
+ Given application has custom appearance
+ And I sign in as an admin
+ And I visit admin appearance page
+ When I attach header logos
+ Then I should see header logos
+ And I remove the header logos
+ Then I should see header logos removed
diff --git a/features/project/milestone.feature b/features/project/milestone.feature
index e0f4c0e9d7c..713f0f3b979 100644
--- a/features/project/milestone.feature
+++ b/features/project/milestone.feature
@@ -13,6 +13,7 @@ Feature: Project Milestone
Given I visit project "Shop" milestones page
And I click link "v2.2"
Then I should see the labels "bug", "enhancement" and "feature"
+ And I should see the "bug" label listed only once
@javascript
Scenario: Listing labels from labels tab
diff --git a/features/steps/admin/appearance.rb b/features/steps/admin/appearance.rb
new file mode 100644
index 00000000000..0d1be46d11d
--- /dev/null
+++ b/features/steps/admin/appearance.rb
@@ -0,0 +1,72 @@
+class Spinach::Features::AdminAppearance < Spinach::FeatureSteps
+ include SharedAuthentication
+ include SharedPaths
+
+ step 'submit form with new appearance' do
+ fill_in 'appearance_title', with: 'MyCompany'
+ fill_in 'appearance_description', with: 'dev server'
+ click_button 'Save'
+ end
+
+ step 'I should be redirected to admin appearance page' do
+ expect(current_path).to eq admin_appearances_path
+ expect(page).to have_content 'Appearance settings'
+ end
+
+ step 'I should see newly created appearance' do
+ expect(page).to have_field('appearance_title', with: 'MyCompany')
+ expect(page).to have_field('appearance_description', with: 'dev server')
+ expect(page).to have_content 'Last edit'
+ end
+
+ step 'I click preview button' do
+ click_link "Preview"
+ end
+
+ step 'application has custom appearance' do
+ create(:appearance)
+ end
+
+ step 'I should see a customized appearance' do
+ expect(page).to have_content appearance.title
+ expect(page).to have_content appearance.description
+ end
+
+ step 'I attach a logo' do
+ attach_file(:appearance_logo, Rails.root.join('spec', 'fixtures', 'dk.png'))
+ click_button 'Save'
+ end
+
+ step 'I attach header logos' do
+ attach_file(:appearance_header_logo, Rails.root.join('spec', 'fixtures', 'dk.png'))
+ click_button 'Save'
+ end
+
+ step 'I should see a logo' do
+ expect(page).to have_xpath('//img[@src="/uploads/appearance/logo/1/dk.png"]')
+ end
+
+ step 'I should see header logos' do
+ expect(page).to have_xpath('//img[@src="/uploads/appearance/header_logo/1/dk.png"]')
+ end
+
+ step 'I remove the logo' do
+ click_link 'Remove logo'
+ end
+
+ step 'I remove the header logos' do
+ click_link 'Remove header logo'
+ end
+
+ step 'I should see logo removed' do
+ expect(page).not_to have_xpath('//img[@src="/uploads/appearance/logo/1/gitlab_logo.png"]')
+ end
+
+ step 'I should see header logos removed' do
+ expect(page).not_to have_xpath('//img[@src="/uploads/appearance/header_logo/1/header_logo_light.png"]')
+ end
+
+ def appearance
+ Appearance.last
+ end
+end
diff --git a/features/steps/project/project_milestone.rb b/features/steps/project/project_milestone.rb
index ec881c0d8fc..2508c09e36d 100644
--- a/features/steps/project/project_milestone.rb
+++ b/features/steps/project/project_milestone.rb
@@ -41,6 +41,12 @@ class Spinach::Features::ProjectMilestone < Spinach::FeatureSteps
end
end
+ step 'I should see the "bug" label listed only once' do
+ page.within('#tab-labels') do
+ expect(page).to have_content('bug', count: 1)
+ end
+ end
+
step 'I click link "v2.2"' do
click_link "v2.2"
end
diff --git a/features/steps/shared/paths.rb b/features/steps/shared/paths.rb
index 0f9835e7356..6432a786bfc 100644
--- a/features/steps/shared/paths.rb
+++ b/features/steps/shared/paths.rb
@@ -7,6 +7,10 @@ module SharedPaths
visit new_project_path
end
+ step 'I visit login page' do
+ visit new_user_session_path
+ end
+
# ----------------------------------------
# User
# ----------------------------------------
@@ -187,6 +191,10 @@ module SharedPaths
visit admin_groups_path
end
+ step 'I visit admin appearance page' do
+ visit admin_appearances_path
+ end
+
step 'I visit admin teams page' do
visit admin_teams_path
end
diff --git a/lib/banzai/filter/sanitization_filter.rb b/lib/banzai/filter/sanitization_filter.rb
index 04ddfe53ed6..abd79b329ae 100644
--- a/lib/banzai/filter/sanitization_filter.rb
+++ b/lib/banzai/filter/sanitization_filter.rb
@@ -7,6 +7,8 @@ module Banzai
#
# Extends HTML::Pipeline::SanitizationFilter with a custom whitelist.
class SanitizationFilter < HTML::Pipeline::SanitizationFilter
+ UNSAFE_PROTOCOLS = %w(javascript :javascript data vbscript).freeze
+
def whitelist
whitelist = super
@@ -43,8 +45,8 @@ module Banzai
# Allow any protocol in `a` elements...
whitelist[:protocols].delete('a')
- # ...but then remove links with the `javascript` protocol
- whitelist[:transformers].push(remove_javascript_links)
+ # ...but then remove links with unsafe protocols
+ whitelist[:transformers].push(remove_unsafe_links)
# Remove `rel` attribute from `a` elements
whitelist[:transformers].push(remove_rel)
@@ -55,14 +57,14 @@ module Banzai
whitelist
end
- def remove_javascript_links
+ def remove_unsafe_links
lambda do |env|
node = env[:node]
return unless node.name == 'a'
return unless node.has_attribute?('href')
- if node['href'].start_with?('javascript', ':javascript')
+ if node['href'].start_with?(*UNSAFE_PROTOCOLS)
node.remove_attribute('href')
end
end
diff --git a/spec/factories/appearances.rb b/spec/factories/appearances.rb
new file mode 100644
index 00000000000..cf2a2b76bcb
--- /dev/null
+++ b/spec/factories/appearances.rb
@@ -0,0 +1,8 @@
+# Read about factories at https://github.com/thoughtbot/factory_girl
+
+FactoryGirl.define do
+ factory :appearance do
+ title "MepMep"
+ description "This is my Community Edition instance"
+ end
+end
diff --git a/spec/features/issues/filter_by_milestone_spec.rb b/spec/features/issues/filter_by_milestone_spec.rb
index 38c8d343ce3..591866b40d4 100644
--- a/spec/features/issues/filter_by_milestone_spec.rb
+++ b/spec/features/issues/filter_by_milestone_spec.rb
@@ -13,7 +13,7 @@ feature 'Issue filtering by Milestone', feature: true do
visit_issues(project)
filter_by_milestone(Milestone::None.title)
- expect(page).to have_css('.title', count: 1)
+ expect(page).to have_css('.issue .title', count: 1)
end
scenario 'filters by a specific Milestone', js: true do
@@ -23,7 +23,7 @@ feature 'Issue filtering by Milestone', feature: true do
visit_issues(project)
filter_by_milestone(milestone.title)
- expect(page).to have_css('.title', count: 1)
+ expect(page).to have_css('.issue .title', count: 1)
end
def visit_issues(project)
diff --git a/spec/lib/banzai/filter/sanitization_filter_spec.rb b/spec/lib/banzai/filter/sanitization_filter_spec.rb
index e14a6dbf922..4a7b00c7660 100644
--- a/spec/lib/banzai/filter/sanitization_filter_spec.rb
+++ b/spec/lib/banzai/filter/sanitization_filter_spec.rb
@@ -156,13 +156,27 @@ describe Banzai::Filter::SanitizationFilter, lib: true do
}
protocols.each do |name, data|
- it "handles #{name}" do
+ it "disallows #{name}" do
doc = filter(data[:input])
expect(doc.to_html).to eq data[:output]
end
end
+ it 'disallows data links' do
+ input = '<a href="data:text/html;base64,PHNjcmlwdD5hbGVydCgnWFNTJyk8L3NjcmlwdD4K">XSS</a>'
+ output = filter(input)
+
+ expect(output.to_html).to eq '<a>XSS</a>'
+ end
+
+ it 'disallows vbscript links' do
+ input = '<a href="vbscript:alert(document.domain)">XSS</a>'
+ output = filter(input)
+
+ expect(output.to_html).to eq '<a>XSS</a>'
+ end
+
it 'allows non-standard anchor schemes' do
exp = %q{<a href="irc://irc.freenode.net/git">IRC</a>}
act = filter(exp)
diff --git a/spec/models/appearance_spec.rb b/spec/models/appearance_spec.rb
new file mode 100644
index 00000000000..c5658bd26e1
--- /dev/null
+++ b/spec/models/appearance_spec.rb
@@ -0,0 +1,10 @@
+require 'rails_helper'
+
+RSpec.describe Appearance, type: :model do
+ subject { create(:appearance) }
+
+ it { is_expected.to be_valid }
+
+ it { is_expected.to validate_presence_of(:title) }
+ it { is_expected.to validate_presence_of(:description) }
+end
diff --git a/spec/models/hooks/project_hook_spec.rb b/spec/models/hooks/project_hook_spec.rb
index 645ee0b929a..983848392b7 100644
--- a/spec/models/hooks/project_hook_spec.rb
+++ b/spec/models/hooks/project_hook_spec.rb
@@ -19,6 +19,10 @@
require 'spec_helper'
describe ProjectHook, models: true do
+ describe "Associations" do
+ it { is_expected.to belong_to :project }
+ end
+
describe '.push_hooks' do
it 'should return hooks for push events only' do
hook = create(:project_hook, push_events: true)
diff --git a/spec/models/hooks/web_hook_spec.rb b/spec/models/hooks/web_hook_spec.rb
index 7070aa4ac62..6ea99952a8f 100644
--- a/spec/models/hooks/web_hook_spec.rb
+++ b/spec/models/hooks/web_hook_spec.rb
@@ -18,20 +18,14 @@
require 'spec_helper'
-describe ProjectHook, models: true do
- describe "Associations" do
- it { is_expected.to belong_to :project }
- end
-
- describe "Mass assignment" do
- end
-
+describe WebHook, models: true do
describe "Validations" do
it { is_expected.to validate_presence_of(:url) }
- context "url format" do
+ describe 'url' do
it { is_expected.to allow_value("http://example.com").for(:url) }
- it { is_expected.to allow_value("https://excample.com").for(:url) }
+ it { is_expected.to allow_value("https://example.com").for(:url) }
+ it { is_expected.to allow_value(" https://example.com ").for(:url) }
it { is_expected.to allow_value("http://test.com/api").for(:url) }
it { is_expected.to allow_value("http://test.com/api?key=abc").for(:url) }
it { is_expected.to allow_value("http://test.com/api?key=abc&type=def").for(:url) }
@@ -39,6 +33,12 @@ describe ProjectHook, models: true do
it { is_expected.not_to allow_value("example.com").for(:url) }
it { is_expected.not_to allow_value("ftp://example.com").for(:url) }
it { is_expected.not_to allow_value("herp-and-derp").for(:url) }
+
+ it 'strips :url before saving it' do
+ hook = create(:project_hook, url: ' https://example.com ')
+
+ expect(hook.url).to eq('https://example.com')
+ end
end
end