Merge branch 'master' into feature/import-export-docs
This commit is contained in:
commit
193d7079a6
|
@ -13,9 +13,11 @@ v 8.9.0 (unreleased)
|
|||
- Fix endless redirections when accessing user OAuth applications when they are disabled
|
||||
- Allow enabling wiki page events from Webhook management UI
|
||||
- Bump rouge to 1.11.0
|
||||
- Fix MR-auto-close text added to description
|
||||
- Fix issue with arrow keys not working in search autocomplete dropdown
|
||||
- Fix an issue where note polling stopped working if a window was in the
|
||||
background during a refresh.
|
||||
- Pre-processing Markdown now only happens when needed
|
||||
- Make EmailsOnPushWorker use Sidekiq mailers queue
|
||||
- Redesign all Devise emails. !4297
|
||||
- Don't show 'Leave Project' to group members
|
||||
|
@ -148,6 +150,7 @@ v 8.9.0 (unreleased)
|
|||
- Ensure Todos counters doesn't count Todos for projects pending delete
|
||||
- Add left/right arrows horizontal navigation
|
||||
- Add tooltip to pin/unpin navbar
|
||||
- Add new sub nav style to Wiki and Graphs sub navigation
|
||||
|
||||
v 8.8.5
|
||||
- Import GitHub repositories respecting the API rate limit !4166
|
||||
|
|
4
Gemfile
4
Gemfile
|
@ -48,7 +48,7 @@ gem 'attr_encrypted', '~> 3.0.0'
|
|||
gem 'u2f', '~> 0.2.1'
|
||||
|
||||
# Browser detection
|
||||
gem "browser", '~> 2.0.3'
|
||||
gem "browser", '~> 2.2'
|
||||
|
||||
# Extracting information from a git repository
|
||||
# Provide access to Gitlab::Git library
|
||||
|
@ -330,7 +330,7 @@ gem "newrelic_rpm", '~> 3.14'
|
|||
|
||||
gem 'octokit', '~> 4.3.0'
|
||||
|
||||
gem "mail_room", "~> 0.7"
|
||||
gem "mail_room", "~> 0.8"
|
||||
|
||||
gem 'email_reply_parser', '~> 0.5.8'
|
||||
|
||||
|
|
|
@ -98,7 +98,7 @@ GEM
|
|||
autoprefixer-rails (>= 5.2.1)
|
||||
sass (>= 3.3.4)
|
||||
brakeman (3.3.2)
|
||||
browser (2.0.3)
|
||||
browser (2.2.0)
|
||||
builder (3.2.2)
|
||||
bullet (5.0.0)
|
||||
activesupport (>= 3.0.0)
|
||||
|
@ -398,7 +398,7 @@ GEM
|
|||
systemu (~> 2.6.2)
|
||||
mail (2.6.4)
|
||||
mime-types (>= 1.16, < 4)
|
||||
mail_room (0.7.0)
|
||||
mail_room (0.8.0)
|
||||
method_source (0.8.2)
|
||||
mime-types (2.99.2)
|
||||
mimemagic (0.3.0)
|
||||
|
@ -833,7 +833,7 @@ DEPENDENCIES
|
|||
binding_of_caller (~> 0.7.2)
|
||||
bootstrap-sass (~> 3.3.0)
|
||||
brakeman (~> 3.3.0)
|
||||
browser (~> 2.0.3)
|
||||
browser (~> 2.2)
|
||||
bullet
|
||||
bundler-audit
|
||||
byebug
|
||||
|
@ -899,7 +899,7 @@ DEPENDENCIES
|
|||
license_finder
|
||||
licensee (~> 8.0.0)
|
||||
loofah (~> 2.0.3)
|
||||
mail_room (~> 0.7)
|
||||
mail_room (~> 0.8)
|
||||
method_source (~> 0.8)
|
||||
minitest (~> 5.7.0)
|
||||
mousetrap-rails (~> 1.4.6)
|
||||
|
|
|
@ -121,6 +121,11 @@ window.onload = ->
|
|||
setTimeout shiftWindow, 100
|
||||
|
||||
$ ->
|
||||
|
||||
$document = $(document)
|
||||
$window = $(window)
|
||||
$body = $('body')
|
||||
|
||||
gl.utils.preventDisabledButtons()
|
||||
bootstrapBreakpoint = bp.getBreakpointSize()
|
||||
|
||||
|
@ -152,7 +157,7 @@ $ ->
|
|||
), 1
|
||||
|
||||
# Initialize tooltips
|
||||
$('body').tooltip(
|
||||
$body.tooltip(
|
||||
selector: '.has-tooltip, [data-toggle="tooltip"]'
|
||||
placement: (_, el) ->
|
||||
$el = $(el)
|
||||
|
@ -171,7 +176,7 @@ $ ->
|
|||
flash.show()
|
||||
|
||||
# Disable form buttons while a form is submitting
|
||||
$('body').on 'ajax:complete, ajax:beforeSend, submit', 'form', (e) ->
|
||||
$body.on 'ajax:complete, ajax:beforeSend, submit', 'form', (e) ->
|
||||
buttons = $('[type="submit"]', @)
|
||||
|
||||
switch e.type
|
||||
|
@ -184,7 +189,7 @@ $ ->
|
|||
$('.account-box').hover -> $(@).toggleClass('hover')
|
||||
|
||||
# Commit show suppressed diff
|
||||
$(document).on 'click', '.diff-content .js-show-suppressed-diff', ->
|
||||
$document.on 'click', '.diff-content .js-show-suppressed-diff', ->
|
||||
$container = $(@).parent()
|
||||
$container.next('table').show()
|
||||
$container.remove()
|
||||
|
@ -197,13 +202,13 @@ $ ->
|
|||
$('.navbar-toggle i').toggleClass("fa-angle-right fa-angle-left")
|
||||
|
||||
# Show/hide comments on diff
|
||||
$("body").on "click", ".js-toggle-diff-comments", (e) ->
|
||||
$body.on "click", ".js-toggle-diff-comments", (e) ->
|
||||
$(@).toggleClass('active')
|
||||
$(@).closest(".diff-file").find(".notes_holder").toggle()
|
||||
e.preventDefault()
|
||||
|
||||
$(document).off "click", '.js-confirm-danger'
|
||||
$(document).on "click", '.js-confirm-danger', (e) ->
|
||||
$document.off "click", '.js-confirm-danger'
|
||||
$document.on "click", '.js-confirm-danger', (e) ->
|
||||
e.preventDefault()
|
||||
btn = $(e.target)
|
||||
text = btn.data("confirm-danger-message")
|
||||
|
@ -211,7 +216,7 @@ $ ->
|
|||
new ConfirmDangerModal(form, text)
|
||||
|
||||
|
||||
$(document).on 'click', 'button', ->
|
||||
$document.on 'click', 'button', ->
|
||||
$(this).blur()
|
||||
|
||||
$('input[type="search"]').each ->
|
||||
|
@ -219,7 +224,7 @@ $ ->
|
|||
$this.attr 'value', $this.val()
|
||||
return
|
||||
|
||||
$(document)
|
||||
$document
|
||||
.off 'keyup', 'input[type="search"]'
|
||||
.on 'keyup', 'input[type="search"]' , (e) ->
|
||||
$this = $(this)
|
||||
|
@ -227,7 +232,7 @@ $ ->
|
|||
|
||||
$sidebarGutterToggle = $('.js-sidebar-toggle')
|
||||
|
||||
$(document)
|
||||
$document
|
||||
.off 'breakpoint:change'
|
||||
.on 'breakpoint:change', (e, breakpoint) ->
|
||||
if breakpoint is 'sm' or breakpoint is 'xs'
|
||||
|
@ -239,14 +244,14 @@ $ ->
|
|||
oldBootstrapBreakpoint = bootstrapBreakpoint
|
||||
bootstrapBreakpoint = bp.getBreakpointSize()
|
||||
if bootstrapBreakpoint != oldBootstrapBreakpoint
|
||||
$(document).trigger('breakpoint:change', [bootstrapBreakpoint])
|
||||
$document.trigger('breakpoint:change', [bootstrapBreakpoint])
|
||||
|
||||
checkInitialSidebarSize = ->
|
||||
bootstrapBreakpoint = bp.getBreakpointSize()
|
||||
if bootstrapBreakpoint is "xs" or "sm"
|
||||
$(document).trigger('breakpoint:change', [bootstrapBreakpoint])
|
||||
$document.trigger('breakpoint:change', [bootstrapBreakpoint])
|
||||
|
||||
$(window)
|
||||
$window
|
||||
.off "resize.app"
|
||||
.on "resize.app", (e) ->
|
||||
fitSidebarForSize()
|
||||
|
@ -256,14 +261,14 @@ $ ->
|
|||
new Aside()
|
||||
|
||||
# Sidenav pinning
|
||||
if $(window).width() < 1440 and $.cookie('pin_nav') is 'true'
|
||||
if $window.width() < 1440 and $.cookie('pin_nav') is 'true'
|
||||
$.cookie('pin_nav', 'false', { path: '/' })
|
||||
$('.page-with-sidebar')
|
||||
.toggleClass('page-sidebar-collapsed page-sidebar-expanded')
|
||||
.removeClass('page-sidebar-pinned')
|
||||
$('.navbar-fixed-top').removeClass('header-pinned-nav')
|
||||
|
||||
$(document)
|
||||
$document
|
||||
.off 'click', '.js-nav-pin'
|
||||
.on 'click', '.js-nav-pin', (e) ->
|
||||
e.preventDefault()
|
||||
|
|
|
@ -121,7 +121,11 @@ class @ContributorsMasterGraph extends ContributorsGraph
|
|||
|
||||
class @ContributorsAuthorGraph extends ContributorsGraph
|
||||
constructor: (@data) ->
|
||||
@width = $('.content').width()/2 - 100
|
||||
# Don't split graph size in half for mobile devices.
|
||||
if $(window).width() < 768
|
||||
@width = $('.content').width() - 80
|
||||
else
|
||||
@width = ($('.content').width() / 2) - 100
|
||||
@height = 200
|
||||
@x = null
|
||||
@y = null
|
||||
|
|
|
@ -97,6 +97,22 @@
|
|||
}
|
||||
}
|
||||
|
||||
.sub-header-block {
|
||||
background-color: $white-light;
|
||||
border-bottom: 1px solid $white-dark;
|
||||
padding: 11px 0;
|
||||
margin-bottom: 11px;
|
||||
|
||||
.oneline {
|
||||
line-height: 35px;
|
||||
}
|
||||
|
||||
&.no-bottom-space {
|
||||
border-bottom: 0;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.cover-block {
|
||||
text-align: center;
|
||||
background: $background-color;
|
||||
|
|
|
@ -461,10 +461,12 @@
|
|||
}
|
||||
}
|
||||
|
||||
.ui-state-active,
|
||||
.ui-state-hover {
|
||||
color: $md-link-color;
|
||||
background-color: $calendar-hover-bg;
|
||||
.ui-datepicker-calendar {
|
||||
.ui-state-hover,
|
||||
.ui-state-active {
|
||||
color: #fff;
|
||||
border: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.ui-datepicker-prev,
|
||||
|
|
|
@ -111,10 +111,6 @@
|
|||
width: 50%;
|
||||
line-height: 28px;
|
||||
|
||||
&.wiki-page {
|
||||
padding: 16px 10px 11px;
|
||||
}
|
||||
|
||||
/* Small devices (phones, tablets, 768px and lower) */
|
||||
@media (max-width: $screen-sm-min) {
|
||||
width: 100%;
|
||||
|
|
|
@ -91,7 +91,6 @@
|
|||
text-decoration: none;
|
||||
font-weight: normal;
|
||||
outline: none;
|
||||
white-space: nowrap;
|
||||
|
||||
&:hover,
|
||||
&:active,
|
||||
|
|
|
@ -50,11 +50,10 @@
|
|||
|
||||
.label-row {
|
||||
.label-name {
|
||||
display: block;
|
||||
display: inline-block;
|
||||
margin-bottom: 10px;
|
||||
|
||||
@media (min-width: $screen-sm-min) {
|
||||
display: inline-block;
|
||||
width: 200px;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
@ -63,6 +62,7 @@
|
|||
.label-description {
|
||||
display: block;
|
||||
margin-bottom: 10px;
|
||||
margin-left: 50px;
|
||||
|
||||
@media (min-width: $screen-sm-min) {
|
||||
display: inline-block;
|
||||
|
|
|
@ -14,24 +14,38 @@
|
|||
font-size: 10px;
|
||||
}
|
||||
|
||||
#contributors-master {
|
||||
@include make-md-column(12);
|
||||
|
||||
svg {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
#contributors {
|
||||
.contributors-list {
|
||||
margin: 0 0 10px;
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
|
||||
svg {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.person {
|
||||
&:nth-child(even) {
|
||||
float: right;
|
||||
}
|
||||
float: left;
|
||||
@include make-md-column(6);
|
||||
margin-top: 10px;
|
||||
|
||||
@media (max-width: $screen-sm-min) {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.person .spark {
|
||||
display: block;
|
||||
background: #f3f3f3;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.person .area-contributor {
|
||||
|
|
|
@ -5,6 +5,7 @@ class Admin::AppearancesController < Admin::ApplicationController
|
|||
end
|
||||
|
||||
def preview
|
||||
render 'preview', layout: 'devise'
|
||||
end
|
||||
|
||||
def create
|
||||
|
|
|
@ -36,6 +36,10 @@ class ApplicationController < ActionController::Base
|
|||
render_404
|
||||
end
|
||||
|
||||
rescue_from Gitlab::Access::AccessDeniedError do |exception|
|
||||
render_403
|
||||
end
|
||||
|
||||
def redirect_back_or_default(default: root_path, options: {})
|
||||
redirect_to request.referer.present? ? :back : default, options
|
||||
end
|
||||
|
|
|
@ -21,29 +21,18 @@ module MembershipActions
|
|||
|
||||
def leave
|
||||
@member = membershipable.members.find_by(user_id: current_user)
|
||||
return render_403 unless @member
|
||||
Members::DestroyService.new(@member, current_user).execute
|
||||
|
||||
source_type = @member.real_source_type.humanize(capitalize: false)
|
||||
|
||||
if can?(current_user, action_member_permission(:destroy, @member), @member)
|
||||
notice =
|
||||
if @member.request?
|
||||
"Your access request to the #{source_type} has been withdrawn."
|
||||
else
|
||||
"You left the \"#{@member.source.human_name}\" #{source_type}."
|
||||
end
|
||||
@member.destroy
|
||||
|
||||
redirect_to [:dashboard, @member.real_source_type.tableize], notice: notice
|
||||
else
|
||||
if cannot_leave?
|
||||
alert = "You can not leave the \"#{@member.source.human_name}\" #{source_type}."
|
||||
alert << " Transfer or delete the #{source_type}."
|
||||
redirect_to polymorphic_url(membershipable), alert: alert
|
||||
notice =
|
||||
if @member.request?
|
||||
"Your access request to the #{source_type} has been withdrawn."
|
||||
else
|
||||
render_403
|
||||
"You left the \"#{@member.source.human_name}\" #{source_type}."
|
||||
end
|
||||
end
|
||||
redirect_path = @member.request? ? @member.source : [:dashboard, @member.real_source_type.tableize]
|
||||
|
||||
redirect_to redirect_path, notice: notice
|
||||
end
|
||||
|
||||
protected
|
||||
|
@ -51,8 +40,4 @@ module MembershipActions
|
|||
def membershipable
|
||||
raise NotImplementedError
|
||||
end
|
||||
|
||||
def cannot_leave?
|
||||
raise NotImplementedError
|
||||
end
|
||||
end
|
||||
|
|
|
@ -36,9 +36,7 @@ class Groups::GroupMembersController < Groups::ApplicationController
|
|||
def destroy
|
||||
@group_member = @group.group_members.find(params[:id])
|
||||
|
||||
return render_403 unless can?(current_user, :destroy_group_member, @group_member)
|
||||
|
||||
@group_member.destroy
|
||||
Members::DestroyService.new(@group_member, current_user).execute
|
||||
|
||||
respond_to do |format|
|
||||
format.html { redirect_to group_group_members_path(@group), notice: 'User was successfully removed from group.' }
|
||||
|
@ -68,8 +66,4 @@ class Groups::GroupMembersController < Groups::ApplicationController
|
|||
|
||||
# MembershipActions concern
|
||||
alias_method :membershipable, :group
|
||||
|
||||
def cannot_leave?
|
||||
@group.last_owner?(current_user)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -50,9 +50,7 @@ class Projects::ProjectMembersController < Projects::ApplicationController
|
|||
def destroy
|
||||
@project_member = @project.project_members.find(params[:id])
|
||||
|
||||
return render_403 unless can?(current_user, :destroy_project_member, @project_member)
|
||||
|
||||
@project_member.destroy
|
||||
Members::DestroyService.new(@project_member, current_user).execute
|
||||
|
||||
respond_to do |format|
|
||||
format.html do
|
||||
|
@ -98,8 +96,4 @@ class Projects::ProjectMembersController < Projects::ApplicationController
|
|||
|
||||
# MembershipActions concern
|
||||
alias_method :membershipable, :project
|
||||
|
||||
def cannot_leave?
|
||||
current_user == @project.owner
|
||||
end
|
||||
end
|
||||
|
|
|
@ -50,8 +50,6 @@ module GitlabMarkdownHelper
|
|||
|
||||
context[:project] ||= @project
|
||||
|
||||
text = Banzai.pre_process(text, context)
|
||||
|
||||
html = Banzai.render(text, context)
|
||||
|
||||
context.merge!(
|
||||
|
|
|
@ -48,7 +48,6 @@ class Member < ActiveRecord::Base
|
|||
after_create :post_create_hook, unless: [:pending?, :importing?]
|
||||
after_update :post_update_hook, unless: [:pending?, :importing?]
|
||||
after_destroy :post_destroy_hook, unless: :pending?
|
||||
after_destroy :post_decline_request, if: :request?
|
||||
|
||||
delegate :name, :username, :email, to: :user, prefix: true
|
||||
|
||||
|
@ -188,7 +187,7 @@ class Member < ActiveRecord::Base
|
|||
end
|
||||
|
||||
def send_request
|
||||
# override in subclass
|
||||
notification_service.new_access_request(self)
|
||||
end
|
||||
|
||||
def post_create_hook
|
||||
|
@ -215,10 +214,6 @@ class Member < ActiveRecord::Base
|
|||
post_create_hook
|
||||
end
|
||||
|
||||
def post_decline_request
|
||||
# override in subclass
|
||||
end
|
||||
|
||||
def system_hook_service
|
||||
SystemHooksService.new
|
||||
end
|
||||
|
|
|
@ -33,12 +33,6 @@ class GroupMember < Member
|
|||
super
|
||||
end
|
||||
|
||||
def send_request
|
||||
notification_service.new_group_access_request(self)
|
||||
|
||||
super
|
||||
end
|
||||
|
||||
def post_create_hook
|
||||
notification_service.new_group_member(self)
|
||||
|
||||
|
@ -64,10 +58,4 @@ class GroupMember < Member
|
|||
|
||||
super
|
||||
end
|
||||
|
||||
def post_decline_request
|
||||
notification_service.decline_group_access_request(self)
|
||||
|
||||
super
|
||||
end
|
||||
end
|
||||
|
|
|
@ -111,12 +111,6 @@ class ProjectMember < Member
|
|||
super
|
||||
end
|
||||
|
||||
def send_request
|
||||
notification_service.new_project_access_request(self)
|
||||
|
||||
super
|
||||
end
|
||||
|
||||
def post_create_hook
|
||||
unless owner?
|
||||
event_service.join_project(self.project, self.user)
|
||||
|
@ -152,12 +146,6 @@ class ProjectMember < Member
|
|||
super
|
||||
end
|
||||
|
||||
def post_decline_request
|
||||
notification_service.decline_project_access_request(self)
|
||||
|
||||
super
|
||||
end
|
||||
|
||||
def event_service
|
||||
EventCreateService.new
|
||||
end
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
module Members
|
||||
class DestroyService < BaseService
|
||||
attr_accessor :member, :current_user
|
||||
|
||||
def initialize(member, user)
|
||||
@member, @current_user = member, user
|
||||
end
|
||||
|
||||
def execute
|
||||
unless member && can?(current_user, "destroy_#{member.type.underscore}".to_sym, member)
|
||||
raise Gitlab::Access::AccessDeniedError
|
||||
end
|
||||
|
||||
member.destroy
|
||||
|
||||
if member.request? && member.user != current_user
|
||||
notification_service.decline_access_request(member)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -83,7 +83,7 @@ module MergeRequests
|
|||
closes_issue = "Closes ##{iid}"
|
||||
|
||||
if merge_request.description.present?
|
||||
merge_request.description << closes_issue.prepend("\n")
|
||||
merge_request.description += closes_issue.prepend("\n")
|
||||
else
|
||||
merge_request.description = closes_issue
|
||||
end
|
||||
|
|
|
@ -181,15 +181,16 @@ class NotificationService
|
|||
end
|
||||
end
|
||||
|
||||
# Project access request
|
||||
def new_project_access_request(project_member)
|
||||
mailer.member_access_requested_email(project_member.real_source_type, project_member.id).deliver_later
|
||||
# Members
|
||||
def new_access_request(member)
|
||||
mailer.member_access_requested_email(member.real_source_type, member.id).deliver_later
|
||||
end
|
||||
|
||||
def decline_project_access_request(project_member)
|
||||
mailer.member_access_denied_email(project_member.real_source_type, project_member.project.id, project_member.user.id).deliver_later
|
||||
def decline_access_request(member)
|
||||
mailer.member_access_denied_email(member.real_source_type, member.source_id, member.user_id).deliver_later
|
||||
end
|
||||
|
||||
# Project invite
|
||||
def invite_project_member(project_member, token)
|
||||
mailer.member_invited_email(project_member.real_source_type, project_member.id, token).deliver_later
|
||||
end
|
||||
|
@ -216,15 +217,7 @@ class NotificationService
|
|||
mailer.member_access_granted_email(project_member.real_source_type, project_member.id).deliver_later
|
||||
end
|
||||
|
||||
# Group access request
|
||||
def new_group_access_request(group_member)
|
||||
mailer.member_access_requested_email(group_member.real_source_type, group_member.id).deliver_later
|
||||
end
|
||||
|
||||
def decline_group_access_request(group_member)
|
||||
mailer.member_access_denied_email(group_member.real_source_type, group_member.group.id, group_member.user.id).deliver_later
|
||||
end
|
||||
|
||||
# Group invite
|
||||
def invite_group_member(group_member, token)
|
||||
mailer.member_invited_email(group_member.real_source_type, group_member.id, token).deliver_later
|
||||
end
|
||||
|
|
|
@ -46,7 +46,7 @@
|
|||
Maximum file size is 1MB. Pages are optimized for a 72x72 px header logo
|
||||
|
||||
.form-actions
|
||||
= f.submit 'Save', class: 'btn btn-save'
|
||||
= f.submit 'Save', class: 'btn btn-save append-right-10'
|
||||
- if @appearance.persisted?
|
||||
= link_to 'Preview last save', preview_admin_appearances_path, class: 'btn', target: '_blank'
|
||||
|
||||
|
|
|
@ -1,29 +1,9 @@
|
|||
- page_title "Preview | Appearance"
|
||||
%h3.page-title
|
||||
Appearance settings - Preview
|
||||
%hr
|
||||
.login-box
|
||||
.login-heading
|
||||
%h3 Existing user? Sign in
|
||||
%form
|
||||
= 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"
|
||||
|
||||
.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"
|
||||
|
|
|
@ -88,28 +88,17 @@
|
|||
= select_tag :access_level, options_for_select(GroupMember.access_level_roles), class: "project-access-select select2"
|
||||
%hr
|
||||
= button_tag 'Add users to group', class: "btn btn-create"
|
||||
|
||||
= render 'shared/members/requests', membership_source: @group, members: @members.request
|
||||
|
||||
.panel.panel-default
|
||||
.panel-heading
|
||||
%h3.panel-title
|
||||
Members
|
||||
%span.badge
|
||||
#{@group.group_members.count}
|
||||
%ul.well-list.group-users-list
|
||||
- @members.each do |member|
|
||||
- user = member.user
|
||||
%li{class: dom_class(member), id: (dom_id(user) if user)}
|
||||
.list-item-name
|
||||
- if user
|
||||
%strong
|
||||
= link_to user.name, admin_user_path(user)
|
||||
- else
|
||||
%strong
|
||||
= member.invite_email
|
||||
(invited)
|
||||
%span.pull-right.light
|
||||
= member.human_access
|
||||
- if can?(current_user, :destroy_group_member, member)
|
||||
= link_to group_group_member_path(@group, member), data: { confirm: remove_member_message(member) }, method: :delete, remote: true, class: "btn-xs btn btn-remove", title: 'Remove user from group' do
|
||||
%i.fa.fa-minus.fa-inverse
|
||||
%strong= @group.name
|
||||
group members
|
||||
%span.badge= @group.members.non_request.size
|
||||
.pull-right
|
||||
= link_to icon('pencil-square-o', text: 'Manage Access'), polymorphic_url([@group, :members]), class: "btn btn-xs"
|
||||
%ul.well-list.group-users-list.content-list
|
||||
= render partial: 'shared/members/member', collection: @members.non_request, as: :member, locals: { show_controls: false }
|
||||
.panel-footer
|
||||
= paginate @members, param_name: 'members_page', theme: 'gitlab'
|
||||
= paginate @members.non_request, param_name: 'members_page', theme: 'gitlab'
|
||||
|
|
|
@ -135,44 +135,27 @@
|
|||
- if @group
|
||||
.panel.panel-default
|
||||
.panel-heading
|
||||
%strong #{@group.name}
|
||||
group members (#{@group.group_members.count})
|
||||
%strong= @group.name
|
||||
group members
|
||||
%span.badge= @group_members.non_request.size
|
||||
.pull-right
|
||||
= link_to admin_group_path(@group), class: 'btn btn-xs' do
|
||||
%i.fa.fa-pencil-square-o
|
||||
%ul.well-list
|
||||
- @group_members.each do |member|
|
||||
= render 'shared/members/member', member: member, show_controls: false
|
||||
= icon('pencil-square-o', text: 'Manage Access')
|
||||
%ul.well-list.content-list
|
||||
= render partial: 'shared/members/member', collection: @group_members.non_request, as: :member, locals: { show_controls: false }
|
||||
.panel-footer
|
||||
= paginate @group_members, param_name: 'group_members_page', theme: 'gitlab'
|
||||
= paginate @group_members.non_request, param_name: 'group_members_page', theme: 'gitlab'
|
||||
|
||||
= render 'shared/members/requests', membership_source: @project, members: @project_members.request
|
||||
|
||||
.panel.panel-default
|
||||
.panel-heading
|
||||
Project members
|
||||
%small
|
||||
(#{@project.users.count})
|
||||
%strong= @project.name
|
||||
project members
|
||||
%span.badge= @project.users.size
|
||||
.pull-right
|
||||
= link_to namespace_project_project_members_path(@project.namespace, @project), class: "btn btn-xs" do
|
||||
%i.fa.fa-pencil-square-o
|
||||
Manage Access
|
||||
%ul.well-list.project_members
|
||||
- @project_members.each do |project_member|
|
||||
- user = project_member.user
|
||||
%li.project_member
|
||||
.list-item-name
|
||||
- if user
|
||||
%strong
|
||||
= link_to user.name, admin_user_path(user)
|
||||
- else
|
||||
%strong
|
||||
= project_member.invite_email
|
||||
(invited)
|
||||
.pull-right
|
||||
- if project_member.owner?
|
||||
%span.light Owner
|
||||
- else
|
||||
%span.light= project_member.human_access
|
||||
= link_to namespace_project_project_member_path(@project.namespace, @project, project_member), data: { confirm: remove_member_message(project_member)}, method: :delete, remote: true, class: "btn btn-sm btn-remove" do
|
||||
%i.fa.fa-times
|
||||
= link_to icon('pencil-square-o', text: 'Manage Access'), polymorphic_url([@project, :members]), class: "btn btn-xs"
|
||||
%ul.well-list.project_members.content-list
|
||||
= render partial: 'shared/members/member', collection: @project_members.non_request, as: :member, locals: { show_controls: false }
|
||||
.panel-footer
|
||||
= paginate @project_members, param_name: 'project_members_page', theme: 'gitlab'
|
||||
= paginate @project_members.non_request, param_name: 'project_members_page', theme: 'gitlab'
|
||||
|
|
|
@ -17,8 +17,7 @@
|
|||
.panel-heading
|
||||
%strong #{@group.name}
|
||||
group members
|
||||
%small
|
||||
(#{@members.total_count})
|
||||
%span.badge= @members.non_request.size
|
||||
.controls
|
||||
= form_tag group_group_members_path(@group), method: :get, class: 'form-inline member-search-form' do
|
||||
.form-group
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
= render 'layouts/nav/admin_settings'
|
||||
|
||||
%ul.nav-links.scrolling-tabs
|
||||
.fade-left
|
||||
%li.fade-left
|
||||
= icon('arrow-left')
|
||||
= nav_link(controller: %w(dashboard admin projects users groups builds runners), html_options: {class: 'home'}) do
|
||||
= link_to admin_root_path, title: 'Overview', class: 'shortcuts-tree' do
|
||||
|
@ -37,5 +37,5 @@
|
|||
= link_to admin_spam_logs_path, title: "Spam Logs" do
|
||||
%span
|
||||
Spam Logs
|
||||
.fade-right
|
||||
%li.fade-right
|
||||
= icon('arrow-right')
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
= render 'layouts/nav/group_settings'
|
||||
|
||||
%ul.nav-links.scrolling-tabs
|
||||
.fade-left
|
||||
%li.fade-left
|
||||
= icon('arrow-left')
|
||||
= nav_link(path: 'groups#show', html_options: {class: 'home'}) do
|
||||
= link_to group_path(@group), title: 'Home' do
|
||||
|
@ -32,5 +32,5 @@
|
|||
= link_to group_group_members_path(@group), title: 'Members' do
|
||||
%span
|
||||
Members
|
||||
.fade-right
|
||||
%li.fade-right
|
||||
= icon('arrow-right')
|
||||
|
|
|
@ -1,16 +1,22 @@
|
|||
- if current_user
|
||||
- if access = @group.users.find_by(id: current_user.id)
|
||||
.controls
|
||||
.dropdown.group-settings-dropdown
|
||||
%a.dropdown-new.btn.btn-default#group-settings-button{href: '#', 'data-toggle' => 'dropdown'}
|
||||
= icon('cog')
|
||||
= icon('caret-down')
|
||||
%ul.dropdown-menu.dropdown-menu-align-right
|
||||
- if can?(current_user, :admin_group, @group)
|
||||
= nav_link(path: 'groups#projects') do
|
||||
= link_to projects_group_path(@group), title: 'Projects' do
|
||||
Projects
|
||||
%li.divider
|
||||
%li
|
||||
= link_to edit_group_path(@group) do
|
||||
Edit Group
|
||||
- can_edit = can?(current_user, :admin_group, @group)
|
||||
- member = @group.members.non_request.find_by(user_id: current_user.id)
|
||||
- can_leave = member && can?(current_user, :destroy_group_member, member)
|
||||
|
||||
.controls
|
||||
.dropdown.group-settings-dropdown
|
||||
%a.dropdown-new.btn.btn-default#group-settings-button{href: '#', 'data-toggle' => 'dropdown'}
|
||||
= icon('cog')
|
||||
= icon('caret-down')
|
||||
%ul.dropdown-menu.dropdown-menu-align-right
|
||||
= nav_link(path: 'groups#projects') do
|
||||
= link_to 'Projects', projects_group_path(@group), title: 'Projects'
|
||||
%li.divider
|
||||
- if can_edit
|
||||
%li
|
||||
= link_to 'Edit Group', edit_group_path(@group)
|
||||
- if can_leave
|
||||
%li
|
||||
= link_to polymorphic_path([:leave, @group, :members]),
|
||||
data: { confirm: leave_confirmation_message(@group) }, method: :delete, title: 'Leave group' do
|
||||
Leave Group
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
%ul.nav-links.scrolling-tabs
|
||||
.fade-left
|
||||
%li.fade-left
|
||||
= icon('arrow-left')
|
||||
= nav_link(path: 'profiles#show', html_options: {class: 'home'}) do
|
||||
= link_to profile_path, title: 'Profile Settings' do
|
||||
|
@ -44,5 +44,5 @@
|
|||
= link_to audit_log_profile_path, title: 'Audit Log' do
|
||||
%span
|
||||
Audit Log
|
||||
.fade-right
|
||||
%li.fade-right
|
||||
= icon('arrow-right')
|
||||
|
|
|
@ -5,19 +5,20 @@
|
|||
= icon('cog')
|
||||
= icon('caret-down')
|
||||
%ul.dropdown-menu.dropdown-menu-align-right
|
||||
- is_project_member = @project.users.exists?(current_user.id)
|
||||
- access = @project.team.max_member_access(current_user.id)
|
||||
- can_edit = can?(current_user, :admin_project, @project)
|
||||
-# We don't use @project.team.find_member because it searches for group members too...
|
||||
- member = @project.members.non_request.find_by(user_id: current_user.id)
|
||||
- can_leave = member && can?(current_user, :destroy_project_member, member)
|
||||
|
||||
= render 'layouts/nav/project_settings', access: access, can_edit: can_edit
|
||||
= render 'layouts/nav/project_settings', can_edit: can_edit
|
||||
|
||||
- if can_edit || is_project_member
|
||||
- if can_edit || can_leave
|
||||
%li.divider
|
||||
- if can_edit
|
||||
%li
|
||||
= link_to edit_project_path(@project) do
|
||||
Edit Project
|
||||
- if is_project_member
|
||||
- if can_leave
|
||||
%li
|
||||
= link_to polymorphic_path([:leave, @project, :members]),
|
||||
data: { confirm: leave_confirmation_message(@project) }, method: :delete, title: 'Leave project' do
|
||||
|
@ -25,7 +26,7 @@
|
|||
|
||||
%div{ class: nav_control_class }
|
||||
%ul.nav-links.scrolling-tabs
|
||||
.fade-left
|
||||
%li.fade-left
|
||||
= icon('arrow-left')
|
||||
= nav_link(path: 'projects#show', html_options: {class: 'home'}) do
|
||||
= link_to project_path(@project), title: 'Project', class: 'shortcuts-project' do
|
||||
|
@ -39,9 +40,9 @@
|
|||
|
||||
- if project_nav_tab? :files
|
||||
= nav_link(controller: %w(tree blob blame edit_tree new_tree find_file commit commits compare repositories tags branches releases network)) do
|
||||
= link_to project_files_path(@project), title: 'Code', class: 'shortcuts-tree' do
|
||||
= link_to project_files_path(@project), title: 'Repository', class: 'shortcuts-tree' do
|
||||
%span
|
||||
Code
|
||||
Repository
|
||||
|
||||
- if project_nav_tab? :pipelines
|
||||
= nav_link(controller: [:pipelines, :builds, :environments]) do
|
||||
|
@ -110,5 +111,5 @@
|
|||
%li.hidden
|
||||
= link_to project_commits_path(@project), title: 'Commits', class: 'shortcuts-commits' do
|
||||
Commits
|
||||
.fade-right
|
||||
%li.fade-right
|
||||
= icon('arrow-right')
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
= link_to namespace_project_project_members_path(@project.namespace, @project), title: 'Members', class: 'team-tab tab' do
|
||||
%span
|
||||
Members
|
||||
- if access && can_edit
|
||||
- if can_edit
|
||||
- if @project.allowed_to_share_with_group?
|
||||
= nav_link(controller: :group_links) do
|
||||
= link_to namespace_project_group_links_path(@project.namespace, @project), title: "Groups" do
|
||||
|
|
|
@ -6,4 +6,4 @@
|
|||
%ul
|
||||
- @errors.each do |error|
|
||||
%li
|
||||
error
|
||||
#{error}
|
||||
|
|
|
@ -1,6 +0,0 @@
|
|||
Project <%= @project.name %> couldn't be exported.
|
||||
|
||||
The errors we encountered were:
|
||||
|
||||
- @errors.each do |error|
|
||||
<%= error %>
|
|
@ -0,0 +1,6 @@
|
|||
= "Project #{@project.name} couldn't be exported."
|
||||
|
||||
= "The errors we encountered were:"
|
||||
|
||||
- @errors.each do |error|
|
||||
#{error}
|
|
@ -1,7 +1,7 @@
|
|||
.scrolling-tabs-container
|
||||
.nav-links.sub-nav.scrolling-tabs
|
||||
%ul{ class: (container_class) }
|
||||
.fade-left
|
||||
%li.fade-left
|
||||
= icon('arrow-left')
|
||||
= nav_link(controller: %w(tree blob blame edit_tree new_tree find_file)) do
|
||||
= link_to project_files_path(@project) do
|
||||
|
@ -26,5 +26,5 @@
|
|||
= nav_link(controller: [:tags, :releases]) do
|
||||
= link_to namespace_project_tags_path(@project.namespace, @project) do
|
||||
Tags
|
||||
.fade-right
|
||||
%li.fade-right
|
||||
= icon('arrow-right')
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
= render "projects/commits/head"
|
||||
|
||||
%div{ class: (container_class) }
|
||||
.row-content-block.second-block.content-component-block
|
||||
.sub-header-block
|
||||
Compare branches, tags or commit ranges.
|
||||
%br
|
||||
Fill input field with commit id like
|
||||
|
|
|
@ -1,24 +1,24 @@
|
|||
- @no_container = true
|
||||
- page_title "#{params[:from]}...#{params[:to]}"
|
||||
= render "projects/commits/head"
|
||||
|
||||
%div{ class: (container_class) }
|
||||
.sub-header-block.no-bottom-space
|
||||
= render "form"
|
||||
|
||||
.row-content-block
|
||||
= render "form"
|
||||
|
||||
- if @commits.present?
|
||||
.prepend-top-default
|
||||
- if @commits.present?
|
||||
= render "projects/commits/commit_list"
|
||||
= render "projects/diffs/diffs", diffs: @diffs, project: @project, diff_refs: @diff_refs
|
||||
- else
|
||||
.light-well.prepend-top-default
|
||||
.center
|
||||
%h4
|
||||
There isn't anything to compare.
|
||||
%p.slead
|
||||
- if params[:to] == params[:from]
|
||||
%span.label-branch #{params[:from]}
|
||||
and
|
||||
%span.label-branch #{params[:to]}
|
||||
are the same.
|
||||
- else
|
||||
You'll need to use different branch names to get a valid comparison.
|
||||
- else
|
||||
.light-well
|
||||
.center
|
||||
%h4
|
||||
There isn't anything to compare.
|
||||
%p.slead
|
||||
- if params[:to] == params[:from]
|
||||
%span.label-branch #{params[:from]}
|
||||
and
|
||||
%span.label-branch #{params[:to]}
|
||||
are the same.
|
||||
- else
|
||||
You'll need to use different branch names to get a valid comparison.
|
||||
|
|
|
@ -40,9 +40,3 @@
|
|||
|
||||
|
||||
= render 'projects', projects: @forks
|
||||
|
||||
- if @private_forks_count > 0
|
||||
.private-forks-notice
|
||||
= icon('lock fw', base: 'circle', class: 'fa-lg private-fork-icon')
|
||||
%strong= pluralize(@private_forks_count, 'private fork')
|
||||
%span you have no access to.
|
||||
|
|
|
@ -1,12 +1,14 @@
|
|||
- page_specific_javascripts asset_path("graphs/application.js")
|
||||
%ul.nav-links
|
||||
= nav_link(action: :show) do
|
||||
= link_to 'Contributors', namespace_project_graph_path
|
||||
= nav_link(action: :commits) do
|
||||
= link_to 'Commits', commits_namespace_project_graph_path
|
||||
= nav_link(action: :languages) do
|
||||
= link_to 'Languages', languages_namespace_project_graph_path
|
||||
- if @project.builds_enabled?
|
||||
= nav_link(action: :ci) do
|
||||
= link_to ci_namespace_project_graph_path do
|
||||
Continuous Integration
|
||||
.nav-links.sub-nav
|
||||
%ul{ class: (container_class) }
|
||||
|
||||
- page_specific_javascripts asset_path("graphs/application.js")
|
||||
= nav_link(action: :show) do
|
||||
= link_to 'Contributors', namespace_project_graph_path
|
||||
= nav_link(action: :commits) do
|
||||
= link_to 'Commits', commits_namespace_project_graph_path
|
||||
= nav_link(action: :languages) do
|
||||
= link_to 'Languages', languages_namespace_project_graph_path
|
||||
- if @project.builds_enabled?
|
||||
= nav_link(action: :ci) do
|
||||
= link_to ci_namespace_project_graph_path do
|
||||
Continuous Integration
|
||||
|
|
|
@ -1,15 +1,18 @@
|
|||
- @no_container = true
|
||||
- page_title "Continuous Integration", "Graphs"
|
||||
= render 'head'
|
||||
.row-content-block.append-bottom-default
|
||||
.oneline
|
||||
A collection of graphs for Continuous Integration
|
||||
|
||||
#charts.ci-charts
|
||||
.row
|
||||
.col-md-6
|
||||
= render 'projects/graphs/ci/overall'
|
||||
.col-md-6
|
||||
= render 'projects/graphs/ci/build_times'
|
||||
%div{ class: (container_class) }
|
||||
.sub-header-block
|
||||
.oneline
|
||||
A collection of graphs for Continuous Integration
|
||||
|
||||
%hr
|
||||
= render 'projects/graphs/ci/builds'
|
||||
#charts.ci-charts
|
||||
.row
|
||||
.col-md-6
|
||||
= render 'projects/graphs/ci/overall'
|
||||
.col-md-6
|
||||
= render 'projects/graphs/ci/build_times'
|
||||
|
||||
%hr
|
||||
= render 'projects/graphs/ci/builds'
|
||||
|
|
|
@ -1,52 +1,54 @@
|
|||
- @no_container = true
|
||||
- page_title "Commits", "Graphs"
|
||||
= render 'head'
|
||||
|
||||
.row-content-block.append-bottom-default
|
||||
.tree-ref-holder
|
||||
= render 'shared/ref_switcher', destination: 'graphs_commits'
|
||||
%ul.breadcrumb.repo-breadcrumb
|
||||
= commits_breadcrumbs
|
||||
%div{ class: (container_class) }
|
||||
.sub-header-block
|
||||
.tree-ref-holder
|
||||
= render 'shared/ref_switcher', destination: 'graphs_commits'
|
||||
%ul.breadcrumb.repo-breadcrumb
|
||||
= commits_breadcrumbs
|
||||
|
||||
%p.lead
|
||||
Commit statistics for
|
||||
%strong #{@ref}
|
||||
#{@commits_graph.start_date.strftime('%b %d')} - #{@commits_graph.end_date.strftime('%b %d')}
|
||||
%p.lead
|
||||
Commit statistics for
|
||||
%strong #{@ref}
|
||||
#{@commits_graph.start_date.strftime('%b %d')} - #{@commits_graph.end_date.strftime('%b %d')}
|
||||
|
||||
.row
|
||||
.col-md-6
|
||||
%ul
|
||||
%li
|
||||
%p.lead
|
||||
%strong #{@commits_graph.commits.size}
|
||||
commits during
|
||||
%strong #{@commits_graph.duration}
|
||||
days
|
||||
%li
|
||||
%p.lead
|
||||
Average
|
||||
%strong #{@commits_graph.commit_per_day}
|
||||
commits per day
|
||||
%li
|
||||
%p.lead
|
||||
Contributed by
|
||||
%strong #{@commits_graph.authors}
|
||||
authors
|
||||
.col-md-6
|
||||
%div
|
||||
%p.slead
|
||||
Commits per day of month
|
||||
%canvas#month-chart
|
||||
.row
|
||||
.col-md-6
|
||||
%div
|
||||
%p.slead
|
||||
Commits per day hour (UTC)
|
||||
%canvas#hour-chart
|
||||
.col-md-6
|
||||
%div
|
||||
%p.slead
|
||||
Commits per weekday
|
||||
%canvas#weekday-chart
|
||||
.row
|
||||
.col-md-6
|
||||
%ul
|
||||
%li
|
||||
%p.lead
|
||||
%strong #{@commits_graph.commits.size}
|
||||
commits during
|
||||
%strong #{@commits_graph.duration}
|
||||
days
|
||||
%li
|
||||
%p.lead
|
||||
Average
|
||||
%strong #{@commits_graph.commit_per_day}
|
||||
commits per day
|
||||
%li
|
||||
%p.lead
|
||||
Contributed by
|
||||
%strong #{@commits_graph.authors}
|
||||
authors
|
||||
.col-md-6
|
||||
%div
|
||||
%p.slead
|
||||
Commits per day of month
|
||||
%canvas#month-chart
|
||||
.row
|
||||
.col-md-6
|
||||
%div
|
||||
%p.slead
|
||||
Commits per day hour (UTC)
|
||||
%canvas#hour-chart
|
||||
.col-md-6
|
||||
%div
|
||||
%p.slead
|
||||
Commits per weekday
|
||||
%canvas#weekday-chart
|
||||
|
||||
:javascript
|
||||
var responsiveChart = function (selector, data) {
|
||||
|
|
|
@ -1,24 +1,26 @@
|
|||
- @no_container = true
|
||||
- page_title "Languages", "Graphs"
|
||||
= render 'head'
|
||||
|
||||
.row-content-block.append-bottom-default
|
||||
.oneline
|
||||
Programming languages used in this repository
|
||||
%div{ class: (container_class) }
|
||||
.sub-header-block
|
||||
.oneline
|
||||
Programming languages used in this repository
|
||||
|
||||
.row
|
||||
.col-md-8
|
||||
%canvas#languages-chart{ height: 400 }
|
||||
.col-md-4
|
||||
%ul.bordered-list
|
||||
- @languages.each do |language|
|
||||
%li
|
||||
%span{ style: "color: #{language[:color]}" }
|
||||
= icon('circle')
|
||||
|
||||
= language[:label]
|
||||
.pull-right
|
||||
= language[:value]
|
||||
\%
|
||||
.row
|
||||
.col-md-8
|
||||
%canvas#languages-chart{ height: 400 }
|
||||
.col-md-4
|
||||
%ul.bordered-list
|
||||
- @languages.each do |language|
|
||||
%li
|
||||
%span{ style: "color: #{language[:color]}" }
|
||||
= icon('circle')
|
||||
|
||||
= language[:label]
|
||||
.pull-right
|
||||
= language[:value]
|
||||
\%
|
||||
|
||||
:javascript
|
||||
var data = #{@languages.to_json};
|
||||
|
|
|
@ -1,29 +1,31 @@
|
|||
- @no_container = true
|
||||
- page_title "Contributors", "Graphs"
|
||||
= render 'head'
|
||||
|
||||
.row-content-block.append-bottom-default
|
||||
.tree-ref-holder
|
||||
= render 'shared/ref_switcher', destination: 'graphs'
|
||||
%ul.breadcrumb.repo-breadcrumb
|
||||
= commits_breadcrumbs
|
||||
%div{ class: (container_class) }
|
||||
.sub-header-block
|
||||
.tree-ref-holder
|
||||
= render 'shared/ref_switcher', destination: 'graphs'
|
||||
%ul.breadcrumb.repo-breadcrumb
|
||||
= commits_breadcrumbs
|
||||
|
||||
.loading-graph
|
||||
.center
|
||||
%h3.page-title
|
||||
%i.fa.fa-spinner.fa-spin
|
||||
Building repository graph.
|
||||
%p.slead Please wait a moment, this page will automatically refresh when ready.
|
||||
.loading-graph
|
||||
.center
|
||||
%h3.page-title
|
||||
%i.fa.fa-spinner.fa-spin
|
||||
Building repository graph.
|
||||
%p.slead Please wait a moment, this page will automatically refresh when ready.
|
||||
|
||||
.stat-graph.hide
|
||||
.header.clearfix
|
||||
%h3#date_header.page-title
|
||||
%p.light
|
||||
Commits to #{@ref}, excluding merge commits. Limited to 6,000 commits.
|
||||
%input#brush_change{:type => "hidden"}
|
||||
.graphs
|
||||
#contributors-master
|
||||
#contributors.clearfix
|
||||
%ol.contributors-list.clearfix
|
||||
.stat-graph.hide
|
||||
.header.clearfix
|
||||
%h3#date_header.page-title
|
||||
%p.light
|
||||
Commits to #{@ref}, excluding merge commits. Limited to 6,000 commits.
|
||||
%input#brush_change{:type => "hidden"}
|
||||
.graphs.row
|
||||
#contributors-master
|
||||
#contributors.clearfix
|
||||
%ol.contributors-list.clearfix
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -15,5 +15,5 @@
|
|||
= check_box_tag :filter_ref, 1, @options[:filter_ref]
|
||||
%span Begin with the selected commit
|
||||
|
||||
.network-graph{ data: { url: '#{escape_javascript(@url)}', commit_url: '#{escape_javascript(@commit_url)}', ref: '#{escape_javascript(@ref)}', commit_id: '#{escape_javascript(@commit.id)}' } }
|
||||
.network-graph{ data: { url: @url, commit_url: @commit_url, ref: @ref, commit_id: @commit.id } }
|
||||
= spinner nil, true
|
||||
|
|
|
@ -2,8 +2,7 @@
|
|||
.panel-heading
|
||||
%strong #{@group.name}
|
||||
group members
|
||||
%small
|
||||
(#{members.count})
|
||||
%span.badge= members.size
|
||||
- if can?(current_user, :admin_group_member, @group)
|
||||
.controls
|
||||
= link_to 'Manage group members',
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
- @project_group_links.each do |group_links|
|
||||
- shared_group = group_links.group
|
||||
- shared_group_users_count = group_links.group.group_members.count
|
||||
- shared_group_members = shared_group.members.non_request
|
||||
- shared_group_users_count = shared_group_members.size
|
||||
.panel.panel-default
|
||||
.panel-heading
|
||||
Shared with
|
||||
|
@ -15,7 +16,7 @@
|
|||
Edit group members
|
||||
%ul.content-list
|
||||
= render partial: 'shared/members/member',
|
||||
collection: shared_group.group_members.order(access_level: :desc).limit(20),
|
||||
collection: shared_group_members.order(access_level: :desc).limit(20),
|
||||
as: :member,
|
||||
locals: { show_controls: false, show_roles: false }
|
||||
- if shared_group_users_count > 20
|
||||
|
|
|
@ -2,8 +2,7 @@
|
|||
.panel-heading
|
||||
%strong #{@project.name}
|
||||
project members
|
||||
%small
|
||||
(#{members.count})
|
||||
%span.badge= members.size
|
||||
.controls
|
||||
= form_tag namespace_project_project_members_path(@project.namespace, @project), method: :get, class: 'form-inline member-search-form' do
|
||||
.form-group
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
= render 'team', members: @project_members.non_request
|
||||
|
||||
- if @group
|
||||
= render "group_members", members: @group_members
|
||||
= render "group_members", members: @group_members.non_request
|
||||
|
||||
- if @project_group_links.any? && @project.allowed_to_share_with_group?
|
||||
= render "shared_group_members"
|
||||
|
|
|
@ -60,7 +60,7 @@
|
|||
- unless @repository.gitlab_ci_yml
|
||||
%li.missing
|
||||
= link_to add_special_file_path(@project, file_name: '.gitlab-ci.yml') do
|
||||
Set up CI
|
||||
Set Up CI
|
||||
|
||||
- if @repository.commit
|
||||
.content-block.second-block.white
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
- if (@page && @page.persisted?)
|
||||
- if can?(current_user, :create_wiki, @project)
|
||||
= link_to '#modal-new-wiki', class: "add-new-wiki btn btn-new", "data-toggle" => "modal" do
|
||||
New Page
|
||||
= link_to namespace_project_wiki_history_path(@project.namespace, @project, @page), class: "btn" do
|
||||
Page History
|
||||
- if can?(current_user, :create_wiki, @project)
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
.top-area
|
||||
%ul.nav-links
|
||||
.nav-links.sub-nav
|
||||
%ul{ class: (container_class) }
|
||||
= nav_link(html_options: {class: params[:id] == 'home' ? 'active' : '' }) do
|
||||
= link_to 'Home', namespace_project_wiki_path(@project.namespace, @project, :home)
|
||||
|
||||
|
@ -10,9 +10,4 @@
|
|||
= link_to namespace_project_wikis_git_access_path(@project.namespace, @project) do
|
||||
Git Access
|
||||
|
||||
.nav-controls
|
||||
- if can?(current_user, :create_wiki, @project)
|
||||
= link_to '#modal-new-wiki', class: "add-new-wiki btn btn-new", "data-toggle" => "modal" do
|
||||
New Page
|
||||
|
||||
= render 'projects/wikis/new'
|
||||
= render 'projects/wikis/new'
|
||||
|
|
|
@ -1,14 +1,17 @@
|
|||
%div#modal-new-wiki.modal
|
||||
.modal-dialog
|
||||
.modal-content
|
||||
.modal-header
|
||||
%a.close{href: "#", "data-dismiss" => "modal"} ×
|
||||
%h3.page-title New Wiki Page
|
||||
.modal-body
|
||||
%form.new-wiki-page
|
||||
.form-group
|
||||
= label_tag :new_wiki_path do
|
||||
%span Page slug
|
||||
= text_field_tag :new_wiki_path, nil, placeholder: 'how-to-setup', class: 'form-control', required: true, :'data-wikis-path' => namespace_project_wikis_path(@project.namespace, @project), autofocus: true
|
||||
.form-actions
|
||||
= button_tag 'Create Page', class: 'build-new-wiki btn btn-create'
|
||||
- @no_container = true
|
||||
|
||||
%div{ class: (container_class) }
|
||||
%div#modal-new-wiki.modal
|
||||
.modal-dialog
|
||||
.modal-content
|
||||
.modal-header
|
||||
%a.close{href: "#", "data-dismiss" => "modal"} ×
|
||||
%h3.page-title New Wiki Page
|
||||
.modal-body
|
||||
%form.new-wiki-page
|
||||
.form-group
|
||||
= label_tag :new_wiki_path do
|
||||
%span Page slug
|
||||
= text_field_tag :new_wiki_path, nil, placeholder: 'how-to-setup', class: 'form-control', required: true, :'data-wikis-path' => namespace_project_wikis_path(@project.namespace, @project), autofocus: true
|
||||
.form-actions
|
||||
= button_tag 'Create Page', class: 'build-new-wiki btn btn-create'
|
||||
|
|
|
@ -1,19 +1,24 @@
|
|||
- @no_container = true
|
||||
- page_title "Edit", @page.title.capitalize, "Wiki"
|
||||
= render 'nav'
|
||||
|
||||
.top-area
|
||||
.nav-text.wiki-page
|
||||
%strong
|
||||
- if @page.persisted?
|
||||
= link_to @page.title.capitalize, namespace_project_wiki_path(@project.namespace, @project, @page)
|
||||
- else
|
||||
= @page.title.capitalize
|
||||
%span.light
|
||||
·
|
||||
Edit Page
|
||||
%div{ class: (container_class) }
|
||||
.top-area
|
||||
.nav-text
|
||||
%strong
|
||||
- if @page.persisted?
|
||||
= link_to @page.title.capitalize, namespace_project_wiki_path(@project.namespace, @project, @page)
|
||||
- else
|
||||
= @page.title.capitalize
|
||||
%span.light
|
||||
·
|
||||
Edit Page
|
||||
|
||||
.nav-controls
|
||||
= render 'main_links'
|
||||
.nav-controls
|
||||
- if can?(current_user, :create_wiki, @project)
|
||||
= link_to '#modal-new-wiki', class: "add-new-wiki btn btn-new", "data-toggle" => "modal" do
|
||||
New Page
|
||||
= render 'main_links'
|
||||
|
||||
|
||||
= render 'form'
|
||||
= render 'form'
|
||||
|
|
|
@ -1,32 +1,34 @@
|
|||
- @no_container = true
|
||||
- page_title "Git Access", "Wiki"
|
||||
|
||||
= render 'nav'
|
||||
.row-content-block
|
||||
%span.oneline
|
||||
Git access for
|
||||
%strong= @project_wiki.path_with_namespace
|
||||
%div{ class: (container_class) }
|
||||
.sub-header-block
|
||||
%span.oneline
|
||||
Git access for
|
||||
%strong= @project_wiki.path_with_namespace
|
||||
|
||||
.pull-right
|
||||
= render "shared/clone_panel", project: @project_wiki
|
||||
.pull-right
|
||||
= render "shared/clone_panel", project: @project_wiki
|
||||
|
||||
.git-empty.prepend-top-default
|
||||
%fieldset
|
||||
%legend Install Gollum:
|
||||
%pre.dark
|
||||
:preserve
|
||||
gem install gollum
|
||||
.prepend-top-default
|
||||
%fieldset
|
||||
%legend Install Gollum:
|
||||
%pre.dark
|
||||
:preserve
|
||||
gem install gollum
|
||||
|
||||
%legend Clone Your Wiki:
|
||||
%pre.dark
|
||||
:preserve
|
||||
git clone #{ content_tag(:span, default_url_to_repo(@project_wiki), class: 'clone')}
|
||||
cd #{h @project_wiki.path}
|
||||
%legend Clone Your Wiki:
|
||||
%pre.dark
|
||||
:preserve
|
||||
git clone #{ content_tag(:span, default_url_to_repo(@project_wiki), class: 'clone')}
|
||||
cd #{h @project_wiki.path}
|
||||
|
||||
%legend Start Gollum And Edit Locally:
|
||||
%pre.dark
|
||||
:preserve
|
||||
gollum
|
||||
== Sinatra/1.3.5 has taken the stage on 4567 for development with backup from Thin
|
||||
>> Thin web server (v1.5.0 codename Knife)
|
||||
>> Maximum connections set to 1024
|
||||
>> Listening on 0.0.0.0:4567, CTRL+C to stop
|
||||
%legend Start Gollum And Edit Locally:
|
||||
%pre.dark
|
||||
:preserve
|
||||
gollum
|
||||
== Sinatra/1.3.5 has taken the stage on 4567 for development with backup from Thin
|
||||
>> Thin web server (v1.5.0 codename Knife)
|
||||
>> Maximum connections set to 1024
|
||||
>> Listening on 0.0.0.0:4567, CTRL+C to stop
|
||||
|
|
|
@ -1,37 +1,37 @@
|
|||
- page_title "History", @page.title.capitalize, "Wiki"
|
||||
= render 'nav'
|
||||
%div{ class: (container_class) }
|
||||
.top-area
|
||||
.nav-text
|
||||
%strong
|
||||
= link_to @page.title.capitalize, namespace_project_wiki_path(@project.namespace, @project, @page)
|
||||
%span.light
|
||||
·
|
||||
History
|
||||
|
||||
.top-area
|
||||
.nav-text
|
||||
%strong
|
||||
= link_to @page.title.capitalize, namespace_project_wiki_path(@project.namespace, @project, @page)
|
||||
%span.light
|
||||
·
|
||||
History
|
||||
|
||||
.table-holder
|
||||
%table.table
|
||||
%thead
|
||||
%tr
|
||||
%th Page version
|
||||
%th Author
|
||||
%th Commit Message
|
||||
%th Last updated
|
||||
%th Format
|
||||
%tbody
|
||||
- @page.versions.each_with_index do |version, index|
|
||||
- commit = version
|
||||
.table-holder
|
||||
%table.table
|
||||
%thead
|
||||
%tr
|
||||
%td
|
||||
= link_to project_wiki_path_with_version(@project, @page,
|
||||
commit.id, index == 0) do
|
||||
= truncate_sha(commit.id)
|
||||
%td
|
||||
= commit.author.name
|
||||
%td
|
||||
= commit.message
|
||||
%td
|
||||
#{time_ago_with_tooltip(version.authored_date)}
|
||||
%td
|
||||
%strong
|
||||
= @page.page.wiki.page(@page.page.name, commit.id).try(:format)
|
||||
%th Page version
|
||||
%th Author
|
||||
%th Commit Message
|
||||
%th Last updated
|
||||
%th Format
|
||||
%tbody
|
||||
- @page.versions.each_with_index do |version, index|
|
||||
- commit = version
|
||||
%tr
|
||||
%td
|
||||
= link_to project_wiki_path_with_version(@project, @page,
|
||||
commit.id, index == 0) do
|
||||
= truncate_sha(commit.id)
|
||||
%td
|
||||
= commit.author.name
|
||||
%td
|
||||
= commit.message
|
||||
%td
|
||||
#{time_ago_with_tooltip(version.authored_date)}
|
||||
%td
|
||||
%strong
|
||||
= @page.page.wiki.page(@page.page.name, commit.id).try(:format)
|
||||
|
|
|
@ -1,12 +1,14 @@
|
|||
- @no_container = true
|
||||
- page_title "Pages", "Wiki"
|
||||
|
||||
= render 'nav'
|
||||
|
||||
%ul.content-list
|
||||
- @wiki_pages.each do |wiki_page|
|
||||
%li
|
||||
= link_to wiki_page.title, namespace_project_wiki_path(@project.namespace, @project, wiki_page)
|
||||
%small (#{wiki_page.format})
|
||||
.pull-right
|
||||
%small Last edited #{time_ago_with_tooltip(wiki_page.commit.authored_date)}
|
||||
= paginate @wiki_pages, theme: 'gitlab'
|
||||
%div{ class: (container_class) }
|
||||
%ul.content-list
|
||||
- @wiki_pages.each do |wiki_page|
|
||||
%li
|
||||
= link_to wiki_page.title, namespace_project_wiki_path(@project.namespace, @project, wiki_page)
|
||||
%small (#{wiki_page.format})
|
||||
.pull-right
|
||||
%small Last edited #{time_ago_with_tooltip(wiki_page.commit.authored_date)}
|
||||
= paginate @wiki_pages, theme: 'gitlab'
|
||||
|
|
|
@ -1,24 +1,26 @@
|
|||
- @no_container = true
|
||||
- page_title @page.title.capitalize, "Wiki"
|
||||
= render 'nav'
|
||||
|
||||
.top-area
|
||||
.nav-text
|
||||
%strong= @page.title.capitalize
|
||||
%div{ class: (container_class) }
|
||||
.top-area
|
||||
.nav-text
|
||||
%strong= @page.title.capitalize
|
||||
|
||||
%span.wiki-last-edit-by
|
||||
·
|
||||
last edited by #{@page.commit.author.name} #{time_ago_with_tooltip(@page.commit.authored_date)}
|
||||
%span.wiki-last-edit-by
|
||||
·
|
||||
last edited by #{@page.commit.author.name} #{time_ago_with_tooltip(@page.commit.authored_date)}
|
||||
|
||||
.nav-controls
|
||||
= render 'main_links'
|
||||
.nav-controls
|
||||
= render 'main_links'
|
||||
|
||||
- if @page.historical?
|
||||
.warning_message
|
||||
This is an old version of this page.
|
||||
You can view the #{link_to "most recent version", namespace_project_wiki_path(@project.namespace, @project, @page)} or browse the #{link_to "history", namespace_project_wiki_history_path(@project.namespace, @project, @page)}.
|
||||
- if @page.historical?
|
||||
.warning_message
|
||||
This is an old version of this page.
|
||||
You can view the #{link_to "most recent version", namespace_project_wiki_path(@project.namespace, @project, @page)} or browse the #{link_to "history", namespace_project_wiki_history_path(@project.namespace, @project, @page)}.
|
||||
|
||||
|
||||
.wiki-holder.prepend-top-default.append-bottom-default
|
||||
.wiki
|
||||
= preserve do
|
||||
= render_wiki_content(@page)
|
||||
.wiki-holder.prepend-top-default.append-bottom-default
|
||||
.wiki
|
||||
= preserve do
|
||||
= render_wiki_content(@page)
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
%ul.nav-links.event-filter.scrolling-tabs
|
||||
.fade-left
|
||||
%li.fade-left
|
||||
= icon('arrow-left')
|
||||
= event_filter_link EventFilter.push, 'Push events'
|
||||
= event_filter_link EventFilter.merged, 'Merge events'
|
||||
= event_filter_link EventFilter.comments, 'Comments'
|
||||
= event_filter_link EventFilter.team, 'Team'
|
||||
.fade-right
|
||||
%li.fade-right
|
||||
= icon('arrow-right')
|
||||
|
|
|
@ -3,6 +3,6 @@
|
|||
.panel-heading
|
||||
%strong= membership_source.name
|
||||
access requests
|
||||
%small= "(#{members.size})"
|
||||
%span.badge= members.size
|
||||
%ul.content-list
|
||||
= render partial: 'shared/members/member', collection: members, as: :member
|
||||
|
|
|
@ -16,6 +16,12 @@
|
|||
= render "shared/projects/project", project: project, skip_namespace: skip_namespace,
|
||||
avatar: avatar, stars: stars, css_class: css_class, ci: ci, use_creator_avatar: use_creator_avatar,
|
||||
forks: forks, show_last_commit_as_description: show_last_commit_as_description
|
||||
|
||||
- if @private_forks_count && @private_forks_count > 0
|
||||
%li.project-row.private-forks-notice
|
||||
= icon('lock fw', base: 'circle', class: 'fa-lg private-fork-icon')
|
||||
%strong= pluralize(@private_forks_count, 'private fork')
|
||||
%span you have no access to.
|
||||
= paginate(projects, remote: remote, theme: "gitlab") if projects.respond_to? :total_pages
|
||||
- else
|
||||
.nothing-here-block No projects found
|
||||
|
|
|
@ -215,7 +215,7 @@ Settings.gitlab.default_projects_features['container_registry'] = true if Settin
|
|||
Settings.gitlab.default_projects_features['visibility_level'] = Settings.send(:verify_constant, Gitlab::VisibilityLevel, Settings.gitlab.default_projects_features['visibility_level'], Gitlab::VisibilityLevel::PRIVATE)
|
||||
Settings.gitlab['repository_downloads_path'] = File.join(Settings.shared['path'], 'cache/archive') if Settings.gitlab['repository_downloads_path'].nil?
|
||||
Settings.gitlab['restricted_signup_domains'] ||= []
|
||||
Settings.gitlab['import_sources'] ||= ['github','bitbucket','gitlab','gitorious','google_code','fogbugz','git']
|
||||
Settings.gitlab['import_sources'] ||= %w[github bitbucket gitlab gitorious google_code fogbugz git gitlab_project]
|
||||
Settings.gitlab['trusted_proxies'] ||= []
|
||||
|
||||
|
||||
|
|
|
@ -3,18 +3,18 @@
|
|||
## User documentation
|
||||
|
||||
- [API](api/README.md) Automate GitLab via a simple and powerful API.
|
||||
- [CI](ci/README.md) GitLab Continuous Integration (CI) getting started, `.gitlab-ci.yml` options, and examples.
|
||||
- [CI/CD](ci/README.md) GitLab Continuous Integration (CI) and Continuous Delivery (CD) getting started, `.gitlab-ci.yml` options, and examples.
|
||||
- [GitLab as OAuth2 authentication service provider](integration/oauth_provider.md). It allows you to login to other applications from GitLab.
|
||||
- [Container Registry](container_registry/README.md) Learn how to use GitLab Container Registry.
|
||||
- [GitLab Basics](gitlab-basics/README.md) Find step by step how to start working on your commandline and on GitLab.
|
||||
- [Importing to GitLab](workflow/importing/README.md).
|
||||
- [Importing and exporting projects between instances](user/project/settings/import_export.md).
|
||||
- [Markdown](markdown/markdown.md) GitLab's advanced formatting system.
|
||||
- [Migrating from SVN](workflow/importing/migrating_from_svn.md) Convert a SVN repository to Git and GitLab
|
||||
- [Migrating from SVN](workflow/importing/migrating_from_svn.md) Convert a SVN repository to Git and GitLab.
|
||||
- [Permissions](permissions/permissions.md) Learn what each role in a project (external/guest/reporter/developer/master/owner) can do.
|
||||
- [Profile Settings](profile/README.md)
|
||||
- [Project Services](project_services/project_services.md) Integrate a project with external services, such as CI and chat.
|
||||
- [Public access](public_access/public_access.md) Learn how you can allow public and internal access to projects.
|
||||
- [Container Registry](container_registry/README.md) Learn how to use GitLab Container Registry.
|
||||
- [SSH](ssh/README.md) Setup your ssh keys and deploy keys for secure access to your projects.
|
||||
- [Webhooks](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.
|
||||
|
@ -25,15 +25,15 @@
|
|||
external authentication with LDAP, SAML, CAS and additional Omniauth providers.
|
||||
- [Custom git hooks](hooks/custom_hooks.md) Custom git hooks (on the filesystem) for when webhooks aren't enough.
|
||||
- [Install](install/README.md) Requirements, directory structures and installation from source.
|
||||
- [Restart GitLab](administration/restart_gitlab.md) Learn how to restart GitLab and its components
|
||||
- [Restart GitLab](administration/restart_gitlab.md) Learn how to restart GitLab and its components.
|
||||
- [Integration](integration/README.md) How to integrate with systems such as JIRA, Redmine, Twitter.
|
||||
- [Issue closing](customization/issue_closing.md) Customize how to close an issue from commit messages.
|
||||
- [Libravatar](customization/libravatar.md) Use Libravatar for user avatars.
|
||||
- [Log system](administration/logs.md) Log system.
|
||||
- [Environment Variables](administration/environment_variables.md) to configure GitLab.
|
||||
- [Operations](operations/README.md) Keeping GitLab up and running
|
||||
- [Operations](operations/README.md) Keeping GitLab up and running.
|
||||
- [Raketasks](raketasks/README.md) Backups, maintenance, automatic webhook setup and the importing of projects.
|
||||
- [Repository checks](administration/repository_checks.md) Periodic Git repository checks
|
||||
- [Repository checks](administration/repository_checks.md) Periodic Git repository checks.
|
||||
- [Security](security/README.md) Learn what you can do to further secure your GitLab instance.
|
||||
- [System hooks](system_hooks/system_hooks.md) Notifications when users, projects and keys are changed.
|
||||
- [Update](update/README.md) Update guides to upgrade your installation.
|
||||
|
@ -42,11 +42,11 @@
|
|||
- [Migrate GitLab CI to CE/EE](migrate_ci_to_ce/README.md) Follow this guide to migrate your existing GitLab CI data to GitLab CE/EE.
|
||||
- [Git LFS configuration](workflow/lfs/lfs_administration.md)
|
||||
- [Housekeeping](administration/housekeeping.md) Keep your Git repository tidy and fast.
|
||||
- [GitLab Performance Monitoring](monitoring/performance/introduction.md) Configure GitLab and InfluxDB for measuring performance metrics
|
||||
- [Monitoring uptime](monitoring/health_check.md) Check the server status using the health check endpoint
|
||||
- [Sidekiq Troubleshooting](administration/troubleshooting/sidekiq.md) Debug when Sidekiq appears hung and is not processing jobs
|
||||
- [High Availability](administration/high_availability/README.md) Configure multiple servers for scaling or high availability
|
||||
- [Container Registry](administration/container_registry.md) Configure Docker Registry with GitLab
|
||||
- [GitLab Performance Monitoring](monitoring/performance/introduction.md) Configure GitLab and InfluxDB for measuring performance metrics.
|
||||
- [Monitoring uptime](monitoring/health_check.md) Check the server status using the health check endpoint.
|
||||
- [Sidekiq Troubleshooting](administration/troubleshooting/sidekiq.md) Debug when Sidekiq appears hung and is not processing jobs.
|
||||
- [High Availability](administration/high_availability/README.md) Configure multiple servers for scaling or high availability.
|
||||
- [Container Registry](administration/container_registry.md) Configure Docker Registry with GitLab.
|
||||
|
||||
## Contributor documentation
|
||||
|
||||
|
|
|
@ -22,6 +22,7 @@ You can read more about Docker Registry at https://docs.docker.com/registry/intr
|
|||
- [Disable Container Registry per project](#disable-container-registry-per-project)
|
||||
- [Disable Container Registry for new projects site-wide](#disable-container-registry-for-new-projects-site-wide)
|
||||
- [Container Registry storage path](#container-registry-storage-path)
|
||||
- [Container Registry storage driver](#container-registry-storage-driver)
|
||||
- [Storage limitations](#storage-limitations)
|
||||
- [Changelog](#changelog)
|
||||
|
||||
|
@ -306,8 +307,12 @@ the Container Registry by themselves, follow the steps below.
|
|||
|
||||
## Container Registry storage path
|
||||
|
||||
To change the storage path where Docker images will be stored, follow the
|
||||
steps below.
|
||||
>**Note:**
|
||||
For configuring storage in the cloud instead of the filesystem, see the
|
||||
[storage driver configuration](#container-registry-storage-driver).
|
||||
|
||||
If you want to store your images on the filesystem, you can change the storage
|
||||
path for the Container Registry, follow the steps below.
|
||||
|
||||
This path is accessible to:
|
||||
|
||||
|
@ -349,6 +354,72 @@ The default location where images are stored in source installations, is
|
|||
|
||||
1. Save the file and [restart GitLab][] for the changes to take effect.
|
||||
|
||||
## Container Registry storage driver
|
||||
|
||||
You can configure the Container Registry to use a different storage backend by
|
||||
configuring a different storage driver. By default the GitLab Container Registry
|
||||
is configured to use the filesystem driver, which makes use of [storage path](#container-registry-storage-path)
|
||||
configuration.
|
||||
|
||||
The different supported drivers are:
|
||||
|
||||
| Driver | Description |
|
||||
|------------|-------------------------------------|
|
||||
| filesystem | Uses a path on the local filesystem |
|
||||
| azure | Microsoft Azure Blob Storage |
|
||||
| gcs | Google Cloud Storage |
|
||||
| s3 | Amazon Simple Storage Service |
|
||||
| swift | OpenStack Swift Object Storage |
|
||||
| oss | Aliyun OSS |
|
||||
|
||||
Read more about the individual driver's config options in the
|
||||
[Docker Registry docs][storage-config].
|
||||
|
||||
> **Warning** GitLab will not backup Docker images that are not stored on the
|
||||
filesystem. Remember to enable backups with your object storage provider if
|
||||
desired.
|
||||
|
||||
---
|
||||
|
||||
**Omnibus GitLab installations**
|
||||
|
||||
To configure the storage driver in Omnibus:
|
||||
|
||||
1. Edit `/etc/gitlab/gitlab.rb`:
|
||||
|
||||
```ruby
|
||||
registry['storage'] = {
|
||||
's3' => {
|
||||
'accesskey' => 's3-access-key',
|
||||
'secretkey' => 's3-secret-key-for-access-key',
|
||||
'bucket' => 'your-s3-bucket'
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
1. Save the file and [reconfigure GitLab][] for the changes to take effect.
|
||||
|
||||
---
|
||||
|
||||
**Installations from source**
|
||||
|
||||
Configuring the storage driver is done in your registry config YML file created
|
||||
when you [deployed your docker registry][registry-deploy].
|
||||
|
||||
Example:
|
||||
|
||||
```
|
||||
storage:
|
||||
s3:
|
||||
accesskey: 'AKIAKIAKI'
|
||||
secretkey: 'secret123'
|
||||
bucket: 'gitlab-registry-bucket-AKIAKIAKI'
|
||||
cache:
|
||||
blobdescriptor: inmemory
|
||||
delete:
|
||||
enabled: true
|
||||
```
|
||||
|
||||
## Storage limitations
|
||||
|
||||
Currently, there is no storage limitation, which means a user can upload an
|
||||
|
|
|
@ -32,6 +32,7 @@ following locations:
|
|||
- [Services](services.md)
|
||||
- [Session](session.md)
|
||||
- [Settings](settings.md)
|
||||
- [Sidekiq metrics](sidekiq_metrics.md)
|
||||
- [System Hooks](system_hooks.md)
|
||||
- [Tags](tags.md)
|
||||
- [Users](users.md)
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
- [Get started with GitLab CI](quick_start/README.md)
|
||||
- [CI examples for various languages](examples/README.md)
|
||||
- [Learn how to enable or disable GitLab CI](enable_or_disable_ci.md)
|
||||
- [Pipelines and builds](pipelines.md)
|
||||
- [Environments and deployments](environments.md)
|
||||
- [Learn how `.gitlab-ci.yml` works](yaml/README.md)
|
||||
- [Configure a Runner, the application that runs your builds](runners/README.md)
|
||||
|
|
|
@ -52,7 +52,7 @@ Clicking on an environment will show the history of deployments.
|
|||
Only deploys that happen after your `.gitlab-ci.yml` is properly configured will
|
||||
show up in the environments and deployments lists.
|
||||
|
||||
[Pipelines]: quick_start/README.md
|
||||
[Pipelines]: pipelines.md
|
||||
[jobs]: yaml/README.md#jobs
|
||||
[environments]: #environments
|
||||
[deployments]: #deployments
|
||||
|
|
|
@ -0,0 +1,38 @@
|
|||
# Introduction to pipelines and builds
|
||||
|
||||
>**Note:**
|
||||
Introduced in GitLab 8.8.
|
||||
|
||||
## Pipelines
|
||||
|
||||
A pipeline is a group of [builds] that get executed in [stages] (batches). All
|
||||
of the builds in a stage are executed in parallel (if there are enough
|
||||
concurrent [runners]), and if they all succeed, the pipeline moves on to the
|
||||
next stage. If one of the builds fails, the next stage is not (usually)
|
||||
executed.
|
||||
|
||||
## Builds
|
||||
|
||||
Builds are individual runs of [jobs]. Not to be confused with a `build` job or
|
||||
`build` stage.
|
||||
|
||||
## Defining pipelines
|
||||
|
||||
Pipelines are defined in `.gitlab-ci.yml` by specifying [jobs] that run in
|
||||
[stages].
|
||||
|
||||
See full [documentation](yaml/README.md#jobs).
|
||||
|
||||
## Seeing pipeline status
|
||||
|
||||
You can find the current and historical pipeline runs under **Pipelines** for your
|
||||
project.
|
||||
|
||||
## Seeing build status
|
||||
|
||||
Clicking on a pipeline will show the builds that were run for that pipeline.
|
||||
|
||||
[builds]: #builds
|
||||
[jobs]: yaml/README.md#jobs
|
||||
[stages]: yaml/README.md#stages
|
||||
[runners]: runners/README.md
|
|
@ -4,41 +4,41 @@
|
|||
is fully integrated into GitLab itself and is [enabled] by default on all
|
||||
projects.
|
||||
|
||||
The TL;DR version of how GitLab CI works is the following.
|
||||
|
||||
---
|
||||
|
||||
GitLab offers a [continuous integration][ci] service. If you
|
||||
[add a `.gitlab-ci.yml` file][yaml] to the root directory of your repository,
|
||||
and configure your GitLab project to use a [Runner], then each merge request or
|
||||
push triggers a build.
|
||||
push triggers your CI [pipeline].
|
||||
|
||||
The `.gitlab-ci.yml` file tells the GitLab runner what to do. By default it
|
||||
runs three [stages]: `build`, `test`, and `deploy`.
|
||||
The `.gitlab-ci.yml` file tells the GitLab runner what to do. By default it runs
|
||||
a pipeline with three [stages]: `build`, `test`, and `deploy`. You don't need to
|
||||
use all three stages; stages with no jobs are simply ignored.
|
||||
|
||||
If everything runs OK (no non-zero return values), you'll get a nice green
|
||||
checkmark associated with the pushed commit or merge request. This makes it
|
||||
easy to see whether a merge request will cause any of the tests to fail before
|
||||
easy to see whether a merge request caused any of the tests to fail before
|
||||
you even look at the code.
|
||||
|
||||
Most projects only use GitLab's CI service to run the test suite so that
|
||||
Most projects use GitLab's CI service to run the test suite so that
|
||||
developers get immediate feedback if they broke something.
|
||||
|
||||
There's a growing trend to use continuous delivery and continuous deployment to
|
||||
automatically deploy tested code to staging and production environments.
|
||||
|
||||
So in brief, the steps needed to have a working CI can be summed up to:
|
||||
|
||||
1. Add `.gitlab-ci.yml` to the root directory of your repository
|
||||
1. Configure a Runner
|
||||
|
||||
From there on, on every push to your Git repository, the build will be
|
||||
automagically started by the Runner and will appear under the project's
|
||||
`/builds` page.
|
||||
From there on, on every push to your Git repository, the Runner will
|
||||
automagically start the pipeline and the pipeline will appear under the
|
||||
project's `/pipelines` page.
|
||||
|
||||
---
|
||||
|
||||
This guide assumes that you:
|
||||
|
||||
- have a working GitLab instance of version 8.0 or higher or are using
|
||||
[GitLab.com](https://gitlab.com/users/sign_in)
|
||||
[GitLab.com](https://gitlab.com)
|
||||
- have a project in GitLab that you would like to use CI for
|
||||
|
||||
Let's break it down to pieces and work on solving the GitLab CI puzzle.
|
||||
|
@ -57,15 +57,14 @@ On any push to your repository, GitLab will look for the `.gitlab-ci.yml`
|
|||
file and start builds on _Runners_ according to the contents of the file,
|
||||
for that commit.
|
||||
|
||||
Because `.gitlab-ci.yml` is in the repository, it is version controlled,
|
||||
old versions still build successfully, forks can easily make use of CI,
|
||||
branches can have separate builds and you have a single source of truth for CI.
|
||||
You can read more about the reasons why we are using `.gitlab-ci.yml`
|
||||
[in our blog about it][blog-ci].
|
||||
Because `.gitlab-ci.yml` is in the repository and is version controlled, old
|
||||
versions still build successfully, forks can easily make use of CI, branches can
|
||||
have different pipelines and jobs, and you have a single source of truth for CI.
|
||||
You can read more about the reasons why we are using `.gitlab-ci.yml` [in our
|
||||
blog about it][blog-ci].
|
||||
|
||||
**Note:** `.gitlab-ci.yml` is a [YAML](https://en.wikipedia.org/wiki/YAML) file
|
||||
so you have to pay extra attention to the indentation. Always use spaces, not
|
||||
tabs.
|
||||
so you have to pay extra attention to indentation. Always use spaces, not tabs.
|
||||
|
||||
### Creating a simple `.gitlab-ci.yml` file
|
||||
|
||||
|
@ -108,7 +107,7 @@ If you want to check whether your `.gitlab-ci.yml` file is valid, there is a
|
|||
Lint tool under the page `/ci/lint` of your GitLab instance. You can also find
|
||||
the link under **Settings > CI settings** in your project.
|
||||
|
||||
For more information and a complete `.gitlab-ci.yml` syntax, please check
|
||||
For more information and a complete `.gitlab-ci.yml` syntax, please read
|
||||
[the documentation on .gitlab-ci.yml](../yaml/README.md).
|
||||
|
||||
### Push `.gitlab-ci.yml` to GitLab
|
||||
|
@ -122,7 +121,8 @@ git commit -m "Add .gitlab-ci.yml"
|
|||
git push origin master
|
||||
```
|
||||
|
||||
Now if you go to the **Builds** page you will see that the builds are pending.
|
||||
Now if you go to the **Pipelines** page you will see that the pipeline is
|
||||
pending.
|
||||
|
||||
You can also go to the **Commits** page and notice the little clock icon next
|
||||
to the commit SHA.
|
||||
|
@ -138,15 +138,14 @@ Notice that there are two jobs pending which are named after what we wrote in
|
|||
`.gitlab-ci.yml`. The red triangle indicates that there is no Runner configured
|
||||
yet for these builds.
|
||||
|
||||
The next step is to configure a Runner so that it picks the pending jobs.
|
||||
The next step is to configure a Runner so that it picks the pending builds.
|
||||
|
||||
## Configuring a Runner
|
||||
|
||||
In GitLab, Runners run the builds that you define in `.gitlab-ci.yml`.
|
||||
A Runner can be a virtual machine, a VPS, a bare-metal machine, a docker
|
||||
container or even a cluster of containers. GitLab and the Runners communicate
|
||||
through an API, so the only needed requirement is that the machine on which the
|
||||
Runner is configured to have Internet access.
|
||||
In GitLab, Runners run the builds that you define in `.gitlab-ci.yml`. A Runner
|
||||
can be a virtual machine, a VPS, a bare-metal machine, a docker container or
|
||||
even a cluster of containers. GitLab and the Runners communicate through an API,
|
||||
so the only requirement is that the Runner's machine has Internet access.
|
||||
|
||||
A Runner can be specific to a certain project or serve multiple projects in
|
||||
GitLab. If it serves all projects it's called a _Shared Runner_.
|
||||
|
@ -188,12 +187,16 @@ To enable **Shared Runners** you have to go to your project's
|
|||
|
||||
[Read more on Shared Runners](../runners/README.md).
|
||||
|
||||
## Seeing the status of your build
|
||||
## Seeing the status of your pipeline and builds
|
||||
|
||||
After configuring the Runner successfully, you should see the status of your
|
||||
last commit change from _pending_ to either _running_, _success_ or _failed_.
|
||||
|
||||
You can view all builds, by going to the **Builds** page in your project.
|
||||
You can view all pipelines by going to the **Pipelines** page in your project.
|
||||
|
||||
![Commit status](img/pipelines_status.png)
|
||||
|
||||
Or you can view all builds, by going to the **Pipelines > Builds** page.
|
||||
|
||||
![Commit status](img/builds_status.png)
|
||||
|
||||
|
@ -238,3 +241,4 @@ CI with various languages.
|
|||
[runner]: ../runners/README.md
|
||||
[enabled]: ../enable_or_disable_ci.md
|
||||
[stages]: ../yaml/README.md#stages
|
||||
[pipeline]: ../pipelines.md
|
||||
|
|
Binary file not shown.
After Width: | Height: | Size: 87 KiB |
|
@ -54,7 +54,7 @@ of your repository and contains definitions of how your project should be built.
|
|||
|
||||
The YAML file defines a set of jobs with constraints stating when they should
|
||||
be run. The jobs are defined as top-level elements with a name and always have
|
||||
to contain the `script` clause:
|
||||
to contain at least the `script` clause:
|
||||
|
||||
```yaml
|
||||
job1:
|
||||
|
@ -165,7 +165,7 @@ stages:
|
|||
|
||||
There are also two edge cases worth mentioning:
|
||||
|
||||
1. If no `stages` is defined in `.gitlab-ci.yml`, then by default the `build`,
|
||||
1. If no `stages` are defined in `.gitlab-ci.yml`, then by default the `build`,
|
||||
`test` and `deploy` are allowed to be used as job's stage by default.
|
||||
2. If a job doesn't specify a `stage`, the job is assigned the `test` stage.
|
||||
|
||||
|
|
|
@ -26,13 +26,6 @@ Feature: Admin Groups
|
|||
When I visit group page
|
||||
Then I should see project shared with group
|
||||
|
||||
@javascript
|
||||
Scenario: Remove user from group
|
||||
Given we have user "John Doe" in group
|
||||
When I visit admin group page
|
||||
And I remove user "John Doe" from group
|
||||
Then I should not see "John Doe" in team list
|
||||
|
||||
@javascript
|
||||
Scenario: Invite user to a group by e-mail
|
||||
When I visit admin group page
|
||||
|
|
|
@ -5,53 +5,9 @@ Feature: Dashboard Group
|
|||
And "John Doe" is owner of group "Owned"
|
||||
And "John Doe" is guest of group "Guest"
|
||||
|
||||
# Leave groups
|
||||
|
||||
@javascript
|
||||
Scenario: Owner should be able to leave from group if he is not the last owner
|
||||
Given "Mary Jane" is owner of group "Owned"
|
||||
When I visit dashboard groups page
|
||||
Then I should see group "Owned" in group list
|
||||
Then I should see group "Guest" in group list
|
||||
When I click on the "Leave" button for group "Owned"
|
||||
And I visit dashboard groups page
|
||||
Then I should not see group "Owned" in group list
|
||||
Then I should see group "Guest" in group list
|
||||
|
||||
@javascript
|
||||
Scenario: Owner should not be able to leave from group if he is the last owner
|
||||
Given "Mary Jane" is guest of group "Owned"
|
||||
When I visit dashboard groups page
|
||||
Then I should see group "Owned" in group list
|
||||
Then I should see group "Guest" in group list
|
||||
When I click on the "Leave" button for group "Owned"
|
||||
Then I should see the "Can not leave message"
|
||||
|
||||
@javascript
|
||||
Scenario: Guest should be able to leave from group
|
||||
Given "Mary Jane" is guest of group "Guest"
|
||||
When I visit dashboard groups page
|
||||
Then I should see group "Owned" in group list
|
||||
Then I should see group "Guest" in group list
|
||||
When I click on the "Leave" button for group "Guest"
|
||||
When I visit dashboard groups page
|
||||
Then I should see group "Owned" in group list
|
||||
Then I should not see group "Guest" in group list
|
||||
|
||||
@javascript
|
||||
Scenario: Guest should be able to leave from group even if he is the only user in the group
|
||||
When I visit dashboard groups page
|
||||
Then I should see group "Owned" in group list
|
||||
Then I should see group "Guest" in group list
|
||||
When I click on the "Leave" button for group "Guest"
|
||||
When I visit dashboard groups page
|
||||
Then I should see group "Owned" in group list
|
||||
Then I should not see group "Guest" in group list
|
||||
|
||||
Scenario: Create a group from dasboard
|
||||
And I visit dashboard groups page
|
||||
And I click new group link
|
||||
And submit form with new group "Samurai" info
|
||||
Then I should be redirected to group "Samurai" page
|
||||
And I should see newly created group "Samurai"
|
||||
|
||||
|
|
|
@ -10,9 +10,9 @@ Feature: Project Active Tab
|
|||
Then the active main tab should be Home
|
||||
And no other main tabs should be active
|
||||
|
||||
Scenario: On Project Code
|
||||
Scenario: On Project Repository
|
||||
Given I visit my project's files page
|
||||
Then the active main tab should be Code
|
||||
Then the active main tab should be Repository
|
||||
And no other main tabs should be active
|
||||
|
||||
Scenario: On Project Issues
|
||||
|
@ -59,46 +59,46 @@ Feature: Project Active Tab
|
|||
And no other sub navs should be active
|
||||
And the active main tab should be Settings
|
||||
|
||||
# Sub Tabs: Code
|
||||
# Sub Tabs: Repository
|
||||
|
||||
Scenario: On Project Code/Files
|
||||
Scenario: On Project Repository/Files
|
||||
Given I visit my project's files page
|
||||
Then the active sub tab should be Files
|
||||
And no other sub tabs should be active
|
||||
And the active main tab should be Code
|
||||
And the active main tab should be Repository
|
||||
|
||||
Scenario: On Project Code/Commits
|
||||
Scenario: On Project Repository/Commits
|
||||
Given I visit my project's commits page
|
||||
Then the active sub tab should be Commits
|
||||
And no other sub tabs should be active
|
||||
And the active main tab should be Code
|
||||
And the active main tab should be Repository
|
||||
|
||||
Scenario: On Project Code/Network
|
||||
Scenario: On Project Repository/Network
|
||||
Given I visit my project's network page
|
||||
Then the active sub tab should be Network
|
||||
And no other sub tabs should be active
|
||||
And the active main tab should be Code
|
||||
And the active main tab should be Repository
|
||||
|
||||
Scenario: On Project Code/Compare
|
||||
Scenario: On Project Repository/Compare
|
||||
Given I visit my project's commits page
|
||||
And I click the "Compare" tab
|
||||
Then the active sub tab should be Compare
|
||||
And no other sub tabs should be active
|
||||
And the active main tab should be Code
|
||||
And the active main tab should be Repository
|
||||
|
||||
Scenario: On Project Code/Branches
|
||||
Scenario: On Project Repository/Branches
|
||||
Given I visit my project's commits page
|
||||
And I click the "Branches" tab
|
||||
Then the active sub tab should be Branches
|
||||
And no other sub tabs should be active
|
||||
And the active main tab should be Code
|
||||
And the active main tab should be Repository
|
||||
|
||||
Scenario: On Project Code/Tags
|
||||
Scenario: On Project Repository/Tags
|
||||
Given I visit my project's commits page
|
||||
And I click the "Tags" tab
|
||||
Then the active sub tab should be Tags
|
||||
And no other sub tabs should be active
|
||||
And the active main tab should be Code
|
||||
And the active main tab should be Repository
|
||||
|
||||
Scenario: On Project Issues/Browse
|
||||
Given I visit my project's issues page
|
||||
|
|
|
@ -8,21 +8,21 @@ Feature: Project Shortcuts
|
|||
@javascript
|
||||
Scenario: Navigate to files tab
|
||||
Given I press "g" and "f"
|
||||
Then the active main tab should be Code
|
||||
Then the active main tab should be Repository
|
||||
Then the active sub tab should be Files
|
||||
|
||||
@javascript
|
||||
Scenario: Navigate to commits tab
|
||||
Given I visit my project's files page
|
||||
Given I press "g" and "c"
|
||||
Then the active main tab should be Code
|
||||
Then the active main tab should be Repository
|
||||
Then the active sub tab should be Commits
|
||||
|
||||
@javascript
|
||||
Scenario: Navigate to network tab
|
||||
Given I press "g" and "n"
|
||||
Then the active sub tab should be Network
|
||||
And the active main tab should be Code
|
||||
And the active main tab should be Repository
|
||||
|
||||
@javascript
|
||||
Scenario: Navigate to graphs tab
|
||||
|
|
|
@ -62,7 +62,7 @@ class Spinach::Features::AdminGroups < Spinach::FeatureSteps
|
|||
|
||||
step 'I should see "johndoe@gitlab.com" in team list in every project as "Reporter"' do
|
||||
page.within ".group-users-list" do
|
||||
expect(page).to have_content "johndoe@gitlab.com (invited)"
|
||||
expect(page).to have_content "johndoe@gitlab.com – Invited by"
|
||||
expect(page).to have_content "Reporter"
|
||||
end
|
||||
end
|
||||
|
@ -92,12 +92,6 @@ class Spinach::Features::AdminGroups < Spinach::FeatureSteps
|
|||
current_group.add_reporter(user_john)
|
||||
end
|
||||
|
||||
step 'I remove user "John Doe" from group' do
|
||||
page.within "#user_#{user_john.id}" do
|
||||
click_link 'Remove user from group'
|
||||
end
|
||||
end
|
||||
|
||||
step 'I should not see "John Doe" in team list' do
|
||||
page.within ".group-users-list" do
|
||||
expect(page).not_to have_content "John Doe"
|
||||
|
|
|
@ -4,44 +4,6 @@ class Spinach::Features::DashboardGroup < Spinach::FeatureSteps
|
|||
include SharedPaths
|
||||
include SharedUser
|
||||
|
||||
# Leave
|
||||
|
||||
step 'I click on the "Leave" button for group "Owned"' do
|
||||
find(:css, 'li', text: "Owner").find(:css, 'i.fa.fa-sign-out').click
|
||||
# poltergeist always confirms popups.
|
||||
end
|
||||
|
||||
step 'I click on the "Leave" button for group "Guest"' do
|
||||
find(:css, 'li', text: "Guest").find(:css, 'i.fa.fa-sign-out').click
|
||||
# poltergeist always confirms popups.
|
||||
end
|
||||
|
||||
step 'I should not see the "Leave" button for group "Owned"' do
|
||||
expect(find(:css, 'li', text: "Owner")).not_to have_selector(:css, 'i.fa.fa-sign-out')
|
||||
# poltergeist always confirms popups.
|
||||
end
|
||||
|
||||
step 'I should not see the "Leave" button for groupr "Guest"' do
|
||||
expect(find(:css, 'li', text: "Guest")).not_to have_selector(:css, 'i.fa.fa-sign-out')
|
||||
# poltergeist always confirms popups.
|
||||
end
|
||||
|
||||
step 'I should see group "Owned" in group list' do
|
||||
expect(page).to have_content("Owned")
|
||||
end
|
||||
|
||||
step 'I should not see group "Owned" in group list' do
|
||||
expect(page).not_to have_content("Owned")
|
||||
end
|
||||
|
||||
step 'I should see group "Guest" in group list' do
|
||||
expect(page).to have_content("Guest")
|
||||
end
|
||||
|
||||
step 'I should not see group "Guest" in group list' do
|
||||
expect(page).not_to have_content("Guest")
|
||||
end
|
||||
|
||||
step 'I click new group link' do
|
||||
click_link "New Group"
|
||||
end
|
||||
|
@ -60,8 +22,4 @@ class Spinach::Features::DashboardGroup < Spinach::FeatureSteps
|
|||
expect(page).to have_content "Samurai"
|
||||
expect(page).to have_content "Tokugawa Shogunate"
|
||||
end
|
||||
|
||||
step 'I should see the "Can not leave message"' do
|
||||
expect(page).to have_content "You can not leave the \"Owned\" group."
|
||||
end
|
||||
end
|
||||
|
|
|
@ -13,12 +13,12 @@ class Spinach::Features::ProjectFindFile < Spinach::FeatureSteps
|
|||
end
|
||||
|
||||
step 'I should see "find file" page' do
|
||||
ensure_active_main_tab('Code')
|
||||
ensure_active_main_tab('Repository')
|
||||
expect(page).to have_selector('.file-finder-holder', count: 1)
|
||||
end
|
||||
|
||||
step 'I fill in Find by path with "git"' do
|
||||
ensure_active_main_tab('Code')
|
||||
ensure_active_main_tab('Repository')
|
||||
expect(page).to have_selector('.file-finder-holder', count: 1)
|
||||
end
|
||||
|
||||
|
|
|
@ -8,8 +8,8 @@ module SharedProjectTab
|
|||
ensure_active_main_tab('Project')
|
||||
end
|
||||
|
||||
step 'the active main tab should be Code' do
|
||||
ensure_active_main_tab('Code')
|
||||
step 'the active main tab should be Repository' do
|
||||
ensure_active_main_tab('Repository')
|
||||
end
|
||||
|
||||
step 'the active main tab should be Graphs' do
|
||||
|
|
|
@ -7,10 +7,6 @@ module Banzai
|
|||
Renderer.render_result(text, context)
|
||||
end
|
||||
|
||||
def self.pre_process(text, context)
|
||||
Renderer.pre_process(text, context)
|
||||
end
|
||||
|
||||
def self.post_process(html, context)
|
||||
Renderer.post_process(html, context)
|
||||
end
|
||||
|
|
|
@ -30,15 +30,11 @@ module Banzai
|
|||
end
|
||||
|
||||
def self.render_result(text, context = {})
|
||||
text = Pipeline[:pre_process].to_html(text, context) if text
|
||||
|
||||
Pipeline[context[:pipeline]].call(text, context)
|
||||
end
|
||||
|
||||
def self.pre_process(text, context)
|
||||
pipeline = Pipeline[:pre_process]
|
||||
|
||||
pipeline.to_html(text, context)
|
||||
end
|
||||
|
||||
# Perform post-processing on an HTML String
|
||||
#
|
||||
# This method is used to perform state-dependent changes to a String of
|
||||
|
|
|
@ -5,6 +5,8 @@
|
|||
#
|
||||
module Gitlab
|
||||
module Access
|
||||
class AccessDeniedError < StandardError; end
|
||||
|
||||
GUEST = 10
|
||||
REPORTER = 20
|
||||
DEVELOPER = 30
|
||||
|
|
|
@ -118,9 +118,7 @@ describe Groups::GroupMembersController do
|
|||
it 'cannot removes himself from the group' do
|
||||
delete :leave, group_id: group
|
||||
|
||||
expect(response).to redirect_to(group_path(group))
|
||||
expect(response).to set_flash[:alert].to "You can not leave the \"#{group.name}\" group. Transfer or delete the group."
|
||||
expect(group.users).to include user
|
||||
expect(response.status).to eq(403)
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -134,7 +132,7 @@ describe Groups::GroupMembersController do
|
|||
delete :leave, group_id: group
|
||||
|
||||
expect(response).to set_flash.to 'Your access request to the group has been withdrawn.'
|
||||
expect(response).to redirect_to(dashboard_groups_path)
|
||||
expect(response).to redirect_to(group_path(group))
|
||||
expect(group.members.request).to be_empty
|
||||
expect(group.users).not_to include user
|
||||
end
|
||||
|
|
|
@ -171,11 +171,7 @@ describe Projects::ProjectMembersController do
|
|||
delete :leave, namespace_id: project.namespace,
|
||||
project_id: project
|
||||
|
||||
expect(response).to redirect_to(
|
||||
namespace_project_path(project.namespace, project)
|
||||
)
|
||||
expect(response).to set_flash[:alert].to "You can not leave the \"#{project.human_name}\" project. Transfer or delete the project."
|
||||
expect(project.users).to include user
|
||||
expect(response.status).to eq(403)
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -190,7 +186,7 @@ describe Projects::ProjectMembersController do
|
|||
project_id: project
|
||||
|
||||
expect(response).to set_flash.to 'Your access request to the project has been withdrawn.'
|
||||
expect(response).to redirect_to(dashboard_projects_path)
|
||||
expect(response).to redirect_to(namespace_project_path(project.namespace, project))
|
||||
expect(project.members.request).to be_empty
|
||||
expect(project.users).not_to include user
|
||||
end
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
require 'spec_helper'
|
||||
|
||||
feature 'Groups > Members > Last owner cannot leave group', feature: true do
|
||||
let(:owner) { create(:user) }
|
||||
let(:group) { create(:group) }
|
||||
|
||||
background do
|
||||
group.add_owner(owner)
|
||||
login_as(owner)
|
||||
visit group_path(group)
|
||||
end
|
||||
|
||||
scenario 'user does not see a "Leave Group" link' do
|
||||
expect(page).not_to have_content 'Leave Group'
|
||||
end
|
||||
end
|
|
@ -0,0 +1,21 @@
|
|||
require 'spec_helper'
|
||||
|
||||
feature 'Groups > Members > Member leaves group', feature: true do
|
||||
let(:user) { create(:user) }
|
||||
let(:owner) { create(:user) }
|
||||
let(:group) { create(:group, :public) }
|
||||
|
||||
background do
|
||||
group.add_owner(owner)
|
||||
group.add_developer(user)
|
||||
login_as(user)
|
||||
visit group_path(group)
|
||||
end
|
||||
|
||||
scenario 'user leaves group' do
|
||||
click_link 'Leave Group'
|
||||
|
||||
expect(current_path).to eq(dashboard_groups_path)
|
||||
expect(group.users.exists?(user.id)).to be_falsey
|
||||
end
|
||||
end
|
|
@ -42,7 +42,7 @@ feature 'Groups > Members > Owner manages access requests', feature: true do
|
|||
|
||||
def expect_visible_access_request(group, user)
|
||||
expect(group.members.request.exists?(user_id: user)).to be_truthy
|
||||
expect(page).to have_content "#{group.name} access requests (1)"
|
||||
expect(page).to have_content "#{group.name} access requests 1"
|
||||
expect(page).to have_content user.name
|
||||
end
|
||||
end
|
||||
|
|
|
@ -21,6 +21,7 @@ feature 'Groups > Members > User requests access', feature: true do
|
|||
expect(page).to have_content 'Your request for access has been queued for review.'
|
||||
|
||||
expect(page).to have_content 'Withdraw Access Request'
|
||||
expect(page).not_to have_content 'Leave Group'
|
||||
end
|
||||
|
||||
scenario 'user is not listed in the group members page' do
|
||||
|
|
|
@ -41,7 +41,7 @@ feature 'Projects > Members > Master manages access requests', feature: true do
|
|||
|
||||
def expect_visible_access_request(project, user)
|
||||
expect(project.members.request.exists?(user_id: user)).to be_truthy
|
||||
expect(page).to have_content "#{project.name} access requests (1)"
|
||||
expect(page).to have_content "#{project.name} access requests 1"
|
||||
expect(page).to have_content user.name
|
||||
end
|
||||
end
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
require 'spec_helper'
|
||||
|
||||
feature 'Projects > Members > Member leaves project', feature: true do
|
||||
let(:user) { create(:user) }
|
||||
let(:project) { create(:project) }
|
||||
|
||||
background do
|
||||
project.team << [user, :developer]
|
||||
login_as(user)
|
||||
visit namespace_project_path(project.namespace, project)
|
||||
end
|
||||
|
||||
scenario 'user leaves project' do
|
||||
click_link 'Leave Project'
|
||||
|
||||
expect(current_path).to eq(dashboard_projects_path)
|
||||
expect(project.users.exists?(user.id)).to be_falsey
|
||||
end
|
||||
end
|
|
@ -0,0 +1,16 @@
|
|||
require 'spec_helper'
|
||||
|
||||
feature 'Projects > Members > Owner cannot leave project', feature: true do
|
||||
let(:owner) { create(:user) }
|
||||
let(:project) { create(:project) }
|
||||
|
||||
background do
|
||||
project.team << [owner, :owner]
|
||||
login_as(owner)
|
||||
visit namespace_project_path(project.namespace, project)
|
||||
end
|
||||
|
||||
scenario 'user does not see a "Leave Project" link' do
|
||||
expect(page).not_to have_content 'Leave Project'
|
||||
end
|
||||
end
|
|
@ -21,6 +21,7 @@ feature 'Projects > Members > User requests access', feature: true do
|
|||
expect(page).to have_content 'Your request for access has been queued for review.'
|
||||
|
||||
expect(page).to have_content 'Withdraw Access Request'
|
||||
expect(page).not_to have_content 'Leave Project'
|
||||
end
|
||||
|
||||
scenario 'user is not listed in the project members page' do
|
||||
|
|
|
@ -70,22 +70,6 @@ feature 'Project', feature: true do
|
|||
end
|
||||
end
|
||||
|
||||
describe 'leave project link' do
|
||||
let(:user) { create(:user) }
|
||||
let(:project) { create(:project, namespace: user.namespace) }
|
||||
|
||||
before do
|
||||
login_with(user)
|
||||
project.team.add_user(user, Gitlab::Access::MASTER)
|
||||
visit namespace_project_path(project.namespace, project)
|
||||
end
|
||||
|
||||
it 'click project-settings and find leave project' do
|
||||
find('#project-settings-button').click
|
||||
expect(page).to have_link('Leave Project')
|
||||
end
|
||||
end
|
||||
|
||||
describe 'project title' do
|
||||
include WaitForAjax
|
||||
|
||||
|
|
|
@ -134,18 +134,6 @@ describe Member, models: true do
|
|||
it { is_expected.to respond_to(:user_email) }
|
||||
end
|
||||
|
||||
describe 'Callbacks' do
|
||||
describe 'after_destroy :post_decline_request, if: :request?' do
|
||||
let(:member) { create(:project_member, requested_at: Time.now.utc) }
|
||||
|
||||
it 'calls #post_decline_request' do
|
||||
expect(member).to receive(:post_decline_request)
|
||||
|
||||
member.destroy
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe ".add_user" do
|
||||
let!(:user) { create(:user) }
|
||||
let(:project) { create(:project) }
|
||||
|
|
|
@ -61,16 +61,6 @@ describe GroupMember, models: true do
|
|||
end
|
||||
end
|
||||
|
||||
describe '#post_decline_request' do
|
||||
it 'calls NotificationService.decline_group_access_request' do
|
||||
member = create(:group_member, user: build_stubbed(:user), requested_at: Time.now)
|
||||
|
||||
expect_any_instance_of(NotificationService).to receive(:decline_group_access_request)
|
||||
|
||||
member.__send__(:post_decline_request)
|
||||
end
|
||||
end
|
||||
|
||||
describe '#real_source_type' do
|
||||
subject { create(:group_member).real_source_type }
|
||||
|
||||
|
|
|
@ -152,15 +152,5 @@ describe ProjectMember, models: true do
|
|||
member.__send__(:after_accept_request)
|
||||
end
|
||||
end
|
||||
|
||||
describe '#post_decline_request' do
|
||||
it 'calls NotificationService.decline_project_access_request' do
|
||||
member = create(:project_member, user: build_stubbed(:user), requested_at: Time.now)
|
||||
|
||||
expect_any_instance_of(NotificationService).to receive(:decline_project_access_request)
|
||||
|
||||
member.__send__(:post_decline_request)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -0,0 +1,71 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe Members::DestroyService, services: true do
|
||||
let(:user) { create(:user) }
|
||||
let(:project) { create(:project) }
|
||||
let!(:member) { create(:project_member, source: project) }
|
||||
|
||||
context 'when member is nil' do
|
||||
before do
|
||||
project.team << [user, :developer]
|
||||
end
|
||||
|
||||
it 'does not destroy the member' do
|
||||
expect { destroy_member(nil, user) }.to raise_error(Gitlab::Access::AccessDeniedError)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when current user cannot destroy the given member' do
|
||||
before do
|
||||
project.team << [user, :developer]
|
||||
end
|
||||
|
||||
it 'does not destroy the member' do
|
||||
expect { destroy_member(member, user) }.to raise_error(Gitlab::Access::AccessDeniedError)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when current user can destroy the given member' do
|
||||
before do
|
||||
project.team << [user, :master]
|
||||
end
|
||||
|
||||
it 'destroys the member' do
|
||||
destroy_member(member, user)
|
||||
|
||||
expect(member).to be_destroyed
|
||||
end
|
||||
|
||||
context 'when the given member is a requester' do
|
||||
before do
|
||||
member.update_column(:requested_at, Time.now)
|
||||
end
|
||||
|
||||
it 'calls Member#after_decline_request' do
|
||||
expect_any_instance_of(NotificationService).to receive(:decline_access_request).with(member)
|
||||
|
||||
destroy_member(member, user)
|
||||
end
|
||||
|
||||
context 'when current user is the member' do
|
||||
it 'does not call Member#after_decline_request' do
|
||||
expect_any_instance_of(NotificationService).not_to receive(:decline_access_request).with(member)
|
||||
|
||||
destroy_member(member, member.user)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when current user is the member and ' do
|
||||
it 'does not call Member#after_decline_request' do
|
||||
expect_any_instance_of(NotificationService).not_to receive(:decline_access_request).with(member)
|
||||
|
||||
destroy_member(member, member.user)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def destroy_member(member, user)
|
||||
Members::DestroyService.new(member, user).execute
|
||||
end
|
||||
end
|
Loading…
Reference in New Issue