Merge branch 'master' into issue_13212
This commit is contained in:
commit
4f529a8806
|
@ -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)
|
||||
|
|
1
Gemfile
1
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'
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
NProgress.configure(showSpinner: false)
|
||||
Turbolinks.enableProgressBar();
|
||||
|
||||
defaultClass = 'tanuki-shape'
|
||||
pieces = [
|
||||
|
|
|
@ -25,12 +25,6 @@
|
|||
*/
|
||||
@import "framework";
|
||||
|
||||
/*
|
||||
* NProgress load bar css
|
||||
*/
|
||||
@import 'nprogress';
|
||||
@import 'nprogress-bootstrap';
|
||||
|
||||
/*
|
||||
* Font icons
|
||||
*/
|
||||
|
|
|
@ -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";
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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) {
|
||||
|
|
|
@ -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
|
|
@ -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)
|
||||
base_query = project.forks.includes(:creator)
|
||||
|
||||
@public_forks, @protected_forks = @all_forks.partition do |project|
|
||||
can?(current_user, :read_project, project)
|
||||
end
|
||||
@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
|
||||
|
|
|
@ -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]
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)}
|
|
@ -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"
|
|
@ -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'
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
11
db/schema.rb
11
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"
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -1,39 +1,37 @@
|
|||
## GitLab CI Documentation
|
||||
|
||||
### User documentation
|
||||
### CI 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)
|
||||
- [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)
|
||||
|
||||
### Languages
|
||||
### CI Examples
|
||||
|
||||
* [Testing PHP](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](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.
|
||||
|
||||
### Services
|
||||
### CI 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)
|
||||
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:
|
||||
|
||||
### 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)
|
||||
- [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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
Binary file not shown.
After Width: | Height: | Size: 357 KiB |
Binary file not shown.
After Width: | Height: | Size: 307 KiB |
Binary file not shown.
After Width: | Height: | Size: 286 KiB |
|
@ -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
|
||||
Admin area > Settings
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
|
@ -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
|
||||
|
|
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
Loading…
Reference in New Issue