Commit d377c341 authored by Valery Sizov's avatar Valery Sizov

Merge branch 'ce_upstream' into 'master'

CE upstream



See merge request !543
parents 893aa713 47eddb10
......@@ -284,7 +284,7 @@ Style/IfWithSemicolon:
# Checks that conditional statements do not have an identical line at the
# end of each branch, which can validly be moved out of the conditional.
Style/IdenticalConditionalBranches:
Enabled: false
Enabled: true
# Checks the indentation of the first line of the right-hand-side of a
# multi-line assignment.
......
......@@ -29,8 +29,10 @@ v 8.10.0 (unreleased)
- Wildcards for protected branches. !4665
- Allow importing from Github using Personal Access Tokens. (Eric K Idema)
- API: Todos !3188 (Robert Schilling)
- API: Expose shared groups for projects and shared projects for groups !5050 (Robert Schilling)
- Add "Enabled Git access protocols" to Application Settings
- Fix user creation with stronger minimum password requirements !4054 (nathan-pmt)
- Only show New Snippet button to users that can create snippets.
- PipelinesFinder uses git cache data
- Throttle the update of `project.pushes_since_gc` to 1 minute.
- Check for conflicts with existing Project's wiki path when creating a new project.
......@@ -39,6 +41,7 @@ v 8.10.0 (unreleased)
- Bump Rinku to 2.0.0
- Remove unused front-end variable -> default_issues_tracker
- Better caching of git calls on ProjectsController#show.
- Avoid to retrieve MR closes_issues as much as possible.
- Add API endpoint for a group issues !4520 (mahcsig)
- Add Bugzilla integration !4930 (iamtjg)
- Instrument Rinku usage
......@@ -46,6 +49,8 @@ v 8.10.0 (unreleased)
- RailsCache metris now includes fetch_hit/fetch_miss and read_hit/read_miss info.
- Allow [ci skip] to be in any case and allow [skip ci]. !4785 (simon_w)
- Set import_url validation to be more strict
- Memoize MR merged/closed events retrieval
- Don't render discussion notes when requesting diff tab through AJAX
- Add basic system information like memory and disk usage to the admin panel
- Don't garbage collect commits that have related DB records like comments
- More descriptive message for git hooks and file locks
......@@ -54,6 +59,8 @@ v 8.10.0 (unreleased)
- Fix importer for GitHub Pull Requests when a branch was reused across Pull Requests
- Add date when user joined the team on the member page
- Fix 404 redirect after validation fails importing a GitLab project
- Added setting to set new users by default as external !4545 (Dravere)
- Add min value for project limit field on user's form !3622 (jastkand)
v 8.9.5
- Add more debug info to import/export and memory killer. !5108
......@@ -98,7 +105,7 @@ v 8.9.3
- Removed fade when filtering results. !4932
- Fix missing avatar on system notes. !4954
- Reduce overhead and optimize ProjectTeam#max_member_access performance. !4973
- Use update_columns to by_pass all the dirty code on active_record. !4985
- Use update_columns to bypass all the dirty code on active_record. !4985
- Fix restore Rake task warning message output !4980
v 8.9.2
......
source "https://rubygems.org"
source 'https://rubygems.org'
gem 'rails', '4.2.6'
gem 'rails-deprecated_sanitizer', '~> 1.0.3'
......@@ -11,11 +11,11 @@ gem 'responders', '~> 2.0'
gem 'sprockets', '~> 3.6.0'
# Default values for AR models
gem "default_value_for", "~> 3.0.0"
gem 'default_value_for', '~> 3.0.0'
# Supported DBs
gem "mysql2", '~> 0.3.16', group: :mysql
gem "pg", '~> 0.18.2', group: :postgres
gem 'mysql2', '~> 0.3.16', group: :mysql
gem 'pg', '~> 0.18.2', group: :postgres
# Authentication libraries
gem 'devise', '~> 4.0'
......@@ -52,16 +52,16 @@ gem 'u2f', '~> 0.2.1'
gem 'validates_hostname', '~> 1.0.0'
# Browser detection
gem "browser", '~> 2.2'
gem 'browser', '~> 2.2'
# Extracting information from a git repository
# Provide access to Gitlab::Git library
gem "gitlab_git", '~> 10.2'
gem 'gitlab_git', '~> 10.2'
# LDAP Auth
# GitLab fork with several improvements to original library. For full list of changes
# see https://github.com/intridea/omniauth-ldap/compare/master...gitlabhq:master
gem 'gitlab_omniauth-ldap', '~> 1.2.1', require: "omniauth-ldap"
gem 'gitlab_omniauth-ldap', '~> 1.2.1', require: 'omniauth-ldap'
gem 'net-ldap'
# Git Wiki
......@@ -70,7 +70,7 @@ gem 'gollum-lib', '~> 4.1.0', require: false
gem 'gollum-rugged_adapter', '~> 0.4.2', require: false
# Language detection
gem "github-linguist", "~> 4.7.0", require: "linguist"
gem 'github-linguist', '~> 4.7.0', require: 'linguist'
# API
gem 'grape', '~> 0.13.0'
......@@ -78,13 +78,13 @@ gem 'grape-entity', '~> 0.4.2'
gem 'rack-cors', '~> 0.4.0', require: 'rack/cors'
# Pagination
gem "kaminari", "~> 0.17.0"
gem 'kaminari', '~> 0.17.0'
# HAML
gem 'hamlit', '~> 2.5'
# Files attachments
gem "carrierwave", '~> 0.10.0'
gem 'carrierwave', '~> 0.10.0'
# Drag and Drop UI
gem 'dropzonejs-rails', '~> 0.7.1'
......@@ -99,13 +99,13 @@ gem 'fog-openstack', '~> 0.1'
gem 'fog-rackspace', '~> 0.1.1'
# for aws storage
gem "unf", '~> 0.1.4'
gem 'unf', '~> 0.1.4'
# Authorization
gem "six", '~> 0.2.0'
gem 'six', '~> 0.2.0'
# Seed data
gem "seed-fu", '~> 2.3.5'
gem 'seed-fu', '~> 2.3.5'
# Search
gem 'elasticsearch-model'
......@@ -134,29 +134,29 @@ gem 'diffy', '~> 3.0.3'
# Application server
group :unicorn do
gem "unicorn", '~> 4.9.0'
gem 'unicorn', '~> 4.9.0'
gem 'unicorn-worker-killer', '~> 0.4.2'
end
# State machine
gem "state_machines-activerecord", '~> 0.4.0'
gem 'state_machines-activerecord', '~> 0.4.0'
# Run events after state machine commits
gem 'after_commit_queue'
gem 'after_commit_queue', '~> 1.3.0'
# Issue tags
gem 'acts-as-taggable-on', '~> 3.4'
# Background jobs
gem 'sinatra', '~> 1.4.4', require: nil
gem 'sinatra', '~> 1.4.4', require: false
gem 'sidekiq', '~> 4.0'
gem 'sidekiq-cron', '~> 0.4.0'
gem 'redis-namespace'
gem 'redis-namespace', '~> 1.5.2'
# HTTP requests
gem "httparty", '~> 0.13.3'
gem 'httparty', '~> 0.13.3'
# Colored output to console
gem "rainbow", '~> 2.1.0'
gem 'rainbow', '~> 2.1.0'
# GitLab settings
gem 'settingslogic', '~> 2.0.9'
......@@ -166,7 +166,7 @@ gem 'settingslogic', '~> 2.0.9'
gem 'version_sorter', '~> 2.0.0'
# Cache
gem "redis-rails", '~> 4.0.0'
gem 'redis-rails', '~> 4.0.0'
# Redis
gem 'redis', '~> 3.2'
......@@ -179,13 +179,13 @@ gem 'tinder', '~> 1.10.0'
gem 'hipchat', '~> 1.5.0'
# Flowdock integration
gem "gitlab-flowdock-git-hook", "~> 1.0.1"
gem 'gitlab-flowdock-git-hook', '~> 1.0.1'
# Gemnasium integration
gem "gemnasium-gitlab-service", "~> 0.2"
gem 'gemnasium-gitlab-service', '~> 0.2'
# Slack integration
gem "slack-notifier", "~> 1.2.0"
gem 'slack-notifier', '~> 1.2.0'
# Asana integration
gem 'asana', '~> 0.4.0'
......@@ -197,20 +197,20 @@ gem 'ruby-fogbugz', '~> 0.2.1'
gem 'd3_rails', '~> 3.5.0'
# underscore-rails
gem "underscore-rails", "~> 1.8.0"
gem 'underscore-rails', '~> 1.8.0'
# Sanitize user input
gem "sanitize", '~> 2.0'
gem 'sanitize', '~> 2.0'
gem 'babosa', '~> 1.0.2'
# Sanitizes SVG input
gem "loofah", "~> 2.0.3"
gem 'loofah', '~> 2.0.3'
# Working with license
gem 'licensee', '~> 8.0.0'
# Protect against bruteforcing
gem "rack-attack", '~> 4.3.1'
gem 'rack-attack', '~> 4.3.1'
# Ace editor
gem 'ace-rails-ap', '~> 4.0.2'
......@@ -224,9 +224,9 @@ gem 'charlock_holmes', '~> 0.7.3'
# Parse duration
gem 'chronic_duration', '~> 0.10.6'
gem "sass-rails", '~> 5.0.0'
gem "coffee-rails", '~> 4.1.0'
gem "uglifier", '~> 2.7.2'
gem 'sass-rails', '~> 5.0.0'
gem 'coffee-rails', '~> 4.1.0'
gem 'uglifier', '~> 2.7.2'
gem 'turbolinks', '~> 2.5.0'
gem 'jquery-turbolinks', '~> 2.1.0'
......@@ -258,13 +258,13 @@ group :metrics do
end
group :development do
gem "foreman"
gem 'foreman', '~> 0.78.0'
gem 'brakeman', '~> 3.3.0', require: false
gem 'letter_opener_web', '~> 1.3.0'
gem 'rerun', '~> 0.11.0'
gem 'bullet', require: false
gem 'rblineprof', platform: :mri, require: false
gem 'bullet', '~> 5.0.0', require: false
gem 'rblineprof', '~> 0.3.6', platform: :mri, require: false
gem 'web-console', '~> 2.0'
# Better errors handler
......@@ -272,15 +272,15 @@ group :development do
gem 'binding_of_caller', '~> 0.7.2'
# Docs generator
gem "sdoc", '~> 0.3.20'
gem 'sdoc', '~> 0.3.20'
# thin instead webrick
gem 'thin', '~> 1.7.0'
end
group :development, :test do
gem 'byebug', platform: :mri
gem 'pry-rails'
gem 'byebug', '~> 8.2.1', platform: :mri
gem 'pry-rails', '~> 0.3.4'
gem 'awesome_print', '~> 1.2.0', require: false
gem 'fuubar', '~> 2.0.0'
......@@ -288,7 +288,7 @@ group :development, :test do
gem 'database_cleaner', '~> 1.4.0'
gem 'factory_girl_rails', '~> 4.6.0'
gem 'rspec-rails', '~> 3.5.0'
gem 'rspec-retry'
gem 'rspec-retry', '~> 0.4.5'
gem 'spinach-rails', '~> 0.2.1'
gem 'spinach-rerun-reporter', '~> 0.0.2'
......@@ -314,14 +314,14 @@ group :development, :test do
gem 'rubocop-rspec', '~> 1.5.0', require: false
gem 'scss_lint', '~> 0.47.0', require: false
gem 'simplecov', '~> 0.11.0', require: false
gem 'flog', require: false
gem 'flay', require: false
gem 'bundler-audit', require: false
gem 'flog', '~> 4.3.2', require: false
gem 'flay', '~> 2.6.1', require: false
gem 'bundler-audit', '~> 0.5.0', require: false
gem 'benchmark-ips', require: false
gem 'benchmark-ips', '~> 2.3.0', require: false
gem "license_finder", require: false
gem 'knapsack'
gem 'license_finder', '~> 2.1.0', require: false
gem 'knapsack', '~> 1.11.0'
end
group :test do
......@@ -329,30 +329,30 @@ group :test do
gem 'email_spec', '~> 1.6.0'
gem 'webmock', '~> 1.21.0'
gem 'test_after_commit', '~> 0.4.2'
gem 'sham_rack'
gem 'sham_rack', '~> 1.3.6'
end
group :production do
gem "gitlab_meta", '7.0'
gem 'gitlab_meta', '7.0'
end
gem "newrelic_rpm", '~> 3.14'
gem 'newrelic_rpm', '~> 3.14'
gem 'octokit', '~> 4.3.0'
gem "mail_room", "~> 0.8"
gem 'mail_room', '~> 0.8'
gem 'email_reply_parser', '~> 0.5.8'
## CI
gem 'activerecord-session_store', '~> 1.0.0'
gem "nested_form", '~> 0.3.2'
gem 'nested_form', '~> 0.3.2'
# OAuth
gem 'oauth2', '~> 1.2.0'
# Soft deletion
gem "paranoia", "~> 2.0"
gem 'paranoia', '~> 2.0'
# Health check
gem 'health_check', '~> 1.5.1'
......
......@@ -55,7 +55,6 @@
#= require_directory ./u2f
#= require_directory .
#= require fuzzaldrin-plus
#= require cropper
#= require u2f
window.slugify = (text) ->
......
......@@ -135,7 +135,6 @@ class Dispatcher
when 'dashboard', 'root'
shortcut_handler = new ShortcutsDashboardNavigation()
when 'profiles'
new Profile()
new NotificationsForm()
new NotificationsDropdown()
when 'projects'
......
......@@ -5,12 +5,12 @@
w.gl.utils.isInGroupsPage = ->
return $('body').data('page').split(':')[0] is 'groups'
return gl.utils.getPagePath() is 'groups'
w.gl.utils.isInProjectPage = ->
return $('body').data('page').split(':')[0] is 'projects'
return gl.utils.getPagePath() is 'projects'
w.gl.utils.getProjectSlug = ->
......@@ -43,6 +43,9 @@
gl.utils.capitalize = (str) ->
return str[0].toUpperCase() + str.slice(1);
gl.utils.getPagePath = ->
return $('body').data('page').split(':')[0]
jQuery.timefor = (time, suffix, expiredLabel) ->
......
......@@ -78,3 +78,6 @@ $ ->
if comment && comment.length > 1 && $title.val() == ''
$title.val(comment[1]).change()
if gl.utils.getPagePath() == 'profiles'
new Profile()
......@@ -77,10 +77,10 @@
&.sub-nav {
text-align: center;
background-color: $background-color;
background-color: $dark-background-color;
.container-fluid {
background-color: $background-color;
background-color: $dark-background-color;
margin-bottom: 0;
}
......
......@@ -12,10 +12,11 @@ $sidebar-breakpoint: 1024px;
/*
* UI elements
*/
$border-color: #e5e5e5;
$focus-border-color: #3aabf0;
$table-border-color: #f0f0f0;
$background-color: #fafafa;
$border-color: #e5e5e5;
$focus-border-color: #3aabf0;
$table-border-color: #f0f0f0;
$background-color: #fafafa;
$dark-background-color: #f7f7f7;
/*
* Text
......@@ -153,9 +154,6 @@ $warning-message-bg: #fbf2d9;
$warning-message-color: #9e8e60;
$warning-message-border: #f0e2bb;
/* header */
$light-grey-header: #faf9f9;
/* tanuki logo colors */
$tanuki-red: #e24329;
$tanuki-orange: #fc6d26;
......
......@@ -90,6 +90,7 @@ class Admin::ApplicationSettingsController < Admin::ApplicationController
:version_check_enabled,
:admin_notification_email,
:user_oauth_applications,
:user_default_external,
:shared_runners_enabled,
:shared_runners_text,
:max_artifacts_size,
......
......@@ -10,7 +10,6 @@ class Projects::MergeRequestsController < Projects::ApplicationController
:ci_status, :toggle_subscription, :cancel_merge_when_build_succeeds, :remove_wip,
:approve, :rebase
]
before_action :closes_issues, only: [:edit, :update, :show, :diffs, :commits, :builds]
before_action :validates_merge_request, only: [:show, :diffs, :commits, :builds]
before_action :define_show_vars, only: [:show, :diffs, :commits, :builds]
before_action :define_widget_vars, only: [:merge, :cancel_merge_when_build_succeeds, :merge_check]
......@@ -54,9 +53,6 @@ class Projects::MergeRequestsController < Projects::ApplicationController
end
def show
@note_counts = Note.where(commit_id: @merge_request.commits.map(&:id)).
group(:commit_id).count
respond_to do |format|
format.html
......@@ -81,6 +77,8 @@ class Projects::MergeRequestsController < Projects::ApplicationController
def diffs
apply_diff_view_cookie!
@merge_request_diff = @merge_request.merge_request_diff
@commit = @merge_request.diff_head_commit
@base_commit = @merge_request.diff_base_commit || @merge_request.likely_diff_base_commit
......@@ -110,7 +108,15 @@ class Projects::MergeRequestsController < Projects::ApplicationController
def commits
respond_to do |format|
format.html { render 'show' }
format.json { render json: { html: view_to_html_string('projects/merge_requests/show/_commits') } }
format.json do
# Get commits from repository
# or from cache if already merged
@commits = @merge_request.commits
@note_counts = Note.where(commit_id: @commits.map(&:id)).
group(:commit_id).count
render json: { html: view_to_html_string('projects/merge_requests/show/_commits') }
end
end
end
......@@ -348,10 +354,6 @@ class Projects::MergeRequestsController < Projects::ApplicationController
alias_method :issuable, :merge_request
alias_method :awardable, :merge_request
def closes_issues
@closes_issues ||= @merge_request.closes_issues
end
def authorize_update_merge_request!
return render_404 unless can?(current_user, :update_merge_request, @merge_request)
end
......@@ -380,14 +382,33 @@ class Projects::MergeRequestsController < Projects::ApplicationController
end
def define_show_vars
@noteable = @merge_request
@commits_count = @merge_request.commits.count
@pipeline = @merge_request.pipeline
@statuses = @pipeline.statuses if @pipeline
if @merge_request.locked_long_ago?
@merge_request.unlock_mr
@merge_request.close
end
if request.format == :html || action_name == 'show'
define_show_html_vars
end
end
# Discussion tab data is only required on html requests
def define_show_html_vars
# Build a note object for comment form
@note = @project.notes.new(noteable: @merge_request)
@note = @project.notes.new(noteable: @noteable)
@discussions = @merge_request.mr_and_commit_notes.
@discussions = @noteable.mr_and_commit_notes.
inc_author_project_award_emoji.
fresh.
discussions
# This is not executed lazily
@notes = Banzai::NoteRenderer.render(
@discussions.flatten,
@project,
......@@ -396,28 +417,11 @@ class Projects::MergeRequestsController < Projects::ApplicationController
@project_wiki,
@ref
)
@noteable = @merge_request
# Get commits from repository
# or from cache if already merged
@commits = @merge_request.commits
@merge_request_diff = @merge_request.merge_request_diff
@pipeline = @merge_request.pipeline
@statuses = @pipeline.statuses if @pipeline
if @merge_request.locked_long_ago?
@merge_request.unlock_mr
@merge_request.close
end
end
def define_widget_vars
@pipeline = @merge_request.pipeline
@pipelines = [@pipeline].compact
closes_issues
end
def invalid_mr
......
......@@ -53,11 +53,11 @@ class ProjectsController < Projects::ApplicationController
notice: "Project '#{@project.name}' was successfully updated."
)
end
format.js
else
format.html { render 'edit' }
format.js
end
format.js
end
end
......
......@@ -55,6 +55,10 @@ module MergeRequestsHelper
end.sort.to_sentence
end
def mr_closes_issues
@mr_closes_issues ||= @merge_request.closes_issues
end
def mr_change_branches_path(merge_request)
new_namespace_project_merge_request_path(
@project.namespace, @project,
......
......@@ -152,6 +152,7 @@ class ApplicationSetting < ActiveRecord::Base
elasticsearch_host: ENV['ELASTIC_HOST'] || 'localhost',
elasticsearch_port: ENV['ELASTIC_PORT'] || '9200',
repository_storage: 'default',
user_default_external: false,
)
end
......
......@@ -23,7 +23,7 @@ class CommitRange
attr_reader :commit_from, :notation, :commit_to
attr_reader :ref_from, :ref_to
# Optional Project model
# The Project model
attr_accessor :project
# The beginning and ending refs can be named or SHAs, and
......@@ -56,7 +56,7 @@ class CommitRange
# Initialize a CommitRange
#
# range_string - The String commit range.
# project - An optional Project model.
# project - The Project model.
#
# Raises ArgumentError if `range_string` does not match `PATTERN`.
def initialize(range_string, project)
......
......@@ -339,11 +339,11 @@ class MergeRequest < ActiveRecord::Base
end
def merge_event
self.target_project.events.where(target_id: self.id, target_type: "MergeRequest", action: Event::MERGED).last
@merge_event ||= target_project.events.where(target_id: self.id, target_type: "MergeRequest", action: Event::MERGED).last
end
def closed_event
self.target_project.events.where(target_id: self.id, target_type: "MergeRequest", action: Event::CLOSED).last
@closed_event ||= target_project.events.where(target_id: self.id, target_type: "MergeRequest", action: Event::CLOSED).last
end
WIP_REGEX = /\A\s*(\[WIP\]\s*|WIP:\s*|WIP\s+)+\s*/i.freeze
......
......@@ -112,15 +112,7 @@ class IrkerService < Service
# Authorize both irc://domain.com/#chan and irc://domain.com/chan
if uri.is_a?(URI) && uri.scheme[/^ircs?\z/] && !uri.path.nil?
# Do not authorize irc://domain.com/
if uri.fragment.nil? && uri.path.length > 1
uri.to_s
else
# Authorize irc://domain.com/smthg#chan
# The irker daemon will deal with it by concatenating smthg and
# chan, thus sending messages on #smthgchan
uri.to_s
end
uri.to_s
end
end
end
......@@ -15,7 +15,7 @@ class User < ActiveRecord::Base
add_authentication_token_field :authentication_token
default_value_for :admin, false
default_value_for :external, false
default_value_for(:external) { current_application_settings.user_default_external }
default_value_for :can_create_group, gitlab_config.default_can_create_group
default_value_for :can_create_team, false
default_value_for :hide_no_ssh_key, false
......
......@@ -62,19 +62,14 @@ module MergeRequests
merge_requests.each do |merge_request|
if merge_request.source_branch == @branch_name || force_push?
merge_request.reload_diff
merge_request.mark_as_unchecked
else
mr_commit_ids = merge_request.commits.map(&:id)
push_commit_ids = @commits.map(&:id)
matches = mr_commit_ids & push_commit_ids
if matches.any?
merge_request.reload_diff
merge_request.mark_as_unchecked
else
merge_request.mark_as_unchecked
end
merge_request.reload_diff if matches.any?
end
merge_request.mark_as_unchecked
end
end
......
......@@ -3,14 +3,14 @@
%tr
%td
- if user
= link_to user.name, [:admin, user]
= link_to user.name, user
.light.small
Joined #{time_ago_with_tooltip(user.created_at)}
- else
(removed)
%td
- if reporter
= link_to reporter.name, [:admin, reporter]
= link_to reporter.name, reporter
- else
(removed)
.light.small
......
......@@ -100,6 +100,13 @@
= f.label :user_oauth_applications do
= f.check_box :user_oauth_applications
Allow users to register any application to use GitLab as an OAuth provider
.form-group
= f.label :user_default_external, 'New users set to external', class: 'control-label col-sm-2'
.col-sm-10
.checkbox
= f.label :user_default_external do
= f.check_box :user_default_external
Newly registered users will by default be external
%fieldset
%legend Sign-in Restrictions
......
......@@ -44,7 +44,7 @@
%legend Access
.form-group
= f.label :projects_limit, class: 'control-label'
.col-sm-10= f.number_field :projects_limit, class: 'form-control'
.col-sm-10= f.number_field :projects_limit, min: 0, class: 'form-control'
.form-group
= f.label :can_create_group, class: 'control-label'
......
......@@ -10,7 +10,6 @@
- if current_user
.pull-right
= link_to new_snippet_path, class: "btn btn-new", title: "New Snippet" do
= icon('plus')
New Snippet
.oneline
......
- content_for :page_specific_javascripts do
= page_specific_javascript_tag('lib/cropper.js')
= page_specific_javascript_tag('profile/application.js')
- page_title "Account"
= render 'profiles/head'
- if current_user.ldap_user?
.alert.alert-info
......
- page_title "Audit Log"
= render 'profiles/head'
.row.prepend-top-default
.col-lg-3.profile-settings-sidebar
......
- page_title "Emails"
= render 'profiles/head'
.row.prepend-top-default
.col-lg-3.profile-settings-sidebar
......
- page_title @key.title, "SSH Keys"
= render 'profiles/head'
= render "key_details"
- page_title "Notifications"
= render 'profiles/head'
%div
- if @user.errors.any?
......
- page_title "Personal Access Tokens"
= render 'profiles/head'
.row.prepend-top-default
.col-lg-3.profile-settings-sidebar
......
- page_title 'Preferences'
= render 'profiles/head'
= form_for @user, url: profile_preferences_path, remote: true, method: :put, html: {class: 'row prepend-top-default js-preferences-form'} do |f|
.col-lg-3.profile-settings-sidebar
......
= render 'profiles/head'
= form_for @user, url: profile_path, method: :put, html: { multipart: true, class: "edit-user prepend-top-default" }, authenticity_token: true do |f|
= form_errors(@user)
......
- page_title 'Two-Factor Authentication', 'Account'
- header_title "Two-Factor Authentication", profile_two_factor_auth_path
= render 'profiles/head'
.row.prepend-top-default
.col-lg-3
......
......@@ -42,7 +42,7 @@
= succeed '.' do
= link_to "command line", "#modal_merge_info", class: "how_to_merge_link vlink", title: "How To Merge", "data-toggle" => "modal"
- if @commits.present?
- if @commits_count.nonzero?
%ul.merge-request-tabs.nav-links.no-top.no-bottom
%li.notes-tab
= link_to namespace_project_merge_request_path(@project.namespace, @project, @merge_request), data: {target: 'div#notes', action: 'notes', toggle: 'tab'} do
......@@ -51,7 +51,7 @@
%li.commits-tab
= link_to commits_namespace_project_merge_request_path(@project.namespace, @project, @merge_request), data: {target: 'div#commits', action: 'commits', toggle: 'tab'} do
Commits
%span.badge= @commits.size
%span.badge= @commits_count
- if @pipeline
%li.builds-tab
= link_to builds_namespace_project_merge_request_path(@project.namespace, @project, @merge_request), data: {target: '#builds', action: 'builds', toggle: 'tab'} do
......
......@@ -28,13 +28,13 @@
- else
= render 'projects/merge_requests/widget/open/accept'
- if @closes_issues.present?
- if mr_closes_issues.present?
.mr-widget-footer
%span
%i.fa.fa-check
Accepting this merge request will close #{"issue".pluralize(@closes_issues.size)}
Accepting this merge request will close #{"issue".pluralize(mr_closes_issues.size)}
= succeed '.' do
!= markdown issues_sentence(@closes_issues), pipeline: :gfm, author: @merge_request.author
!= markdown issues_sentence(mr_closes_issues), pipeline: :gfm, author: @merge_request.author
- if @merge_request.approvals.any?
.mr-widget-footer.approved-by-users
......
.hidden-xs
= link_to new_namespace_project_snippet_path(@project.namespace, @project), class: 'btn btn-grouped btn-create new-snippet-link', title: "New Snippet" do
= icon('plus')
New Snippet
- if can?(current_user, :create_project_snippet, @project)
= link_to new_namespace_project_snippet_path(@project.namespace, @project), class: 'btn btn-grouped btn-create new-snippet-link', title: "New Snippet" do
New Snippet
- if can?(current_user, :update_project_snippet, @snippet)
= link_to edit_namespace_project_snippet_path(@project.namespace, @project, @snippet), class: "btn btn-grouped snippable-edit" do
Edit
- if can?(current_user, :update_project_snippet, @snippet)
= link_to namespace_project_snippet_path(@project.namespace, @project, @snippet), method: :delete, data: { confirm: "Are you sure?" }, class: "btn btn-grouped btn-warning", title: 'Delete Snippet' do
Delete
.visible-xs-block.dropdown
%button.btn.btn-default.btn-block.append-bottom-0.prepend-top-5{ data: { toggle: "dropdown" } }
Options
%span.caret
.dropdown-menu.dropdown-menu-full-width
%ul
%li
= link_to new_namespace_project_snippet_path(@project.namespace, @project), title: "New Snippet" do
New Snippet
- if can?(current_user, :update_project_snippet, @snippet)
%li
= link_to edit_namespace_project_snippet_path(@project.namespace, @project, @snippet) do
Edit
- if can?(current_user, :update_project_snippet, @snippet)
%li
= link_to namespace_project_snippet_path(@project.namespace, @project, @snippet), method: :delete, data: { confirm: "Are you sure?" }, title: 'Delete Snippet' do
Delete
- if can?(current_user, :create_project_snippet, @project) || can?(current_user, :update_project_snippet, @snippet)
.visible-xs-block.dropdown
%button.btn.btn-default.btn-block.append-bottom-0.prepend-top-5{ data: { toggle: "dropdown" } }
Options
%span.caret
.dropdown-menu.dropdown-menu-full-width
%ul
- if can?(current_user, :create_project_snippet, @project)
%li
= link_to new_namespace_project_snippet_path(@project.namespace, @project), title: "New Snippet" do
New Snippet
- if can?(current_user, :update_project_snippet, @snippet)
%li
= link_to edit_namespace_project_snippet_path(@project.namespace, @project, @snippet) do
Edit
- if can?(current_user, :update_project_snippet, @snippet)
%li
= link_to namespace_project_snippet_path(@project.namespace, @project, @snippet), method: :delete, data: { confirm: "Are you sure?" }, title: 'Delete Snippet' do
Delete
......@@ -2,9 +2,9 @@
.row-content-block.top-block
.pull-right
= link_to new_namespace_project_snippet_path(@project.namespace, @project), class: "btn btn-new", title: "New Snippet" do
= icon('plus')
New Snippet
- if can?(current_user, :create_project_snippet, @project)
= link_to new_namespace_project_snippet_path(@project.namespace, @project), class: "btn btn-new", title: "New Snippet" do
New Snippet
.oneline
Share code pastes with others out of git repository
......
.hidden-xs
= link_to new_snippet_path, class: "btn btn-grouped btn-create new-snippet-link", title: "New Snippet" do
= icon('plus')
New Snippet
- if current_user
= link_to new_snippet_path, class: "btn btn-grouped btn-create new-snippet-link", title: "New Snippet" do
New Snippet
- if can?(current_user, :update_personal_snippet, @snippet)
= link_to edit_snippet_path(@snippet), class: "btn btn-grouped snippable-edit" do
Edit
- if can?(current_user, :admin_personal_snippet, @snippet)
= link_to snippet_path(@snippet), method: :delete, data: { confirm: "Are you sure?" }, class: "btn btn-grouped btn-warning", title: 'Delete Snippet' do
= link_to snippet_path(@snippet), method: :delete, data: { confirm: "Are you sure?" }, class: "btn btn-grouped btn-danger", title: 'Delete Snippet' do
Delete
.visible-xs-block.dropdown
%button.btn.btn-default.btn-block.append-bottom-0.prepend-top-5{ data: { toggle: "dropdown" } }
Options
%span.caret
.dropdown-menu.dropdown-menu-full-width
%ul
%li
= link_to new_snippet_path, title: "New Snippet" do
New Snippet
- if can?(current_user, :update_personal_snippet, @snippet)
- if current_user
.visible-xs-block.dropdown
%button.btn.btn-default.btn-block.append-bottom-0.prepend-top-5{ data: { toggle: "dropdown" } }
Options
%span.caret
.dropdown-menu.dropdown-menu-full-width
%ul
%li
= link_to edit_snippet_path(@snippet) do
Edit
- if can?(current_user, :admin_personal_snippet, @snippet)
%li
= link_to snippet_path(@snippet), method: :delete, data: { confirm: "Are you sure?" }, title: 'Delete Snippet' do
Delete
= link_to new_snippet_path, title: "New Snippet" do
New Snippet
- if can?(current_user, :update_personal_snippet, @snippet)
%li
= link_to edit_snippet_path(@snippet) do
Edit
- if can?(current_user, :admin_personal_snippet, @snippet)
%li
= link_to snippet_path(@snippet), method: :delete, data: { confirm: "Are you sure?" }, title: 'Delete Snippet' do
Delete
......@@ -29,6 +29,11 @@
&nbsp;
= link_to user_path(@user, :atom, { private_token: current_user.private_token }), class: 'btn btn-gray' do
= icon('rss')
- if current_user.admin?
&nbsp;
= link_to [:admin, @user], class: 'btn btn-gray', title: 'View user in admin area',
data: {toggle: 'tooltip', placement: 'bottom', container: 'body'} do
= icon('users')
.avatar-holder
= link_to avatar_icon(@user, 400), target: '_blank' do
......
......@@ -87,6 +87,7 @@ module Gitlab
config.assets.precompile << "graphs/application.js"
config.assets.precompile << "users/application.js"
config.assets.precompile << "network/application.js"
config.assets.precompile << "profile/application.js"
config.assets.precompile << "lib/utils/*.js"
config.assets.precompile << "lib/*.js"
......
class AddUserDefaultExternalToApplicationSettings < ActiveRecord::Migration
include Gitlab::Database::MigrationHelpers
disable_ddl_transaction!
def up
add_column_with_default(:application_settings, :user_default_external, :boolean,
default: false, allow_null: false)
end
def down
remove_column(:application_settings, :user_default_external)
end
end
......@@ -4,12 +4,12 @@ class RemoveDuplicatedKeys < ActiveRecord::Migration
select_all("SELECT fingerprint FROM #{quote_table_name(:keys)} GROUP BY fingerprint HAVING COUNT(*) > 1").each do |row|
fingerprint = connection.quote(row['fingerprint'])
execute(%Q{
DELETE FROM keys
DELETE FROM #{quote_table_name(:keys)}
WHERE fingerprint = #{fingerprint}
AND id != (
SELECT id FROM (
SELECT max(id) AS id
FROM keys
FROM #{quote_table_name(:keys)}
WHERE fingerprint = #{fingerprint}
) max_ids
)
......
......@@ -11,7 +11,7 @@ class FixNoValidatableImportUrl < ActiveRecord::Migration
attr_reader :results, :query
def initialize(batch_size: 100, query:)
def initialize(batch_size: 1000, query:)
@offset = 0
@batch_size = batch_size
@query = query
......@@ -58,22 +58,38 @@ class FixNoValidatableImportUrl < ActiveRecord::Migration
return
end
say('Nullifying empty import URLs')
nullify_empty_urls
say('Cleaning up invalid import URLs... This may take a few minutes if we have a large number of imported projects.')
invalid_import_url_project_ids.each { |project_id| cleanup_import_url(project_id) }
process_invalid_import_urls
end
def invalid_import_url_project_ids
ids = []
def process_invalid_import_urls
batches = SqlBatches.new(query: "SELECT id, import_url FROM projects WHERE import_url IS NOT NULL")
while batches.next?
project_ids = []
batches.results.each do |result|
ids << result['id'] unless valid_url?(result['import_url'])
project_ids << result['id'] unless valid_url?(result['import_url'])
end
process_batch(project_ids)
end
ids
end
def process_batch(project_ids)
Thread.new do
begin
project_ids.each { |project_id| cleanup_import_url(project_id) }
ensure
ActiveRecord::Base.connection.close
end
end.join
end
def valid_url?(url)
......@@ -83,4 +99,8 @@ class FixNoValidatableImportUrl < ActiveRecord::Migration
def cleanup_import_url(project_id)
execute("UPDATE projects SET import_url = NULL WHERE id = #{project_id}")
end
def nullify_empty_urls
execute("UPDATE projects SET import_url = NULL WHERE import_url = ''")
end
end
......@@ -87,6 +87,7 @@ ActiveRecord::Schema.define(version: 20160705163108) do
t.string "health_check_access_token"
t.boolean "send_user_confirmation_email", default: false
t.integer "container_registry_token_expire_delay", default: 5
t.boolean "user_default_external", default: false, null: false
t.text "after_sign_up_text"
t.boolean "elasticsearch_indexing", default: false, null: false
t.boolean "elasticsearch_search", default: false, null: false
......
......@@ -41,46 +41,49 @@ Parameters:
```json
[
{
"id": 4,
"description": null,
"id": 9,
"description": "foo",
"default_branch": "master",
"tag_list": [],
"public": false,
"visibility_level": 0,
"ssh_url_to_repo": "git@example.com:diaspora/diaspora-client.git",
"http_url_to_repo": "http://example.com/diaspora/diaspora-client.git",
"web_url": "http://example.com/diaspora/diaspora-client",
"tag_list": [
"example",
"disapora client"
],
"owner": {
"id": 3,
"name": "Diaspora",
"created_at": "2013-09-30T13: 46: 02Z"
},
"name": "Diaspora Client",
"name_with_namespace": "Diaspora / Diaspora Client",
"path": "diaspora-client",
"path_with_namespace": "diaspora/diaspora-client",
"archived": false,
"visibility_level": 10,
"ssh_url_to_repo": "git@gitlab.example.com/html5-boilerplate.git",
"http_url_to_repo": "http://gitlab.example.com/h5bp/html5-boilerplate.git",
"web_url": "http://gitlab.example.com/h5bp/html5-boilerplate",
"name": "Html5 Boilerplate",
"name_with_namespace": "Experimental / Html5 Boilerplate",
"path": "html5-boilerplate",
"path_with_namespace": "h5bp/html5-boilerplate",
"issues_enabled": true,
"merge_requests_enabled": true,
"builds_enabled": true,
"wiki_enabled": true,
"snippets_enabled": false,
"created_at": "2013-09-30T13: 46: 02Z",
"last_activity_at": "2013-09-30T13: 46: 02Z",
"creator_id": 3,
"builds_enabled": true,
"snippets_enabled": true,
"created_at": "2016-04-05T21:40:50.169Z",
"last_activity_at": "2016-04-06T16:52:08.432Z",
"shared_runners_enabled": true,
"creator_id": 1,
"namespace": {
"created_at": "2013-09-30T13: 46: 02Z",
"description": "",
"id": 3,
"name": "Diaspora",
"owner_id": 1,
"path": "diaspora",
"updated_at": "2013-09-30T13: 46: 02Z"
"id": 5,
"name": "Experimental",
"path": "h5bp",
"owner_id": null,
"created_at": "2016-04-05T21:40:49.152Z",
"updated_at": "2016-04-07T08:07:48.466Z",
"description": "foo",
"avatar": {
"url": null
},
"share_with_group_lock": false,
"visibility_level": 10
},
"archived": false,
"avatar_url": "http://example.com/uploads/project/avatar/4/uploads/avatar.png"
"avatar_url": null,
"star_count": 1,
"forks_count": 0,
"open_issues_count": 3,
"public_builds": true,
"shared_with_groups": []
}
]
```
......@@ -95,7 +98,180 @@ GET /groups/:id
Parameters:
- `id` (required) - The ID or path of a group
| Attribute | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `id` | integer/string | yes | The ID or path of a group |
```bash
curl -H "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v3/groups/4
```
Example response:
```json
{
"id": 4,
"name": "Twitter",
"path": "twitter",
"description": "Aliquid qui quis dignissimos distinctio ut commodi voluptas est.",
"visibility_level": 20,
"avatar_url": null,
"web_url": "https://gitlab.example.com/groups/twitter",
"projects": [
{
"id": 7,
"description": "Voluptas veniam qui et beatae voluptas doloremque explicabo facilis.",
"default_branch": "master",
"tag_list": [],
"public": true,
"archived": false,
"visibility_level": 20,
"ssh_url_to_repo": "git@gitlab.example.com:twitter/typeahead-js.git",
"http_url_to_repo": "https://gitlab.example.com/twitter/typeahead-js.git",
"web_url": "https://gitlab.example.com/twitter/typeahead-js",
"name": "Typeahead.Js",
"name_with_namespace": "Twitter / Typeahead.Js",
"path": "typeahead-js",
"path_with_namespace": "twitter/typeahead-js",
"issues_enabled": true,
"merge_requests_enabled": true,
"wiki_enabled": true,
"builds_enabled": true,
"snippets_enabled": false,
"container_registry_enabled": true,
"created_at": "2016-06-17T07:47:25.578Z",
"last_activity_at": "2016-06-17T07:47:25.881Z",
"shared_runners_enabled": true,
"creator_id": 1,
"namespace": {
"id": 4,
"name": "Twitter",
"path": "twitter",
"owner_id": null,
"created_at": "2016-06-17T07:47:24.216Z",
"updated_at": "2016-06-17T07:47:24.216Z",
"description": "Aliquid qui quis dignissimos distinctio ut commodi voluptas est.",
"avatar": {
"url": null
},
"share_with_group_lock": false,
"visibility_level": 20
},
"avatar_url": null,
"star_count": 0,
"forks_count": 0,
"open_issues_count": 3,
"public_builds": true,
"shared_with_groups": []
},
{
"id": 6,
"description": "Aspernatur omnis repudiandae qui voluptatibus eaque.",
"default_branch": "master",
"tag_list": [],
"public": false,
"archived": false,
"visibility_level": 10,
"ssh_url_to_repo": "git@gitlab.example.com:twitter/flight.git",
"http_url_to_repo": "https://gitlab.example.com/twitter/flight.git",
"web_url": "https://gitlab.example.com/twitter/flight",
"name": "Flight",
"name_with_namespace": "Twitter / Flight",
"path": "flight",
"path_with_namespace": "twitter/flight",
"issues_enabled": true,
"merge_requests_enabled": true,
"wiki_enabled": true,
"builds_enabled": true,
"snippets_enabled": false,
"container_registry_enabled": true,
"created_at": "2016-06-17T07:47:24.661Z",
"last_activity_at": "2016-06-17T07:47:24.838Z",
"shared_runners_enabled": true,
"creator_id": 1,
"namespace": {
"id": 4,
"name": "Twitter",
"path": "twitter",
"owner_id": null,
"created_at": "2016-06-17T07:47:24.216Z",
"updated_at": "2016-06-17T07:47:24.216Z",
"description": "Aliquid qui quis dignissimos distinctio ut commodi voluptas est.",
"avatar": {
"url": null
},
"share_with_group_lock": false,
"visibility_level": 20
},
"avatar_url": null,
"star_count": 0,
"forks_count": 0,
"open_issues_count": 8,
"public_builds": true,
"shared_with_groups": []
}
],
"shared_projects": [
{
"id": 8,
"description": "Velit eveniet provident fugiat saepe eligendi autem.",
"default_branch": "master",
"tag_list": [],
"public": false,
"archived": false,
"visibility_level": 0,
"ssh_url_to_repo": "git@gitlab.example.com:h5bp/html5-boilerplate.git",
"http_url_to_repo": "https://gitlab.example.com/h5bp/html5-boilerplate.git",
"web_url": "https://gitlab.example.com/h5bp/html5-boilerplate",
"name": "Html5 Boilerplate",
"name_with_namespace": "H5bp / Html5 Boilerplate",
"path": "html5-boilerplate",
"path_with_namespace": "h5bp/html5-boilerplate",
"issues_enabled": true,
"merge_requests_enabled": true,
"wiki_enabled": true,
"builds_enabled": true,
"snippets_enabled": false,
"container_registry_enabled": true,
"created_at": "2016-06-17T07:47:27.089Z",
"last_activity_at": "2016-06-17T07:47:27.310Z",
"shared_runners_enabled": true,
"creator_id": 1,
"namespace": {
"id": 5,
"name": "H5bp",
"path": "h5bp",
"owner_id": null,
"created_at": "2016-06-17T07:47:26.621Z",
"updated_at": "2016-06-17T07:47:26.621Z",
"description": "Id consequatur rem vel qui doloremque saepe.",
"avatar": {
"url": null
},
"share_with_group_lock": false,
"visibility_level": 20
},
"avatar_url": null,
"star_count": 0,
"forks_count": 0,
"open_issues_count": 4,
"public_builds": true,
"shared_with_groups": [
{
"group_id": 4,
"group_name": "Twitter",
"group_access_level": 30
},
{
"group_id": 3,
"group_name": "Gitlab Org",
"group_access_level": 10
}
]
}
]
}
```
## New group
......@@ -218,7 +394,8 @@ Example response:
"star_count": 1,
"forks_count": 0,
"open_issues_count": 3,
"public_builds": true
"public_builds": true,
"shared_with_groups": []
}
]
}
......
......@@ -82,7 +82,8 @@ Parameters:
"forks_count": 0,
"star_count": 0,
"runners_token": "b8547b1dc37721d05889db52fa2f02",
"public_builds": true
"public_builds": true,
"shared_with_groups": []
},
{
"id": 6,
......@@ -140,7 +141,8 @@ Parameters:
"forks_count": 0,
"star_count": 0,
"runners_token": "b8547b1dc37721d05889db52fa2f02",
"public_builds": true
"public_builds": true,
"shared_with_groups": []
}
]
```
......@@ -262,7 +264,20 @@ Parameters:
"shared_runners_enabled": true,
"forks_count": 0,
"star_count": 0,
"runners_token": "b8bc4a7a29eb76ea83cf79e4908c2b"
"runners_token": "b8bc4a7a29eb76ea83cf79e4908c2b",
"public_builds": true,
"shared_with_groups": [
{
"group_id": 4,
"group_name": "Twitter",
"group_access_level": 30
},
{
"group_id": 3,
"group_name": "Gitlab Org",
"group_access_level": 10
}
]
}
```
......@@ -425,6 +440,7 @@ Parameters:
- `wiki_enabled` (optional)
- `snippets_enabled` (optional)
- `container_registry_enabled` (optional)
- `shared_runners_enabled` (optional)
- `public` (optional) - if `true` same as setting visibility_level = 20
- `visibility_level` (optional)
- `import_url` (optional)
......@@ -449,6 +465,7 @@ Parameters:
- `wiki_enabled` (optional)
- `snippets_enabled` (optional)
- `container_registry_enabled` (optional)
- `shared_runners_enabled` (optional)
- `public` (optional) - if `true` same as setting visibility_level = 20
- `visibility_level` (optional)
- `import_url` (optional)
......@@ -475,6 +492,7 @@ Parameters:
- `wiki_enabled` (optional)
- `snippets_enabled` (optional)
- `container_registry_enabled` (optional)
- `shared_runners_enabled` (optional)
- `public` (optional) - if `true` same as setting visibility_level = 20
- `visibility_level` (optional)
- `public_builds` (optional)
......@@ -553,7 +571,9 @@ Example response:
"avatar_url": "http://example.com/uploads/project/avatar/3/uploads/avatar.png",
"shared_runners_enabled": true,
"forks_count": 0,
"star_count": 1
"star_count": 1,
"public_builds": true,
"shared_with_groups": []
}
```
......@@ -616,7 +636,9 @@ Example response:
"avatar_url": "http://example.com/uploads/project/avatar/3/uploads/avatar.png",
"shared_runners_enabled": true,
"forks_count": 0,
"star_count": 0
"star_count": 0,
"public_builds": true,
"shared_with_groups": []
}
```
......@@ -699,7 +721,9 @@ Example response:
"shared_runners_enabled": true,
"forks_count": 0,
"star_count": 0,
"runners_token": "b8bc4a7a29eb76ea83cf79e4908c2b"
"runners_token": "b8bc4a7a29eb76ea83cf79e4908c2b",
"public_builds": true,
"shared_with_groups": []
}
```
......@@ -713,7 +737,7 @@ have the proper access rights, code 403 is returned. Status 404 is returned if t
doesn't exist, or is hidden to the user.
```
POST /projects/:id/archive
POST /projects/:id/unarchive
```
| Attribute | Type | Required | Description |
......@@ -782,7 +806,9 @@ Example response:
"shared_runners_enabled": true,
"forks_count": 0,
"star_count": 0,
"runners_token": "b8bc4a7a29eb76ea83cf79e4908c2b"
"runners_token": "b8bc4a7a29eb76ea83cf79e4908c2b",
"public_builds": true,
"shared_with_groups": []
}
```
......
......@@ -811,7 +811,7 @@ deploy:
It's possible to overwrite globally defined `before_script` and `after_script`:
```yaml
before_script
before_script:
- global before script
job:
......
......@@ -52,5 +52,6 @@ information from database or file system
* Use red button for destructive actions (not revertable). For example removing issue.
* Use green or blue button for primary action. Primary button should be only one.
Do not use both green and blue button in one form.
* For all other cases use default white button
* For all other cases use default white button.
* Text button should have only first word capitalized. So should be "Create issue" instead of "Create Issue"
......@@ -19,7 +19,7 @@ GitHub will generate an application ID and secret key for you to use.
- Application name: This can be anything. Consider something like "\<Organization\>'s GitLab" or "\<Your Name\>'s GitLab" or something else descriptive.
- Homepage URL: The URL to your GitLab installation. 'https://gitlab.company.com'
- Application description: Fill this in if you wish.
- Default authorization callback URL is '${YOUR_DOMAIN}/import/github/callback'
- Authorization callback URL is 'http(s)://${YOUR_DOMAIN}'
1. Select "Register application".
1. You should now see a Client ID and Client Secret near the top right of the page (see screenshot).
......
......@@ -102,3 +102,6 @@ An administrator can flag a user as external [through the API](../api/users.md)
or by checking the checkbox on the admin panel. As an administrator, navigate
to **Admin > Users** to create a new user or edit an existing one. There, you
will find the option to flag the user as external.
By default new users are not set as external users. This behavior can be changed
by an administrator under **Admin > Application Settings**.
\ No newline at end of file
......@@ -63,6 +63,14 @@ module API
expose :path, :path_with_namespace
end
class SharedGroup < Grape::Entity
expose :group_id
expose :group_name do |group_link, options|
group_link.group.name
end
expose :group_access, as: :group_access_level
end
class Project < Grape::Entity
expose :id, :description, :default_branch, :tag_list
expose :public?, as: :public
......@@ -82,6 +90,9 @@ module API
expose :open_issues_count, if: lambda { |project, options| project.issues_enabled? && project.default_issues_tracker? }
expose :runners_token, if: lambda { |_project, options| options[:user_can_admin_project] }
expose :public_builds
expose :shared_with_groups do |project, options|
SharedGroup.represent(project.project_group_links.all, options)
end
end
class ProjectMember < UserBasic
......@@ -108,6 +119,7 @@ module API
class GroupDetail < Group
expose :projects, using: Entities::Project
expose :shared_projects, using: Entities::Project
end
class GroupMember < UserBasic
......
......@@ -51,7 +51,8 @@ module Gitlab
elasticsearch_search: false,
elasticsearch_indexing: false,
elasticsearch_host: ENV['ELASTIC_HOST'] || 'localhost',
elasticsearch_port: ENV['ELASTIC_PORT'] || '9200'
elasticsearch_port: ENV['ELASTIC_PORT'] || '9200',
user_default_external: false
)
end
......
......@@ -18,7 +18,7 @@ module Gitlab
end
def commit_per_day
@commit_per_day ||= (@commits.size.to_f / @duration).round(1)
@commit_per_day ||= @commits.size / (@duration + 1)
end
def collect_data
......
......@@ -143,18 +143,14 @@ module Rouge
'</span>'
end
end
lines.join("\n")
else
if @linenos == 'inline'
lines = lines.each_with_index.map do |line, index|
number = index + @linenostart
"<span class=\"linenos\">#{number}</span>#{line}"
end
lines.join("\n")
else
lines.join("\n")
elsif @linenos == 'inline'
lines = lines.each_with_index.map do |line, index|
number = index + @linenostart
"<span class=\"linenos\">#{number}</span>#{line}"
end
end
lines.join("\n")
end
def span(tok, val)
......
require 'spec_helper'
describe "Admin::AbuseReports", feature: true, js: true do
let(:user) { create(:user) }
context 'as an admin' do
describe 'if a user has been reported for abuse' do
before do
create(:abuse_report, user: user)
login_as :admin
end
describe 'in the abuse report view' do
it "should present a link to the user's profile" do
visit admin_abuse_reports_path
expect(page).to have_link user.name, href: user_path(user)
end
end
describe 'in the profile page of the user' do
it 'should show a link to the admin view of the user' do
visit user_path(user)
expect(page).to have_link '', href: admin_user_path(user)
end
end
end
end
end
require 'spec_helper'
describe Gitlab::Graphs::Commits, lib: true do
let!(:project) { create(:project, :public, :empty_repo) }
let!(:commit1) { create(:commit, git_commit: RepoHelpers.sample_commit, project: project, committed_date: Time.now) }
let!(:commit1_yesterday) { create(:commit, git_commit: RepoHelpers.sample_commit, project: project, committed_date: 1.day.ago)}
let!(:commit2) { create(:commit, git_commit: RepoHelpers.another_sample_commit, project: project, committed_date: Time.now) }
describe '#commit_per_day' do
context 'when range is only commits from today' do
subject { described_class.new([commit2, commit1]).commit_per_day }
it { is_expected.to eq 2 }
end
end
context 'when range is only commits from today' do
subject { described_class.new([commit2, commit1]) }
describe '#commit_per_day' do
it { expect(subject.commit_per_day).to eq 2 }
end
describe '#duration' do
it { expect(subject.duration).to eq 0 }
end
end
context 'with commits from yesterday and today' do
subject { described_class.new([commit2, commit1_yesterday]) }
describe '#commit_per_day' do
it { expect(subject.commit_per_day).to eq 1 }
end
describe '#duration' do
it { expect(subject.duration).to eq 1 }
end
end
end
......@@ -460,6 +460,7 @@ describe User, models: true do
it { expect(user.can_create_group?).to be_truthy }
it { expect(user.can_create_project?).to be_truthy }
it { expect(user.first_name).to eq('John') }
it { expect(user.external).to be_falsey }
end
describe 'with defaults' do
......@@ -482,6 +483,26 @@ describe User, models: true do
expect(user.theme_id).to eq(1)
end
end
context 'when current_application_settings.user_default_external is true' do
before do
stub_application_setting(user_default_external: true)
end
it "creates external user by default" do
user = build(:user)
expect(user.external).to be_truthy
end
describe 'with default overrides' do
it "creates a non-external user" do
user = build(:user, external: false)
expect(user.external).to be_falsey
end
end
end
end
describe '.find_by_any_email' do
......
......@@ -59,10 +59,25 @@ describe API::API, api: true do
describe "GET /groups/:id" do
context "when authenticated as user" do
it "should return one of user1's groups" do
it "returns one of user1's groups" do
project = create(:project, namespace: group2, path: 'Foo')
create(:project_group_link, project: project, group: group1)
get api("/groups/#{group1.id}", user1)
expect(response).to have_http_status(200)
json_response['name'] == group1.name
expect(json_response['id']).to eq(group1.id)
expect(json_response['name']).to eq(group1.name)
expect(json_response['path']).to eq(group1.path)
expect(json_response['description']).to eq(group1.description)
expect(json_response['visibility_level']).to eq(group1.visibility_level)
expect(json_response['avatar_url']).to eq(group1.avatar_url)
expect(json_response['web_url']).to eq(group1.web_url)
expect(json_response['projects']).to be_an Array
expect(json_response['projects'].length).to eq(2)
expect(json_response['shared_projects']).to be_an Array
expect(json_response['shared_projects'].length).to eq(1)
expect(json_response['shared_projects'][0]['id']).to eq(project.id)
end
it "should not return a non existing group" do
......
......@@ -392,11 +392,47 @@ describe API::API, api: true do
before { project }
before { project_member }
it 'should return a project by id' do
it 'returns a project by id' do
group = create(:group)
link = create(:project_group_link, project: project, group: group)
get api("/projects/#{project.id}", user)
expect(response).to have_http_status(200)
expect(json_response['id']).to eq(project.id)
expect(json_response['description']).to eq(project.description)
expect(json_response['default_branch']).to eq(project.default_branch)
expect(json_response['tag_list']).to be_an Array
expect(json_response['public']).to be_falsey
expect(json_response['archived']).to be_falsey
expect(json_response['visibility_level']).to be_present
expect(json_response['ssh_url_to_repo']).to be_present
expect(json_response['http_url_to_repo']).to be_present
expect(json_response['web_url']).to be_present
expect(json_response['owner']).to be_a Hash
expect(json_response['owner']).to be_a Hash
expect(json_response['name']).to eq(project.name)
expect(json_response['owner']['username']).to eq(user.username)
expect(json_response['path']).to be_present
expect(json_response['issues_enabled']).to be_present
expect(json_response['merge_requests_enabled']).to be_present
expect(json_response['wiki_enabled']).to be_present
expect(json_response['builds_enabled']).to be_present
expect(json_response['snippets_enabled']).to be_present
expect(json_response['container_registry_enabled']).to be_present
expect(json_response['created_at']).to be_present
expect(json_response['last_activity_at']).to be_present
expect(json_response['shared_runners_enabled']).to be_present
expect(json_response['creator_id']).to be_present
expect(json_response['namespace']).to be_present
expect(json_response['avatar_url']).to be_nil
expect(json_response['star_count']).to be_present
expect(json_response['forks_count']).to be_present
expect(json_response['public_builds']).to be_present
expect(json_response['shared_with_groups']).to be_an Array
expect(json_response['shared_with_groups'].length).to eq(1)
expect(json_response['shared_with_groups'][0]['group_id']).to eq(group.id)
expect(json_response['shared_with_groups'][0]['group_name']).to eq(group.name)
expect(json_response['shared_with_groups'][0]['group_access_level']).to eq(link.group_access)
end
it 'should return a project by path name' do
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment