Commit b2e02061 authored by Rémy Coutable's avatar Rémy Coutable

Merge branch 'nt/ce-to-ee-thursday' into 'master'

CE upstream: Thursday

Closes omnibus-gitlab#1993, gitlab-ce#30642, gitlab-qa#41, and gitlab-ce#30636

See merge request !1647
parents af053ce5 b3f8a978
...@@ -335,8 +335,6 @@ migration paths: ...@@ -335,8 +335,6 @@ migration paths:
script: script:
- git fetch origin v8.14.10 - git fetch origin v8.14.10
- git checkout -f FETCH_HEAD - git checkout -f FETCH_HEAD
- cp config/resque.yml.example config/resque.yml
- sed -i 's/localhost/redis/g' config/resque.yml
- bundle install --without postgres production --jobs $(nproc) $FLAGS --retry=3 - bundle install --without postgres production --jobs $(nproc) $FLAGS --retry=3
- bundle exec rake db:drop db:create db:schema:load db:seed_fu - bundle exec rake db:drop db:create db:schema:load db:seed_fu
- git checkout $CI_COMMIT_SHA - git checkout $CI_COMMIT_SHA
......
...@@ -25,14 +25,20 @@ logs, and code as it's very hard to read otherwise.) ...@@ -25,14 +25,20 @@ logs, and code as it's very hard to read otherwise.)
#### Results of GitLab environment info #### Results of GitLab environment info
<details>
(For installations with omnibus-gitlab package run and paste the output of: (For installations with omnibus-gitlab package run and paste the output of:
`sudo gitlab-rake gitlab:env:info`) `sudo gitlab-rake gitlab:env:info`)
(For installations from source run and paste the output of: (For installations from source run and paste the output of:
`sudo -u git -H bundle exec rake gitlab:env:info RAILS_ENV=production`) `sudo -u git -H bundle exec rake gitlab:env:info RAILS_ENV=production`)
</details>
#### Results of GitLab application Check #### Results of GitLab application Check
<details>
(For installations with omnibus-gitlab package run and paste the output of: (For installations with omnibus-gitlab package run and paste the output of:
`sudo gitlab-rake gitlab:check SANITIZE=true`) `sudo gitlab-rake gitlab:check SANITIZE=true`)
...@@ -41,6 +47,8 @@ logs, and code as it's very hard to read otherwise.) ...@@ -41,6 +47,8 @@ logs, and code as it's very hard to read otherwise.)
(we will only investigate if the tests are passing) (we will only investigate if the tests are passing)
</details>
### Possible fixes ### Possible fixes
(If you can, link to the line of code that might be responsible for the problem) (If you can, link to the line of code that might be responsible for the problem)
...@@ -363,7 +363,7 @@ GEM ...@@ -363,7 +363,7 @@ GEM
grape-entity (0.6.0) grape-entity (0.6.0)
activesupport activesupport
multi_json (>= 1.3.2) multi_json (>= 1.3.2)
grpc (1.1.2) grpc (1.2.2)
google-protobuf (~> 3.1) google-protobuf (~> 3.1)
googleauth (~> 0.5.1) googleauth (~> 0.5.1)
gssapi (1.2.0) gssapi (1.2.0)
......
...@@ -101,6 +101,7 @@ $(() => { ...@@ -101,6 +101,7 @@ $(() => {
if (list.type === 'closed') { if (list.type === 'closed') {
list.position = Infinity; list.position = Infinity;
list.label = { description: 'Shows all closed issues. Moving an issue to this list closes it' };
} }
}); });
......
...@@ -50,7 +50,7 @@ window.gl.GfmAutoComplete = { ...@@ -50,7 +50,7 @@ window.gl.GfmAutoComplete = {
template: '<li>${title}</li>' template: '<li>${title}</li>'
}, },
Loading: { Loading: {
template: '<li style="pointer-events: none;"><i class="fa fa-refresh fa-spin"></i> Loading...</li>' template: '<li style="pointer-events: none;"><i class="fa fa-spinner fa-spin"></i> Loading...</li>'
}, },
DefaultOptions: { DefaultOptions: {
sorter: function(query, items, searchKey) { sorter: function(query, items, searchKey) {
......
...@@ -20,57 +20,60 @@ class Issue { ...@@ -20,57 +20,60 @@ class Issue {
}); });
Issue.initIssueBtnEventListeners(); Issue.initIssueBtnEventListeners();
} }
Issue.$btnNewBranch = $('#new-branch');
Issue.initMergeRequests(); Issue.initMergeRequests();
Issue.initRelatedBranches(); Issue.initRelatedBranches();
Issue.initCanCreateBranch(); Issue.initCanCreateBranch();
} }
static initIssueBtnEventListeners() { static initIssueBtnEventListeners() {
var issueFailMessage; const issueFailMessage = 'Unable to update this issue at this time.';
issueFailMessage = 'Unable to update this issue at this time.';
return $('a.btn-close, a.btn-reopen').on('click', function(e) { const closeButtons = $('a.btn-close');
var $this, isClose, shouldSubmit, url; const isClosedBadge = $('div.status-box-closed');
const isOpenBadge = $('div.status-box-open');
const projectIssuesCounter = $('.issue_counter');
const reopenButtons = $('a.btn-reopen');
return closeButtons.add(reopenButtons).on('click', function(e) {
var $this, shouldSubmit, url;
e.preventDefault(); e.preventDefault();
e.stopImmediatePropagation(); e.stopImmediatePropagation();
$this = $(this); $this = $(this);
isClose = $this.hasClass('btn-close');
shouldSubmit = $this.hasClass('btn-comment'); shouldSubmit = $this.hasClass('btn-comment');
if (shouldSubmit) { if (shouldSubmit) {
Issue.submitNoteForm($this.closest('form')); Issue.submitNoteForm($this.closest('form'));
} }
$this.prop('disabled', true); $this.prop('disabled', true);
Issue.setNewBranchButtonState(true, null);
url = $this.attr('href'); url = $this.attr('href');
return $.ajax({ return $.ajax({
type: 'PUT', type: 'PUT',
url: url, url: url
error: function(jqXHR, textStatus, errorThrown) { }).fail(function(jqXHR, textStatus, errorThrown) {
var issueStatus; new Flash(issueFailMessage);
issueStatus = isClose ? 'close' : 'open'; Issue.initCanCreateBranch();
return new Flash(issueFailMessage, 'alert'); }).done(function(data, textStatus, jqXHR) {
}, if ('id' in data) {
success: function(data, textStatus, jqXHR) { $(document).trigger('issuable:change');
if ('id' in data) {
$(document).trigger('issuable:change'); const isClosed = $this.hasClass('btn-close');
let total = Number($('.issue_counter').text().replace(/[^\d]/, '')); closeButtons.toggleClass('hidden', isClosed);
if (isClose) { reopenButtons.toggleClass('hidden', !isClosed);
$('a.btn-close').addClass('hidden'); isClosedBadge.toggleClass('hidden', !isClosed);
$('a.btn-reopen').removeClass('hidden'); isOpenBadge.toggleClass('hidden', isClosed);
$('div.status-box-closed').removeClass('hidden');
$('div.status-box-open').addClass('hidden'); let numProjectIssues = Number(projectIssuesCounter.text().replace(/[^\d]/, ''));
total -= 1; numProjectIssues = isClosed ? numProjectIssues - 1 : numProjectIssues + 1;
} else { projectIssuesCounter.text(gl.text.addDelimiter(numProjectIssues));
$('a.btn-reopen').addClass('hidden'); } else {
$('a.btn-close').removeClass('hidden'); new Flash(issueFailMessage);
$('div.status-box-closed').addClass('hidden');
$('div.status-box-open').removeClass('hidden');
total += 1;
}
$('.issue_counter').text(gl.text.addDelimiter(total));
} else {
new Flash(issueFailMessage, 'alert');
}
return $this.prop('disabled', false);
} }
$this.prop('disabled', false);
Issue.initCanCreateBranch();
}); });
}); });
} }
...@@ -86,9 +89,9 @@ class Issue { ...@@ -86,9 +89,9 @@ class Issue {
static initMergeRequests() { static initMergeRequests() {
var $container; var $container;
$container = $('#merge-requests'); $container = $('#merge-requests');
return $.getJSON($container.data('url')).error(function() { return $.getJSON($container.data('url')).fail(function() {
return new Flash('Failed to load referenced merge requests', 'alert'); return new Flash('Failed to load referenced merge requests');
}).success(function(data) { }).done(function(data) {
if ('html' in data) { if ('html' in data) {
return $container.html(data.html); return $container.html(data.html);
} }
...@@ -98,9 +101,9 @@ class Issue { ...@@ -98,9 +101,9 @@ class Issue {
static initRelatedBranches() { static initRelatedBranches() {
var $container; var $container;
$container = $('#related-branches'); $container = $('#related-branches');
return $.getJSON($container.data('url')).error(function() { return $.getJSON($container.data('url')).fail(function() {
return new Flash('Failed to load related branches', 'alert'); return new Flash('Failed to load related branches');
}).success(function(data) { }).done(function(data) {
if ('html' in data) { if ('html' in data) {
return $container.html(data.html); return $container.html(data.html);
} }
...@@ -108,24 +111,27 @@ class Issue { ...@@ -108,24 +111,27 @@ class Issue {
} }
static initCanCreateBranch() { static initCanCreateBranch() {
var $container;
$container = $('#new-branch');
// If the user doesn't have the required permissions the container isn't // If the user doesn't have the required permissions the container isn't
// rendered at all. // rendered at all.
if ($container.length === 0) { if (Issue.$btnNewBranch.length === 0) {
return; return;
} }
return $.getJSON($container.data('path')).error(function() { return $.getJSON(Issue.$btnNewBranch.data('path')).fail(function() {
$container.find('.unavailable').show(); Issue.setNewBranchButtonState(false, false);
return new Flash('Failed to check if a new branch can be created.', 'alert'); new Flash('Failed to check if a new branch can be created.');
}).success(function(data) { }).done(function(data) {
if (data.can_create_branch) { Issue.setNewBranchButtonState(false, data.can_create_branch);
$container.find('.available').show();
} else {
return $container.find('.unavailable').show();
}
}); });
} }
static setNewBranchButtonState(isPending, canCreate) {
if (Issue.$btnNewBranch.length === 0) {
return;
}
Issue.$btnNewBranch.find('.available').toggle(!isPending && canCreate);
Issue.$btnNewBranch.find('.unavailable').toggle(!isPending && !canCreate);
}
} }
export default Issue; export default Issue;
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
direction: rtl; direction: rtl;
@media (min-width: $screen-sm-min) and (max-width: $screen-md-max) { @media (min-width: $screen-sm-min) and (max-width: $screen-md-max) {
overflow-x: scroll; overflow-x: auto;
} }
} }
......
...@@ -82,7 +82,7 @@ ...@@ -82,7 +82,7 @@
.input-token:last-child { .input-token:last-child {
flex: 1; flex: 1;
-webkit-flex: 1; -webkit-flex: 1;
max-width: initial; max-width: inherit;
} }
} }
...@@ -246,17 +246,17 @@ ...@@ -246,17 +246,17 @@
} }
} }
.filtered-search-history-dropdown-toggle-button { .filtered-search-history-dropdown-wrapper {
position: static;
display: flex; display: flex;
align-items: center; flex-direction: column;
}
.filtered-search-history-dropdown-toggle-button {
flex: 1;
width: auto; width: auto;
height: 100%; padding-right: 10px;
padding-top: 0;
padding-left: 0.75em;
padding-bottom: 0;
padding-right: 0.5em;
background-color: transparent;
border-radius: 0; border-radius: 0;
border-top: 0; border-top: 0;
border-left: 0; border-left: 0;
...@@ -264,6 +264,7 @@ ...@@ -264,6 +264,7 @@
border-right: 1px solid $border-color; border-right: 1px solid $border-color;
color: $gl-text-color-secondary; color: $gl-text-color-secondary;
line-height: 1;
transition: color 0.1s linear; transition: color 0.1s linear;
...@@ -275,24 +276,21 @@ ...@@ -275,24 +276,21 @@
} }
.dropdown-toggle-text { .dropdown-toggle-text {
display: inline-block;
color: inherit; color: inherit;
.fa { .fa {
vertical-align: middle;
color: inherit; color: inherit;
} }
} }
.fa { .fa {
position: initial; position: static;
} }
} }
.filtered-search-history-dropdown-wrapper {
position: initial;
flex-shrink: 0;
}
.filtered-search-history-dropdown { .filtered-search-history-dropdown {
width: 40%; width: 40%;
......
...@@ -39,7 +39,7 @@ ...@@ -39,7 +39,7 @@
overflow-y: hidden; overflow-y: hidden;
font-size: 12px; font-size: 12px;
.fa-refresh { .fa-spinner {
font-size: 24px; font-size: 24px;
margin-left: 20px; margin-left: 20px;
} }
...@@ -219,7 +219,7 @@ ...@@ -219,7 +219,7 @@
font-size: 12px; font-size: 12px;
position: relative; position: relative;
.fa-refresh { .fa-spinner {
font-size: 24px; font-size: 24px;
} }
...@@ -366,7 +366,7 @@ ...@@ -366,7 +366,7 @@
background-color: $row-hover; background-color: $row-hover;
} }
.fa-refresh { .fa-spinner {
font-size: 13px; font-size: 13px;
margin-left: 3px; margin-left: 3px;
} }
......
...@@ -523,7 +523,6 @@ ...@@ -523,7 +523,6 @@
} }
.content-block { .content-block {
border-top: 1px solid $border-color;
padding: $gl-padding-top $gl-padding; padding: $gl-padding-top $gl-padding;
} }
......
...@@ -18,12 +18,12 @@ ul.notes { ...@@ -18,12 +18,12 @@ ul.notes {
float: left; float: left;
svg { svg {
width: 18px; width: 16px;
height: 18px; height: 16px;
fill: $gray-darkest; fill: $gray-darkest;
position: absolute; position: absolute;
left: 30px; left: 0;
top: 15px; top: 16px;
} }
} }
...@@ -144,6 +144,10 @@ ul.notes { ...@@ -144,6 +144,10 @@ ul.notes {
padding: 0; padding: 0;
clear: both; clear: both;
@media (min-width: $screen-sm-min) {
margin-left: 65px;
}
&.timeline-entry::after { &.timeline-entry::after {
clear: none; clear: none;
} }
...@@ -172,6 +176,10 @@ ul.notes { ...@@ -172,6 +176,10 @@ ul.notes {
.timeline-content { .timeline-content {
padding: 14px 10px; padding: 14px 10px;
@media (min-width: $screen-sm-min) {
margin-left: 20px;
}
} }
.note-header { .note-header {
......
...@@ -10,7 +10,7 @@ class Projects::HooksController < Projects::ApplicationController ...@@ -10,7 +10,7 @@ class Projects::HooksController < Projects::ApplicationController
@hook = @project.hooks.new(hook_params) @hook = @project.hooks.new(hook_params)
@hook.save @hook.save
unless @hook.valid? unless @hook.valid?
@hooks = @project.hooks.select(&:persisted?) @hooks = @project.hooks.select(&:persisted?)
flash[:alert] = @hook.errors.full_messages.join.html_safe flash[:alert] = @hook.errors.full_messages.join.html_safe
end end
...@@ -49,7 +49,7 @@ class Projects::HooksController < Projects::ApplicationController ...@@ -49,7 +49,7 @@ class Projects::HooksController < Projects::ApplicationController
def hook_params def hook_params
params.require(:hook).permit( params.require(:hook).permit(
:build_events, :job_events,
:pipeline_events, :pipeline_events,
:enable_ssl_verification, :enable_ssl_verification,
:issues_events, :issues_events,
......
...@@ -41,7 +41,7 @@ class Projects::MergeRequestsController < Projects::ApplicationController ...@@ -41,7 +41,7 @@ class Projects::MergeRequestsController < Projects::ApplicationController
@collection_type = "MergeRequest" @collection_type = "MergeRequest"
@merge_requests = merge_requests_collection @merge_requests = merge_requests_collection
@merge_requests = @merge_requests.page(params[:page]) @merge_requests = @merge_requests.page(params[:page])
@merge_requests = @merge_requests.includes(merge_request_diff: :merge_request) @merge_requests = @merge_requests.preload(merge_request_diff: :merge_request)
@issuable_meta_data = issuable_meta_data(@merge_requests, @collection_type) @issuable_meta_data = issuable_meta_data(@merge_requests, @collection_type)
if @merge_requests.out_of_range? && @merge_requests.total_pages != 0 if @merge_requests.out_of_range? && @merge_requests.total_pages != 0
......
...@@ -363,7 +363,11 @@ class ProjectsController < Projects::ApplicationController ...@@ -363,7 +363,11 @@ class ProjectsController < Projects::ApplicationController
end end
def project_view_files? def project_view_files?
current_user && current_user.project_view == 'files' if current_user
current_user.project_view == 'files'
else
project_view_files_allowed?
end
end end
# Override extract_ref from ExtractsPath, which returns the branch and file path # Override extract_ref from ExtractsPath, which returns the branch and file path
...@@ -384,4 +388,8 @@ class ProjectsController < Projects::ApplicationController ...@@ -384,4 +388,8 @@ class ProjectsController < Projects::ApplicationController
@id = get_id @id = get_id
tree tree
end end
def project_view_files_allowed?
!project.empty_repo? && can?(current_user, :download_code, project)
end
end end
...@@ -3,7 +3,8 @@ module JavascriptHelper ...@@ -3,7 +3,8 @@ module JavascriptHelper
javascript_include_tag asset_path(js) javascript_include_tag asset_path(js)
end end
def page_specific_javascript_bundle_tag(js) # deprecated; use webpack_bundle_tag directly instead
javascript_include_tag(*webpack_asset_paths(js)) def page_specific_javascript_bundle_tag(bundle)
webpack_bundle_tag(bundle)
end end
end end
...@@ -63,6 +63,10 @@ module PreferencesHelper ...@@ -63,6 +63,10 @@ module PreferencesHelper
end end
def anonymous_project_view def anonymous_project_view
@project.empty_repo? || !can?(current_user, :download_code, @project) ? 'activity' : 'readme' if !@project.empty_repo? && can?(current_user, :download_code, @project)
'files'
else
'activity'
end
end end
end end
require 'webpack/rails/manifest'
module WebpackHelper
def webpack_bundle_tag(bundle)
javascript_include_tag(*gitlab_webpack_asset_paths(bundle))
end
# override webpack-rails gem helper until changes can make it upstream
def gitlab_webpack_asset_paths(source, extension: nil)
return "" unless source.present?
paths = Webpack::Rails::Manifest.asset_paths(source)
if extension
paths = paths.select { |p| p.ends_with? ".#{extension}" }
end
# include full webpack-dev-server url for rspec tests running locally
if Rails.env.test? && Rails.configuration.webpack.dev_server.enabled
host = Rails.configuration.webpack.dev_server.host
port = Rails.configuration.webpack.dev_server.port
protocol = Rails.configuration.webpack.dev_server.https ? 'https' : 'http'
paths.map! do |p|
"#{protocol}://#{host}:#{port}#{p}"
end
end
paths
end
end
...@@ -7,7 +7,7 @@ module Ci ...@@ -7,7 +7,7 @@ module Ci
belongs_to :project belongs_to :project
belongs_to :owner, class_name: "User" belongs_to :owner, class_name: "User"
has_many :trigger_requests, dependent: :destroy has_many :trigger_requests
has_one :trigger_schedule, dependent: :destroy has_one :trigger_schedule, dependent: :destroy
validates :token, presence: true, uniqueness: true validates :token, presence: true, uniqueness: true
......
...@@ -2,9 +2,9 @@ ...@@ -2,9 +2,9 @@
module DiscussionOnDiff module DiscussionOnDiff
extend ActiveSupport::Concern extend ActiveSupport::Concern
included do NUMBER_OF_TRUNCATED_DIFF_LINES = 16
NUMBER_OF_TRUNCATED_DIFF_LINES = 16
included do
delegate :line_code, delegate :line_code,
:original_line_code, :original_line_code,
:diff_file, :diff_file,
......
...@@ -23,6 +23,10 @@ class ContainerRepository < ActiveRecord::Base ...@@ -23,6 +23,10 @@ class ContainerRepository < ActiveRecord::Base
@path ||= [project.full_path, name].select(&:present?).join('/') @path ||= [project.full_path, name].select(&:present?).join('/')
end end
def location
File.join(registry.path, path)
end
def tag(tag) def tag(tag)
ContainerRegistry::Tag.new(self, tag) ContainerRegistry::Tag.new(self, tag)
end end
......
...@@ -34,8 +34,6 @@ class Issue < ActiveRecord::Base ...@@ -34,8 +34,6 @@ class Issue < ActiveRecord::Base
validates :project, presence: true validates :project, presence: true
scope :cared, ->(user) { where(assignee_id: user) }
scope :open_for, ->(user) { opened.assigned_to(user) }
scope :in_projects, ->(project_ids) { where(project_id: project_ids) } scope :in_projects, ->(project_ids) { where(project_id: project_ids) }
scope :without_due_date, -> { where(due_date: nil) } scope :without_due_date, -> { where(due_date: nil) }
......
...@@ -21,6 +21,8 @@ class Label < ActiveRecord::Base ...@@ -21,6 +21,8 @@ class Label < ActiveRecord::Base
has_many :issues, through: :label_links, source: :target, source_type: 'Issue' has_many :issues, through: :label_links, source: :target, source_type: 'Issue'
has_many :merge_requests, through: :label_links, source: :target, source_type: 'MergeRequest' has_many :merge_requests, through: :label_links, source: :target, source_type: 'MergeRequest'
before_validation :strip_whitespace_from_title_and_color
validates :color, color: true, allow_blank: false validates :color, color: true, allow_blank: false
# Don't allow ',' for label titles # Don't allow ',' for label titles
...@@ -193,4 +195,8 @@ class Label < ActiveRecord::Base ...@@ -193,4 +195,8 @@ class Label < ActiveRecord::Base
def sanitize_title(value) def sanitize_title(value)
CGI.unescapeHTML(Sanitize.clean(value.to_s)) CGI.unescapeHTML(Sanitize.clean(value.to_s))
end end
def strip_whitespace_from_title_and_color
%w(color title).each { |attr| self[attr] = self[attr]&.strip }
end
end end
...@@ -110,7 +110,6 @@ class MergeRequest < ActiveRecord::Base ...@@ -110,7 +110,6 @@ class MergeRequest < ActiveRecord::Base
scope :by_source_or_target_branch, ->(branch_name) do scope :by_source_or_target_branch, ->(branch_name) do
where("source_branch = :branch OR target_branch = :branch", branch: branch_name) where("source_branch = :branch OR target_branch = :branch", branch: branch_name)
end end
scope :cared, ->(user) { where('assignee_id = :user OR author_id = :user', user: user.id) }
scope :by_milestone, ->(milestone) { where(milestone_id: milestone) } scope :by_milestone, ->(milestone) { where(milestone_id: milestone) }
scope :of_projects, ->(ids) { where(target_project_id: ids) } scope :of_projects, ->(ids) { where(target_project_id: ids) }
scope :from_project, ->(project) { where(source_project_id: project.id) } scope :from_project, ->(project) { where(source_project_id: project.id) }
......
...@@ -98,6 +98,7 @@ class Note < ActiveRecord::Base ...@@ -98,6 +98,7 @@ class Note < ActiveRecord::Base
before_validation :set_discussion_id, on: :create before_validation :set_discussion_id, on: :create
after_save :keep_around_commit, unless: :for_personal_snippet? after_save :keep_around_commit, unless: :for_personal_snippet?
after_save :expire_etag_cache after_save :expire_etag_cache
after_destroy :expire_etag_cache
class << self class << self
def model_name def model_name
......
...@@ -613,10 +613,6 @@ class User < ActiveRecord::Base ...@@ -613,10 +613,6 @@ class User < ActiveRecord::Base
name.split.first unless name.blank? name.split.first unless name.blank?
end end
def cared_merge_requests
MergeRequest.cared(self)
end
def projects_limit_left def projects_limit_left
projects_limit - personal_projects.count projects_limit - personal_projects.count
end end
......
...@@ -31,6 +31,7 @@ class GroupPolicy < BasePolicy ...@@ -31,6 +31,7 @@ class GroupPolicy < BasePolicy
can! :admin_namespace can! :admin_namespace
can! :admin_group_member can! :admin_group_member
can! :change_visibility_level can! :change_visibility_level
can! :create_subgroup if @user.can_create_group
end end
if globally_viewable && @subject.request_access_enabled && !member if globally_viewable && @subject.request_access_enabled && !member
......
...@@ -13,7 +13,7 @@ ...@@ -13,7 +13,7 @@
= button_to reset_health_check_token_admin_application_settings_path, = button_to reset_health_check_token_admin_application_settings_path,
method: :put, class: 'btn btn-default', method: :put, class: 'btn btn-default',
data: { confirm: 'Are you sure you want to reset the health check token?' } do data: { confirm: 'Are you sure you want to reset the health check token?' } do
= icon('refresh') = icon('spinner')
Reset health check access token Reset health check access token
%p.light %p.light
Health information can be retrieved as plain text, JSON, or XML using: Health information can be retrieved as plain text, JSON, or XML using:
......
...@@ -21,7 +21,7 @@ ...@@ -21,7 +21,7 @@
= button_to reset_runners_token_admin_application_settings_path, = button_to reset_runners_token_admin_application_settings_path,
method: :put, class: 'btn btn-default', method: :put, class: 'btn btn-default',
data: { confirm: 'Are you sure you want to reset registration token?' } do data: { confirm: 'Are you sure you want to reset registration token?' } do
= icon('refresh') = icon('spinner')
Reset runners registration token Reset runners registration token
.bs-callout .bs-callout
......
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
.nav-controls .nav-controls
= form_tag request.path, method: :get do |f| = form_tag request.path, method: :get do |f|
= search_field_tag :filter_groups, params[:filter_groups], placeholder: 'Filter by name', class: 'form-control', spellcheck: false = search_field_tag :filter_groups, params[:filter_groups], placeholder: 'Filter by name', class: 'form-control', spellcheck: false
- if can? current_user, :admin_group, @group - if can?(current_user, :create_subgroup, @group)
= link_to new_group_path(parent_id: @group.id), class: 'btn btn-new pull-right' do = link_to new_group_path(parent_id: @group.id), class: 'btn btn-new pull-right' do
New Subgroup New Subgroup
......
...@@ -252,7 +252,7 @@ ...@@ -252,7 +252,7 @@
= icon('chevron-down') = icon('chevron-down')
.dropdown-menu.dropdown-select.dropdown-menu-selectable .dropdown-menu.dropdown-select.dropdown-menu-selectable
.dropdown-title .dropdown-title
%span Dropdown Title %span Dropdown title
%button.dropdown-title-button.dropdown-menu-close{ aria: { label: "Close" } } %button.dropdown-title-button.dropdown-menu-close{ aria: { label: "Close" } }
= icon('times') = icon('times')
.dropdown-input .dropdown-input
...@@ -291,7 +291,7 @@ ...@@ -291,7 +291,7 @@
= icon('chevron-down') = icon('chevron-down')
.dropdown-menu.dropdown-select.dropdown-menu-selectable.is-loading .dropdown-menu.dropdown-select.dropdown-menu-selectable.is-loading
.dropdown-title .dropdown-title
%span Dropdown Title %span Dropdown title
%button.dropdown-title-button.dropdown-menu-close{ aria: { label: "Close" } } %button.dropdown-title-button.dropdown-menu-close{ aria: { label: "Close" } }
= icon('times') = icon('times')
.dropdown-input .dropdown-input
...@@ -335,7 +335,7 @@ ...@@ -335,7 +335,7 @@
= icon('chevron-down') = icon('chevron-down')
.dropdown-menu.dropdown-select.dropdown-menu-selectable.dropdown-menu-user .dropdown-menu.dropdown-select.dropdown-menu-selectable.dropdown-menu-user
.dropdown-title .dropdown-title
%span Dropdown Title %span Dropdown title
%button.dropdown-title-button.dropdown-menu-close{ aria: { label: "Close" } } %button.dropdown-title-button.dropdown-menu-close{ aria: { label: "Close" } }
= icon('times') = icon('times')
.dropdown-input .dropdown-input
...@@ -362,7 +362,7 @@ ...@@ -362,7 +362,7 @@
.dropdown-title .dropdown-title
%button.dropdown-title-button.dropdown-menu-back{ aria: { label: "Go back" } } %button.dropdown-title-button.dropdown-menu-back{ aria: { label: "Go back" } }
= icon('arrow-left') = icon('arrow-left')
%span Dropdown Title %span Dropdown title
%button.dropdown-title-button.dropdown-menu-close{ aria: { label: "Close" } } %button.dropdown-title-button.dropdown-menu-close{ aria: { label: "Close" } }
= icon('times') = icon('times')
.dropdown-input .dropdown-input
......
...@@ -28,9 +28,9 @@ ...@@ -28,9 +28,9 @@
= stylesheet_link_tag "application", media: "all" = stylesheet_link_tag "application", media: "all"
= stylesheet_link_tag "print", media: "print" = stylesheet_link_tag "print", media: "print"
= javascript_include_tag(*webpack_asset_paths("runtime")) = webpack_bundle_tag "runtime"
= javascript_include_tag(*webpack_asset_paths("common")) = webpack_bundle_tag "common"
= javascript_include_tag(*webpack_asset_paths("main")) = webpack_bundle_tag "main"
- if content_for?(:page_specific_javascripts) - if content_for?(:page_specific_javascripts)
= yield :page_specific_javascripts = yield :page_specific_javascripts
......
%ul %ul
= nav_link(path: ['dashboard#show', 'root#show', 'projects#trending', 'projects#starred', 'projects#index'], html_options: {class: 'home'}) do = nav_link(path: ['dashboard#show', 'root#show', 'projects#trending', 'projects#starred', 'projects#index'], html_options: {class: 'home'}) do
= link_to explore_root_path, title: 'Projects' do = link_to explore_root_path, title: 'Projects', class: 'dashboard-shortcuts-projects' do
.shortcut-mappings
.key
= icon('arrow-up', 'aria-label' => 'hidden')
P
%span %span
Projects Projects
= nav_link(controller: [:groups, 'groups/milestones', 'groups/group_members']) do = nav_link(controller: [:groups, 'groups/milestones', 'groups/group_members']) do
= link_to explore_groups_path, title: 'Groups' do = link_to explore_groups_path, title: 'Groups', class: 'dashboard-shortcuts-groups' do
.shortcut-mappings
.key
= icon('arrow-up', 'aria-label' => 'hidden')
G
%span %span
Groups Groups
= nav_link(controller: :snippets) do = nav_link(controller: :snippets) do
= link_to explore_snippets_path, title: 'Snippets' do = link_to explore_snippets_path, title: 'Snippets', class: 'dashboard-shortcuts-snippets' do
.shortcut-mappings
.key
= icon('arrow-up', 'aria-label' => 'hidden')
S
%span %span
Snippets Snippets
%li.divider
= nav_link(controller: :help) do = nav_link(controller: :help) do
= link_to help_path, title: 'Help' do = link_to help_path, title: 'Help' do
%span %span
......
...@@ -23,7 +23,7 @@ ...@@ -23,7 +23,7 @@
Registry Registry
- if project_nav_tab? :issues - if project_nav_tab? :issues
= nav_link(controller: [:issues, :labels, :milestones, :boards]) do = nav_link(controller: @project.default_issues_tracker? ? [:issues, :labels, :milestones, :boards] : :issues) do
= link_to namespace_project_issues_path(@project.namespace, @project), title: 'Issues', class: 'shortcuts-issues' do = link_to namespace_project_issues_path(@project.namespace, @project), title: 'Issues', class: 'shortcuts-issues' do
%span %span
Issues Issues
...@@ -31,7 +31,7 @@ ...@@ -31,7 +31,7 @@
%span.badge.count.issue_counter= number_with_delimiter(IssuesFinder.new(current_user, project_id: @project.id).execute.opened.count) %span.badge.count.issue_counter= number_with_delimiter(IssuesFinder.new(current_user, project_id: @project.id).execute.opened.count)
- if project_nav_tab? :merge_requests - if project_nav_tab? :merge_requests
= nav_link(controller: :merge_requests) do = nav_link(controller: @project.default_issues_tracker? ? :merge_requests : [:merge_requests, :labels, :milestones]) do
= link_to namespace_project_merge_requests_path(@project.namespace, @project), title: 'Merge Requests', class: 'shortcuts-merge_requests' do = link_to namespace_project_merge_requests_path(@project.namespace, @project), title: 'Merge Requests', class: 'shortcuts-merge_requests' do
%span %span
Merge Requests Merge Requests
......
...@@ -136,7 +136,7 @@ ...@@ -136,7 +136,7 @@
- else - else
= build.id = build.id
- if build.retried? - if build.retried?
%i.fa.fa-refresh.has-tooltip{ data: { container: 'body', placement: 'bottom' }, title: 'Job was retried' } %i.fa.fa-spinner.has-tooltip{ data: { container: 'body', placement: 'bottom' }, title: 'Job was retried' }
:javascript :javascript
new Sidebar(); new Sidebar();
...@@ -36,7 +36,7 @@ ...@@ -36,7 +36,7 @@
= icon('warning', class: 'text-warning has-tooltip', title: 'Job is stuck. Check runners.') = icon('warning', class: 'text-warning has-tooltip', title: 'Job is stuck. Check runners.')
- if retried - if retried
= icon('refresh', class: 'text-warning has-tooltip', title: 'Job was retried') = icon('spinner', class: 'text-warning has-tooltip', title: 'Job was retried')
.label-container .label-container
- if job.tags.any? - if job.tags.any?
......
- @no_container = true - @no_container = true
- page_title "Edit", @label.name, "Labels" - page_title "Edit", @label.name, "Labels"
= render "projects/issues/head" = render "shared/mr_head"
%div{ class: container_class } %div{ class: container_class }
%h3.page-title %h3.page-title
......
- @no_container = true - @no_container = true
- page_title "Labels" - page_title "Labels"
- hide_class = '' - hide_class = ''
= render "projects/issues/head" = render "shared/mr_head"
- if @labels.exists? || @prioritized_labels.exists? - if @labels.exists? || @prioritized_labels.exists?
%div{ class: container_class } %div{ class: container_class }
......
- @no_container = true - @no_container = true
- page_title "New Label" - page_title "New Label"
= render "projects/issues/head" = render "shared/mr_head"
%div{ class: container_class } %div{ class: container_class }
%h3.page-title %h3.page-title
......
= content_for :sub_nav do
.scrolling-tabs-container.sub-nav-scroll
= render 'shared/nav_scroll'
.nav-links.sub-nav.scrolling-tabs
%ul{ class: (container_class) }
= nav_link(controller: :merge_requests) do
= link_to namespace_project_merge_requests_path(@project.namespace, @project), title: 'Merge Requests' do
%span
List
- if project_nav_tab? :labels
= nav_link(controller: :labels) do
= link_to namespace_project_labels_path(@project.namespace, @project), title: 'Labels' do
%span
Labels
- if project_nav_tab? :milestones
= nav_link(controller: :milestones) do
= link_to namespace_project_milestones_path(@project.namespace, @project), title: 'Milestones' do
%span
Milestones
...@@ -2,6 +2,9 @@ ...@@ -2,6 +2,9 @@
- @bulk_edit = can?(current_user, :admin_merge_request, @project) - @bulk_edit = can?(current_user, :admin_merge_request, @project)
- page_title "Merge Requests" - page_title "Merge Requests"
- unless @project.default_issues_tracker?
= content_for :sub_nav do
= render "projects/merge_requests/head"
= render 'projects/last_push' = render 'projects/last_push'
- content_for :page_specific_javascripts do - content_for :page_specific_javascripts do
......
...@@ -18,7 +18,7 @@ ...@@ -18,7 +18,7 @@
Select merge moment Select merge moment
%ul.js-merge-dropdown.dropdown-menu.dropdown-menu-right{ role: 'menu' } %ul.js-merge-dropdown.dropdown-menu.dropdown-menu-right{ role: 'menu' }
%li %li
= link_to "#", class: "merge_when_pipeline_succeeds" do = link_to "#", class: "merge-when-pipeline-succeeds" do
= icon('check fw') = icon('check fw')
Merge when pipeline succeeds Merge when pipeline succeeds
%li %li
......
- @no_container = true - @no_container = true
- page_title "Edit", @milestone.title, "Milestones" - page_title "Edit", @milestone.title, "Milestones"
= render "projects/issues/head" = render "shared/mr_head"
%div{ class: container_class } %div{ class: container_class }
......
- @no_container = true - @no_container = true
- page_title 'Milestones' - page_title 'Milestones'
= render 'projects/issues/head' = render "shared/mr_head"
%div{ class: container_class } %div{ class: container_class }
.top-area .top-area
......
- @no_container = true - @no_container = true
- page_title "New Milestone" - page_title "New Milestone"
= render "projects/issues/head" = render "shared/mr_head"
%div{ class: container_class } %div{ class: container_class }
%h3.page-title %h3.page-title
......
- @no_container = true - @no_container = true
- page_title @milestone.title, "Milestones" - page_title @milestone.title, "Milestones"
- page_description @milestone.description - page_description @milestone.description
= render "projects/issues/head" = render "shared/mr_head"
%div{ class: container_class } %div{ class: container_class }
.detail-page-header.milestone-page-header .detail-page-header.milestone-page-header
......
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
= icon('chevron-down', 'aria-hidden': 'true') = icon('chevron-down', 'aria-hidden': 'true')
= escape_once(image.path) = escape_once(image.path)
= clipboard_button(clipboard_text: "docker pull #{image.path}") = clipboard_button(clipboard_text: "docker pull #{image.location}")
.controls.hidden-xs.pull-right .controls.hidden-xs.pull-right
= link_to namespace_project_container_registry_path(@project.namespace, @project, image), = link_to namespace_project_container_registry_path(@project.namespace, @project, image),
......
%tr.tag %tr.tag
%td %td
= escape_once(tag.name) = escape_once(tag.name)
= clipboard_button(text: "docker pull #{tag.path}") = clipboard_button(text: "docker pull #{tag.location}")
%td %td
- if tag.revision - if tag.revision
%span.has-tooltip{ title: "#{tag.revision}" } %span.has-tooltip{ title: "#{tag.revision}" }
......
- if @project.default_issues_tracker?
= render "projects/issues/head"
- else
= render "projects/merge_requests/head"
...@@ -3,7 +3,6 @@ class BuildCoverageWorker ...@@ -3,7 +3,6 @@ class BuildCoverageWorker
include BuildQueue include BuildQueue
def perform(build_id) def perform(build_id)
Ci::Build.find_by(id: build_id) Ci::Build.find_by(id: build_id)&.update_coverage
.try(:update_coverage)
end end
end end
---
title: Fix filtered search input width for IE
merge_request:
author:
---
title: Update all instances of the old loading icon
merge_request: 10490
author: Andrew Torres
---
title: Add webpack_bundle_tag helper to improve non-localhost GDK configurations
merge_request: 10604
author:
---
title: Separate CE params on Grape API
merge_request:
author:
---
title: Turns true value and false value database methods from instance to class methods
merge_request: 10583
author:
---
title: Fix issue's note cache expiration after delete
merge_request:
author: mhasbini
---
title: Show sub-nav under Merge Requests when issue tracker is non-default.
merge_request: 10658
author:
---
title: "[BB Importer] Save the error trace and the whole raw document to debug problems
easier"
merge_request:
author:
---
title: Add tooltip to header of Done board
merge_request: 10574
author: Andy Brown
---
title: Change project view default for existing users and anonymous visitors to files+readme
merge_request: 10498
author:
---
title: Fix missing capitalisation on views
merge_request:
author:
---
title: Fix bad query for PostgreSQL showing merge requests list
merge_request: 10666
author:
---
title: Remove heading and trailing spaces from label's color and title
merge_request: 10603
author: blackst0ne
---
title: Fix MR widget bug that merged a MR when Merge when pipeline succeeds was clicked
via the dropdown
merge_request: 10611
author:
---
title: "Make the `gitlab:gitlab_shell:check` task check that the repositories storage path are owned by the `root` group"
merge_request:
author:
---
title: Reset New branch button when issue state changes
merge_request: 5962
author: winniehell
---
title: Hide new subgroup button if user has no permission to create one
merge_request: 10627
author:
---
title: Fix preemptive scroll bar on user activity calendar.
merge_request: !10636
author:
---
title: "Bugfix: POST /projects/:id/hooks and PUT /projects/:id/hook/:hook_id no longer ignore the the job_events param in the V4 API"
merge_request: 10586
author:
---
title: Add foreign key for ci_trigger_requests on ci_triggers
merge_request: 10537
author:
...@@ -11,6 +11,7 @@ var WatchMissingNodeModulesPlugin = require('react-dev-utils/WatchMissingNodeMod ...@@ -11,6 +11,7 @@ var WatchMissingNodeModulesPlugin = require('react-dev-utils/WatchMissingNodeMod
var ROOT_PATH = path.resolve(__dirname, '..'); var ROOT_PATH = path.resolve(__dirname, '..');
var IS_PRODUCTION = process.env.NODE_ENV === 'production'; var IS_PRODUCTION = process.env.NODE_ENV === 'production';
var IS_DEV_SERVER = process.argv[1].indexOf('webpack-dev-server') !== -1; var IS_DEV_SERVER = process.argv[1].indexOf('webpack-dev-server') !== -1;
var DEV_SERVER_HOST = process.env.DEV_SERVER_HOST || 'localhost';
var DEV_SERVER_PORT = parseInt(process.env.DEV_SERVER_PORT, 10) || 3808; var DEV_SERVER_PORT = parseInt(process.env.DEV_SERVER_PORT, 10) || 3808;
var DEV_SERVER_LIVERELOAD = process.env.DEV_SERVER_LIVERELOAD !== 'false'; var DEV_SERVER_LIVERELOAD = process.env.DEV_SERVER_LIVERELOAD !== 'false';
var WEBPACK_REPORT = process.env.WEBPACK_REPORT; var WEBPACK_REPORT = process.env.WEBPACK_REPORT;
...@@ -187,12 +188,13 @@ if (IS_PRODUCTION) { ...@@ -187,12 +188,13 @@ if (IS_PRODUCTION) {
if (IS_DEV_SERVER) { if (IS_DEV_SERVER) {
config.devtool = 'cheap-module-eval-source-map'; config.devtool = 'cheap-module-eval-source-map';
config.devServer = { config.devServer = {
host: DEV_SERVER_HOST,
port: DEV_SERVER_PORT, port: DEV_SERVER_PORT,
headers: { 'Access-Control-Allow-Origin': '*' }, headers: { 'Access-Control-Allow-Origin': '*' },
stats: 'errors-only', stats: 'errors-only',
inline: DEV_SERVER_LIVERELOAD inline: DEV_SERVER_LIVERELOAD
}; };
config.output.publicPath = '//localhost:' + DEV_SERVER_PORT + config.output.publicPath; config.output.publicPath = '//' + DEV_SERVER_HOST + ':' + DEV_SERVER_PORT + config.output.publicPath;
config.plugins.push( config.plugins.push(
// watch node_modules for changes if we encounter a missing module compile error // watch node_modules for changes if we encounter a missing module compile error
new WatchMissingNodeModulesPlugin(path.join(ROOT_PATH, 'node_modules')) new WatchMissingNodeModulesPlugin(path.join(ROOT_PATH, 'node_modules'))
......
...@@ -223,7 +223,9 @@ class Gitlab::Seeder::CycleAnalytics ...@@ -223,7 +223,9 @@ class Gitlab::Seeder::CycleAnalytics
end end
Gitlab::Seeder.quiet do Gitlab::Seeder.quiet do
if ENV['SEED_CYCLE_ANALYTICS'] flag = 'SEED_CYCLE_ANALYTICS'
if ENV[flag]
Project.all.each do |project| Project.all.each do |project|
seeder = Gitlab::Seeder::CycleAnalytics.new(project) seeder = Gitlab::Seeder::CycleAnalytics.new(project)
seeder.seed! seeder.seed!
...@@ -235,6 +237,6 @@ Gitlab::Seeder.quiet do ...@@ -235,6 +237,6 @@ Gitlab::Seeder.quiet do
seeder = Gitlab::Seeder::CycleAnalytics.new(Project.order(:id).first, perf: true) seeder = Gitlab::Seeder::CycleAnalytics.new(Project.order(:id).first, perf: true)
seeder.seed_metrics! seeder.seed_metrics!
else else
puts "Not running the cycle analytics seed file. Use the `SEED_CYCLE_ANALYTICS` environment variable to enable it." puts "Skipped. Use the `#{flag}` environment variable to enable."
end end
end end
...@@ -27,43 +27,49 @@ end ...@@ -27,43 +27,49 @@ end
Sidekiq::Testing.inline! do Sidekiq::Testing.inline! do
Gitlab::Seeder.quiet do Gitlab::Seeder.quiet do
project_urls = [ flag = 'SEED_NESTED_GROUPS'
'https://android.googlesource.com/platform/hardware/broadcom/libbt.git',
'https://android.googlesource.com/platform/hardware/broadcom/wlan.git',
'https://android.googlesource.com/platform/hardware/bsp/bootloader/intel/edison-u-boot.git',
'https://android.googlesource.com/platform/hardware/bsp/broadcom.git',
'https://android.googlesource.com/platform/hardware/bsp/freescale.git',
'https://android.googlesource.com/platform/hardware/bsp/imagination.git',
'https://android.googlesource.com/platform/hardware/bsp/intel.git',
'https://android.googlesource.com/platform/hardware/bsp/kernel/common/v4.1.git',
'https://android.googlesource.com/platform/hardware/bsp/kernel/common/v4.4.git'
]
user = User.admins.first if ENV[flag]
project_urls = [
'https://android.googlesource.com/platform/hardware/broadcom/libbt.git',
'https://android.googlesource.com/platform/hardware/broadcom/wlan.git',
'https://android.googlesource.com/platform/hardware/bsp/bootloader/intel/edison-u-boot.git',
'https://android.googlesource.com/platform/hardware/bsp/broadcom.git',
'https://android.googlesource.com/platform/hardware/bsp/freescale.git',
'https://android.googlesource.com/platform/hardware/bsp/imagination.git',
'https://android.googlesource.com/platform/hardware/bsp/intel.git',
'https://android.googlesource.com/platform/hardware/bsp/kernel/common/v4.1.git',
'https://android.googlesource.com/platform/hardware/bsp/kernel/common/v4.4.git'
]
project_urls.each_with_index do |url, i| user = User.admins.first
full_path = url.sub('https://android.googlesource.com/', '')
full_path = full_path.sub(/\.git\z/, '')
full_path, _, project_path = full_path.rpartition('/')
group = Group.find_by_full_path(full_path) || create_group_with_parents(user, full_path)
params = { project_urls.each_with_index do |url, i|
import_url: url, full_path = url.sub('https://android.googlesource.com/', '')
namespace_id: group.id, full_path = full_path.sub(/\.git\z/, '')
path: project_path, full_path, _, project_path = full_path.rpartition('/')
name: project_path, group = Group.find_by_full_path(full_path) || create_group_with_parents(user, full_path)
description: FFaker::Lorem.sentence,
visibility_level: Gitlab::VisibilityLevel.values.sample
}
project = Projects::CreateService.new(user, params).execute params = {
project.send(:_run_after_commit_queue) import_url: url,
namespace_id: group.id,
path: project_path,
name: project_path,
description: FFaker::Lorem.sentence,
visibility_level: Gitlab::VisibilityLevel.values.sample
}
if project.valid? project = Projects::CreateService.new(user, params).execute
print '.' project.send(:_run_after_commit_queue)
else
print 'F' if project.valid?
print '.'
else
print 'F'
end
end end
else
puts "Skipped. Use the `#{flag}` environment variable to enable."
end end
end end
end end
# rubocop:disable all # rubocop:disable all
class ConvertClosedToStateInIssue < ActiveRecord::Migration class ConvertClosedToStateInIssue < ActiveRecord::Migration
include Gitlab::Database include Gitlab::Database::MigrationHelpers
def up def up
execute "UPDATE #{table_name} SET state = 'closed' WHERE closed = #{true_value}" execute "UPDATE #{table_name} SET state = 'closed' WHERE closed = #{true_value}"
......
# rubocop:disable all # rubocop:disable all
class ConvertClosedToStateInMergeRequest < ActiveRecord::Migration class ConvertClosedToStateInMergeRequest < ActiveRecord::Migration
include Gitlab::Database include Gitlab::Database::MigrationHelpers
def up def up
execute "UPDATE #{table_name} SET state = 'merged' WHERE closed = #{true_value} AND merged = #{true_value}" execute "UPDATE #{table_name} SET state = 'merged' WHERE closed = #{true_value} AND merged = #{true_value}"
......
# rubocop:disable all # rubocop:disable all
class ConvertClosedToStateInMilestone < ActiveRecord::Migration class ConvertClosedToStateInMilestone < ActiveRecord::Migration
include Gitlab::Database include Gitlab::Database::MigrationHelpers
def up def up
execute "UPDATE #{table_name} SET state = 'closed' WHERE closed = #{true_value}" execute "UPDATE #{table_name} SET state = 'closed' WHERE closed = #{true_value}"
......
# rubocop:disable all # rubocop:disable all
class UserColorScheme < ActiveRecord::Migration class UserColorScheme < ActiveRecord::Migration
include Gitlab::Database include Gitlab::Database::MigrationHelpers
def up def up
add_column :users, :color_scheme_id, :integer, null: false, default: 1 add_column :users, :color_scheme_id, :integer, null: false, default: 1
......
# rubocop:disable all # rubocop:disable all
class AddVisibilityLevelToProjects < ActiveRecord::Migration class AddVisibilityLevelToProjects < ActiveRecord::Migration
include Gitlab::Database include Gitlab::Database::MigrationHelpers
def self.up def self.up
add_column :projects, :visibility_level, :integer, :default => 0, :null => false add_column :projects, :visibility_level, :integer, :default => 0, :null => false
......
# rubocop:disable all # rubocop:disable all
class MigrateAlreadyImportedProjects < ActiveRecord::Migration class MigrateAlreadyImportedProjects < ActiveRecord::Migration
include Gitlab::Database include Gitlab::Database::MigrationHelpers
def up def up
execute("UPDATE projects SET import_status = 'finished' WHERE imported = #{true_value}") execute("UPDATE projects SET import_status = 'finished' WHERE imported = #{true_value}")
......
# rubocop:disable all # rubocop:disable all
class AddVisibilityLevelToSnippet < ActiveRecord::Migration class AddVisibilityLevelToSnippet < ActiveRecord::Migration
include Gitlab::Database include Gitlab::Database::MigrationHelpers
def up def up
add_column :snippets, :visibility_level, :integer, :default => 0, :null => false add_column :snippets, :visibility_level, :integer, :default => 0, :null => false
......
# rubocop:disable all # rubocop:disable all
class MigrateCiWebHooks < ActiveRecord::Migration class MigrateCiWebHooks < ActiveRecord::Migration
include Gitlab::Database include Gitlab::Database::MigrationHelpers
def up def up
execute( execute(
......
# rubocop:disable all # rubocop:disable all
class MigrateCiEmails < ActiveRecord::Migration class MigrateCiEmails < ActiveRecord::Migration
include Gitlab::Database include Gitlab::Database::MigrationHelpers
def up def up
# This inserts a new service: BuildsEmailService # This inserts a new service: BuildsEmailService
......
# rubocop:disable all # rubocop:disable all
class MigrateCiSlackService < ActiveRecord::Migration class MigrateCiSlackService < ActiveRecord::Migration
include Gitlab::Database include Gitlab::Database::MigrationHelpers
def up def up
properties_query = 'SELECT properties FROM ci_services ' \ properties_query = 'SELECT properties FROM ci_services ' \
......
# rubocop:disable all # rubocop:disable all
class MigrateCiHipChatService < ActiveRecord::Migration class MigrateCiHipChatService < ActiveRecord::Migration
include Gitlab::Database include Gitlab::Database::MigrationHelpers
def up def up
# From properties strip `hipchat_` key # From properties strip `hipchat_` key
......
class AddForeighKeyTriggerRequestsTrigger < ActiveRecord::Migration
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
disable_ddl_transaction!
def up
add_concurrent_foreign_key(:ci_trigger_requests, :ci_triggers, column: :trigger_id)
end
def down
remove_foreign_key(:ci_trigger_requests, column: :trigger_id)
end
end
class MigrateBuildEventsToPipelineEvents < ActiveRecord::Migration class MigrateBuildEventsToPipelineEvents < ActiveRecord::Migration
include Gitlab::Database::MigrationHelpers include Gitlab::Database::MigrationHelpers
include Gitlab::Database
DOWNTIME = false DOWNTIME = false
......
# See http://doc.gitlab.com/ce/development/migration_style_guide.html
# for more information on how to write migrations for GitLab.
class MigrateUserProjectView < ActiveRecord::Migration
include Gitlab::Database::MigrationHelpers
# Set this constant to true if this migration requires downtime.
DOWNTIME = false
def up
update_column_in_batches(:users, :project_view, 2) do |table, query|
query.where(table[:project_view].eq(0))
end
end
def down
# Nothing can be done to restore old values
end
end
...@@ -1568,6 +1568,7 @@ ActiveRecord::Schema.define(version: 20170408033905) do ...@@ -1568,6 +1568,7 @@ ActiveRecord::Schema.define(version: 20170408033905) do
add_foreign_key "chat_teams", "namespaces", on_delete: :cascade add_foreign_key "chat_teams", "namespaces", on_delete: :cascade
add_foreign_key "ci_builds", "ci_pipelines", column: "auto_canceled_by_id", name: "fk_a2141b1522", on_delete: :nullify add_foreign_key "ci_builds", "ci_pipelines", column: "auto_canceled_by_id", name: "fk_a2141b1522", on_delete: :nullify
add_foreign_key "ci_pipelines", "ci_pipelines", column: "auto_canceled_by_id", name: "fk_262d4c2d19", on_delete: :nullify add_foreign_key "ci_pipelines", "ci_pipelines", column: "auto_canceled_by_id", name: "fk_262d4c2d19", on_delete: :nullify
add_foreign_key "ci_trigger_requests", "ci_triggers", column: "trigger_id", name: "fk_b8ec8b7245", on_delete: :cascade
add_foreign_key "ci_trigger_schedules", "ci_triggers", column: "trigger_id", name: "fk_90a406cc94", on_delete: :cascade add_foreign_key "ci_trigger_schedules", "ci_triggers", column: "trigger_id", name: "fk_90a406cc94", on_delete: :cascade
add_foreign_key "ci_triggers", "users", column: "owner_id", name: "fk_e8e10d1964", on_delete: :cascade add_foreign_key "ci_triggers", "users", column: "owner_id", name: "fk_e8e10d1964", on_delete: :cascade
add_foreign_key "container_repositories", "projects" add_foreign_key "container_repositories", "projects"
......
...@@ -110,9 +110,8 @@ Here is an collection of tutorials and guides on setting up your CI pipeline. ...@@ -110,9 +110,8 @@ Here is an collection of tutorials and guides on setting up your CI pipeline.
- [Run PHP Composer & NPM scripts then deploy them to a staging server](examples/deployment/composer-npm-deploy.md) - [Run PHP Composer & NPM scripts then deploy them to a staging server](examples/deployment/composer-npm-deploy.md)
- **Blog posts** - **Blog posts**
- [Automated Debian packaging](https://about.gitlab.com/2016/10/12/automated-debian-package-build-with-gitlab-ci/) - [Automated Debian packaging](https://about.gitlab.com/2016/10/12/automated-debian-package-build-with-gitlab-ci/)
- [Spring boot application with GitLab CI and Kubernetes](https://about.gitlab.com/2016/11/30/setting-up-gitlab-ci-for-android-projects/) - [Spring boot application with GitLab CI and Kubernetes](https://about.gitlab.com/2016/12/14/continuous-delivery-of-a-spring-boot-application-with-gitlab-ci-and-kubernetes/)
- [Setting up CI for iOS projects](https://about.gitlab.com/2016/12/14/continuous-delivery-of-a-spring-boot-application-with-gitlab-ci-and-kubernetes/) - [Setting up GitLab CI for iOS projects](https://about.gitlab.com/2016/03/10/setting-up-gitlab-ci-for-ios-projects/)
- [Using GitLab CI for iOS projects](https://about.gitlab.com/2016/03/10/setting-up-gitlab-ci-for-ios-projects/)
- [Setting up GitLab CI for Android projects](https://about.gitlab.com/2016/11/30/setting-up-gitlab-ci-for-android-projects/) - [Setting up GitLab CI for Android projects](https://about.gitlab.com/2016/11/30/setting-up-gitlab-ci-for-android-projects/)
- [Building a new GitLab Docs site with Nanoc, GitLab CI, and GitLab Pages](https://about.gitlab.com/2016/12/07/building-a-new-gitlab-docs-site-with-nanoc-gitlab-ci-and-gitlab-pages/) - [Building a new GitLab Docs site with Nanoc, GitLab CI, and GitLab Pages](https://about.gitlab.com/2016/12/07/building-a-new-gitlab-docs-site-with-nanoc-gitlab-ci-and-gitlab-pages/)
- [CI/CD with GitLab in action](https://about.gitlab.com/2017/03/13/ci-cd-demo/) - [CI/CD with GitLab in action](https://about.gitlab.com/2017/03/13/ci-cd-demo/)
......
doc/ci/img/pipelines.png

7.34 KB | W: | H:

doc/ci/img/pipelines.png

6.15 KB | W: | H:

doc/ci/img/pipelines.png
doc/ci/img/pipelines.png
doc/ci/img/pipelines.png
doc/ci/img/pipelines.png
  • 2-up
  • Swipe
  • Onion skin
...@@ -48,8 +48,8 @@ Steps to split page-specific JavaScript from the main `main.js`: ...@@ -48,8 +48,8 @@ Steps to split page-specific JavaScript from the main `main.js`:
```haml ```haml
- content_for :page_specific_javascripts do - content_for :page_specific_javascripts do
= page_specific_javascript_bundle_tag('lib_chart') = webpack_bundle_tag 'lib_chart'
= page_specific_javascript_bundle_tag('graphs') = webpack_bundle_tag 'graphs'
``` ```
The above loads `chart.js` and `graphs_bundle.js` for this page only. `chart.js` The above loads `chart.js` and `graphs_bundle.js` for this page only. `chart.js`
......
...@@ -13,10 +13,19 @@ for more information on general testing practices at GitLab. ...@@ -13,10 +13,19 @@ for more information on general testing practices at GitLab.
## Karma test suite ## Karma test suite
GitLab uses the [Karma][karma] test runner with [Jasmine][jasmine] as its test GitLab uses the [Karma][karma] test runner with [Jasmine][jasmine] as its test
framework for our JavaScript unit tests. For tests that rely on DOM framework for our JavaScript unit tests. For tests that rely on DOM
manipulation we use fixtures which are pre-compiled from HAML source files and manipulation we use fixtures which are pre-compiled from HAML source files and
served during testing by the [jasmine-jquery][jasmine-jquery] plugin. served during testing by the [jasmine-jquery][jasmine-jquery] plugin.
JavaScript tests live in `spec/javascripts/`, matching the folder structure
of `app/assets/javascripts/`: `app/assets/javascripts/behaviors/autosize.js`
has a corresponding `spec/javascripts/behaviors/autosize_spec.js` file.
Keep in mind that in a CI environment, these tests are run in a headless
browser and you will not have access to certain APIs, such as
[`Notification`](https://developer.mozilla.org/en-US/docs/Web/API/notification),
which will have to be stubbed.
### Running frontend tests ### Running frontend tests
`rake karma` runs the frontend-only (JavaScript) tests. `rake karma` runs the frontend-only (JavaScript) tests.
...@@ -80,24 +89,23 @@ If an integration test depends on JavaScript to run correctly, you need to make ...@@ -80,24 +89,23 @@ If an integration test depends on JavaScript to run correctly, you need to make
sure the spec is configured to enable JavaScript when the tests are run. If you sure the spec is configured to enable JavaScript when the tests are run. If you
don't do this you'll see vague error messages from the spec runner. don't do this you'll see vague error messages from the spec runner.
To enable a JavaScript driver in an `rspec` test, add `js: true` to the To enable a JavaScript driver in an `rspec` test, add `:js` to the
individual spec or the context block containing multiple specs that need individual spec or the context block containing multiple specs that need
JavaScript enabled: JavaScript enabled:
```ruby ```ruby
# For one spec # For one spec
it 'presents information about abuse report', js: true do it 'presents information about abuse report', :js do
# assertions... # assertions...
end end
describe "Admin::AbuseReports", js: true do describe "Admin::AbuseReports", :js do
it 'presents information about abuse report' do it 'presents information about abuse report' do
# assertions... # assertions...
end end
it 'shows buttons for adding to abuse report' do it 'shows buttons for adding to abuse report' do
# assertions... # assertions...
end end
end end
``` ```
...@@ -113,13 +121,12 @@ file for the failing spec, add the `@javascript` flag above the Scenario: ...@@ -113,13 +121,12 @@ file for the failing spec, add the `@javascript` flag above the Scenario:
``` ```
@javascript @javascript
Scenario: Developer can approve merge request Scenario: Developer can approve merge request
Given I am a "Shop" developer Given I am a "Shop" developer
And I visit project "Shop" merge requests page And I visit project "Shop" merge requests page
And merge request 'Bug NS-04' must be approved And merge request 'Bug NS-04' must be approved
And I click link "Bug NS-04" And I click link "Bug NS-04"
When I click link "Approve" When I click link "Approve"
Then I should see approved merge request "Bug NS-04" Then I should see approved merge request "Bug NS-04"
``` ```
[capybara]: http://teamcapybara.github.io/capybara/ [capybara]: http://teamcapybara.github.io/capybara/
......
...@@ -4,28 +4,53 @@ When writing migrations for GitLab, you have to take into account that ...@@ -4,28 +4,53 @@ When writing migrations for GitLab, you have to take into account that
these will be ran by hundreds of thousands of organizations of all sizes, some with these will be ran by hundreds of thousands of organizations of all sizes, some with
many years of data in their database. many years of data in their database.
In addition, having to take a server offline for a an upgrade small or big is In addition, having to take a server offline for a a upgrade small or big is a
a big burden for most organizations. For this reason it is important that your big burden for most organizations. For this reason it is important that your
migrations are written carefully, can be applied online and adhere to the style guide below. migrations are written carefully, can be applied online and adhere to the style
guide below.
Migrations should not require GitLab installations to be taken offline unless Migrations are **not** allowed to require GitLab installations to be taken
_absolutely_ necessary - see the ["What Requires Downtime?"](what_requires_downtime.md) offline unless _absolutely necessary_. Downtime assumptions should be based on
page. If a migration requires downtime, this should be clearly mentioned during the behaviour of a migration when performed using PostgreSQL, as various
the review process, as well as being documented in the monthly release post. For operations in MySQL may require downtime without there being alternatives.
more information, see the "Downtime Tagging" section below.
When downtime is necessary the migration has to be approved by:
1. The VP of Engineering
1. A Backend Lead
1. A Database Specialist
An up-to-date list of people holding these titles can be found at
<https://about.gitlab.com/team/>.
The document ["What Requires Downtime?"](what_requires_downtime.md) specifies
various database operations, whether they require downtime and how to
work around that whenever possible.
When writing your migrations, also consider that databases might have stale data When writing your migrations, also consider that databases might have stale data
or inconsistencies and guard for that. Try to make as little assumptions as possible or inconsistencies and guard for that. Try to make as few assumptions as
about the state of the database. possible about the state of the database.
Please don't depend on GitLab-specific code since it can change in future
versions. If needed copy-paste GitLab code into the migration to make it forward
compatible.
## Commit Guidelines
Please don't depend on GitLab specific code since it can change in future versions. Each migration **must** be added in its own commit with a descriptive commit
If needed copy-paste GitLab code into the migration to make it forward compatible. message. If a commit adds a migration it _should only_ include the migration and
any corresponding changes to `db/schema.rb`. This makes it easy to revert a
database migration without accidentally reverting other changes.
## Downtime Tagging ## Downtime Tagging
Every migration must specify if it requires downtime or not, and if it should Every migration must specify if it requires downtime or not, and if it should
require downtime it must also specify a reason for this. To do so, add the require downtime it must also specify a reason for this. This is required even
following two constants to the migration class' body: if 99% of the migrations won't require downtime as this makes it easier to find
the migrations that _do_ require downtime.
To tag a migration, add the following two constants to the migration class'
body:
* `DOWNTIME`: a boolean that when set to `true` indicates the migration requires * `DOWNTIME`: a boolean that when set to `true` indicates the migration requires
downtime. downtime.
...@@ -50,12 +75,53 @@ from a migration class. ...@@ -50,12 +75,53 @@ from a migration class.
## Reversibility ## Reversibility
Your migration should be reversible. This is very important, as it should Your migration **must be** reversible. This is very important, as it should
be possible to downgrade in case of a vulnerability or bugs. be possible to downgrade in case of a vulnerability or bugs.
In your migration, add a comment describing how the reversibility of the In your migration, add a comment describing how the reversibility of the
migration was tested. migration was tested.
## Multi Threading
Sometimes a migration might need to use multiple Ruby threads to speed up a
migration. For this to work your migration needs to include the module
`Gitlab::Database::MultiThreadedMigration`:
```ruby
class MyMigration < ActiveRecord::Migration
include Gitlab::Database::MigrationHelpers
include Gitlab::Database::MultiThreadedMigration
end
```
You can then use the method `with_multiple_threads` to perform work in separate
threads. For example:
```ruby
class MyMigration < ActiveRecord::Migration
include Gitlab::Database::MigrationHelpers
include Gitlab::Database::MultiThreadedMigration
def up
with_multiple_threads(4) do
disable_statement_timeout
# ...
end
end
end
```
Here the call to `disable_statement_timeout` will use the connection local to
the `with_multiple_threads` block, instead of re-using the global connection
pool. This ensures each thread has its own connection object, and won't time
out when trying to obtain one.
**NOTE:** PostgreSQL has a maximum amount of connections that it allows. This
limit can vary from installation to installation. As a result it's recommended
you do not use more than 32 threads in a single migration. Usually 4-8 threads
should be more than enough.
## Removing indices ## Removing indices
When removing an index make sure to use the method `remove_concurrent_index` instead When removing an index make sure to use the method `remove_concurrent_index` instead
...@@ -78,7 +144,10 @@ end ...@@ -78,7 +144,10 @@ end
## Adding indices ## Adding indices
If you need to add an unique index please keep in mind there is possibility of existing duplicates. If it is possible write a separate migration for handling this situation. It can be just removing or removing with overwriting all references to these duplicates depend on situation. If you need to add a unique index please keep in mind there is the possibility
of existing duplicates being present in the database. This means that should
always _first_ add a migration that removes any duplicates, before adding the
unique index.
When adding an index make sure to use the method `add_concurrent_index` instead When adding an index make sure to use the method `add_concurrent_index` instead
of the regular `add_index` method. The `add_concurrent_index` method of the regular `add_index` method. The `add_concurrent_index` method
...@@ -90,17 +159,22 @@ so: ...@@ -90,17 +159,22 @@ so:
```ruby ```ruby
class MyMigration < ActiveRecord::Migration class MyMigration < ActiveRecord::Migration
include Gitlab::Database::MigrationHelpers include Gitlab::Database::MigrationHelpers
disable_ddl_transaction! disable_ddl_transaction!
def change def up
add_concurrent_index :table, :column
end
def down
remove_index :table, :column if index_exists?(:table, :column)
end end
end end
``` ```
## Adding Columns With Default Values ## Adding Columns With Default Values
When adding columns with default values you should use the method When adding columns with default values you must use the method
`add_column_with_default`. This method ensures the table is updated without `add_column_with_default`. This method ensures the table is updated without
requiring downtime. This method is not reversible so you must manually define requiring downtime. This method is not reversible so you must manually define
the `up` and `down` methods in your migration class. the `up` and `down` methods in your migration class.
...@@ -123,6 +197,9 @@ class MyMigration < ActiveRecord::Migration ...@@ -123,6 +197,9 @@ class MyMigration < ActiveRecord::Migration
end end
``` ```
Keep in mind that this operation can easily take 10-15 minutes to complete on
larger installations (e.g. GitLab.com). As a result you should only add default
values if absolutely necessary.
## Integer column type ## Integer column type
...@@ -147,13 +224,15 @@ add_column(:projects, :foo, :integer, default: 10, limit: 8) ...@@ -147,13 +224,15 @@ add_column(:projects, :foo, :integer, default: 10, limit: 8)
## Testing ## Testing
Make sure that your migration works with MySQL and PostgreSQL with data. An empty database does not guarantee that your migration is correct. Make sure that your migration works with MySQL and PostgreSQL with data. An
empty database does not guarantee that your migration is correct.
Make sure your migration can be reversed. Make sure your migration can be reversed.
## Data migration ## Data migration
Please prefer Arel and plain SQL over usual ActiveRecord syntax. In case of using plain SQL you need to quote all input manually with `quote_string` helper. Please prefer Arel and plain SQL over usual ActiveRecord syntax. In case of
using plain SQL you need to quote all input manually with `quote_string` helper.
Example with Arel: Example with Arel:
...@@ -177,3 +256,17 @@ select_all("SELECT name, COUNT(id) as cnt FROM tags GROUP BY name HAVING COUNT(i ...@@ -177,3 +256,17 @@ select_all("SELECT name, COUNT(id) as cnt FROM tags GROUP BY name HAVING COUNT(i
execute("DELETE FROM tags WHERE id IN(#{duplicate_ids.join(",")})") execute("DELETE FROM tags WHERE id IN(#{duplicate_ids.join(",")})")
end end
``` ```
If you need more complex logic you can define and use models local to a
migration. For example:
```ruby
class MyMigration < ActiveRecord::Migration
class Project < ActiveRecord::Base
self.table_name = 'projects'
end
end
```
When doing so be sure to explicitly set the model's table name so it's not
derived from the class name or namespace.
This diff is collapsed.
This diff is collapsed.
...@@ -289,9 +289,9 @@ sudo usermod -aG redis git ...@@ -289,9 +289,9 @@ sudo usermod -aG redis git
### Clone the Source ### Clone the Source
# Clone GitLab repository # Clone GitLab repository
sudo -u git -H git clone https://gitlab.com/gitlab-org/gitlab-ce.git -b 9-0-stable gitlab sudo -u git -H git clone https://gitlab.com/gitlab-org/gitlab-ce.git -b 9-1-stable gitlab
**Note:** You can change `9-0-stable` to `master` if you want the *bleeding edge* version, but never install master on a production server! **Note:** You can change `9-1-stable` to `master` if you want the *bleeding edge* version, but never install master on a production server!
### Configure It ### Configure It
...@@ -475,7 +475,7 @@ with setting up Gitaly until you upgrade to GitLab 9.2 or later. ...@@ -475,7 +475,7 @@ with setting up Gitaly until you upgrade to GitLab 9.2 or later.
sudo -u git cp config.toml.example config.toml sudo -u git cp config.toml.example config.toml
# If you are using non-default settings you need to update config.toml # If you are using non-default settings you need to update config.toml
sudo -u git -H editor config.toml sudo -u git -H editor config.toml
# Enable Gitaly in the init script # Enable Gitaly in the init script
echo 'gitaly_enabled=true' | sudo tee -a /etc/default/gitlab echo 'gitaly_enabled=true' | sudo tee -a /etc/default/gitlab
......
# Authentication
This page gathers all the resources for the topic **Authentication** within GitLab.
## GitLab users
- [SSH](../../ssh/README.md)
- [Two-Factor Authentication (2FA)](../../user/profile/account/two_factor_authentication.md#two-factor-authentication)
- **Articles:**
- [Support for Universal 2nd Factor Authentication - YubiKeys](https://about.gitlab.com/2016/06/22/gitlab-adds-support-for-u2f/)
- [Security Webcast with Yubico](https://about.gitlab.com/2016/08/31/gitlab-and-yubico-security-webcast/)
- **Integrations:**
- [GitLab as OAuth2 authentication service provider](../../integration/oauth_provider.md#introduction-to-oauth)
## GitLab administrators
- [LDAP (Community Edition)](../../administration/auth/ldap.md)
- [LDAP (Enterprise Edition)](https://docs.gitlab.com/ee/administration/auth/ldap-ee.html)
- [Enforce Two-factor Authentication (2FA)](../../security/two_factor_authentication.md#enforce-two-factor-authentication-2fa)
- **Articles:**
- [Feature Highlight: LDAP Integration](https://about.gitlab.com/2014/07/10/feature-highlight-ldap-sync/)
- [Debugging LDAP](https://about.gitlab.com/handbook/support/workflows/ldap/debugging_ldap.html)
- **Integrations:**
- [OmniAuth](../../integration/omniauth.md)
- [Authentiq OmniAuth Provider](../../administration/auth/authentiq.md#authentiq-omniauth-provider)
- [Atlassian Crowd OmniAuth Provider](../../administration/auth/crowd.md)
- [CAS OmniAuth Provider](../../integration/cas.md)
- [SAML OmniAuth Provider](../../integration/saml.md)
- [Okta SSO provider](../../administration/auth/okta.md)
- [Kerberos integration (GitLab EE)](https://docs.gitlab.com/ee/integration/kerberos.html)
## API
- [OAuth 2 Tokens](../../api/README.md#oauth-2-tokens)
- [Private Tokens](../../api/README.md#private-tokens)
- [Impersonation tokens](../../api/README.md#impersonation-tokens)
- [GitLab as an OAuth2 provider](../../api/oauth2.md#gitlab-as-an-oauth2-provider)
- [GitLab Runner API - Authentication](../../api/ci/runners.md#authentication)
## Third-party resources
- [Kanboard Plugin GitLab Authentication](https://kanboard.net/plugin/gitlab-auth)
- [Jenkins GitLab OAuth Plugin](https://wiki.jenkins-ci.org/display/JENKINS/GitLab+OAuth+Plugin)
- [Setup Gitlab CE with Active Directory authentication](https://www.caseylabs.com/setup-gitlab-ce-with-active-directory-authentication/)
- [How to customize GitLab to support OpenID authentication](http://eric.van-der-vlist.com/blog/2013/11/23/how-to-customize-gitlab-to-support-openid-authentication/)
- [Openshift - Configuring Authentication and User Agent](https://docs.openshift.org/latest/install_config/configuring_authentication.html#GitLab)
# Git documentation
Git is a [free and open source](https://git-scm.com/about/free-and-open-source)
distributed version control system designed to handle everything from small to
very large projects with speed and efficiency.
[GitLab](https://about.gitlab.com) is a Git-based fully integrated platform for
software development. Besides Git's functionalities, GitLab has a lot of
powerful [features](https://about.gitlab.com/features/) to enhance your
[workflow](https://about.gitlab.com/2016/10/25/gitlab-workflow-an-overview/).
We've gathered some resources to help you to get the best from Git with GitLab.
## Getting started
- [Git concepts](../../university/training/user_training.md#git-concepts)
- [Start using Git on the command line](../../gitlab-basics/start-using-git.md)
- [Command Line basic commands](../../gitlab-basics/command-line-commands.md)
- [GitLab Git Cheat Sheet (download)](https://gitlab.com/gitlab-com/marketing/raw/master/design/print/git-cheatsheet/print-pdf/git-cheatsheet.pdf)
- **Articles:**
- [Git Tips & Tricks](https://about.gitlab.com/2016/12/08/git-tips-and-tricks/)
- [Eight Tips to help you work better with Git](https://about.gitlab.com/2015/02/19/8-tips-to-help-you-work-better-with-git/)
- **Presentations:**
- [GLU Course: About Version Control](https://docs.google.com/presentation/d/16sX7hUrCZyOFbpvnrAFrg6tVO5_yT98IgdAqOmXwBho/edit?usp=sharing)
- **Third-party resources:**
- What is [Git](https://git-scm.com)
- [Version control](https://git-scm.com/book/en/v2/Getting-Started-About-Version-Control)
- [Getting Started - Git Basics](https://git-scm.com/book/en/v2/Getting-Started-Git-Basics)
- [Getting Started - Installing Git](https://git-scm.com/book/en/v2/Getting-Started-Installing-Git)
- [Git on the Server - GitLab](https://git-scm.com/book/en/v2/Git-on-the-Server-GitLab)
## Branching strategies
- **Articles:**
- [GitLab Flow](https://about.gitlab.com/2014/09/29/gitlab-flow/)
- **Third-party resources:**
- [Git Branching - Branches in a Nutshell](https://git-scm.com/book/en/v2/Git-Branching-Branches-in-a-Nutshell)
- [Git Branching - Branching Workflows](https://git-scm.com/book/en/v2/Git-Branching-Branching-Workflows)
## Advanced use
- [Custom Git Hooks](../../administration/custom_hooks.md)
- [Git Attributes](../../user/project/git_attributes.md)
- Git Submodules: [Using Git submodules with GitLab CI](../../ci/git_submodules.md#using-git-submodules-with-gitlab-ci)
## API
- [Gitignore templates](../../api/templates/gitignores.md)
## Git LFS
- [Git LFS](../../workflow/lfs/manage_large_binaries_with_git_lfs.md)
- [Git-Annex to Git-LFS migration guide](https://docs.gitlab.com/ee/workflow/lfs/migrate_from_git_annex_to_git_lfs.html)
- **Articles:**
- [Getting Started with Git LFS](https://about.gitlab.com/2017/01/30/getting-started-with-git-lfs-tutorial/)
- [Towards a production quality open source Git LFS server](https://about.gitlab.com/2015/08/13/towards-a-production-quality-open-source-git-lfs-server/)
## General information
- **Articles:**
- [The future of SaaS hosted Git repository pricing](https://about.gitlab.com/2016/05/11/git-repository-pricing/)
...@@ -7,10 +7,10 @@ you through better understanding GitLab's concepts ...@@ -7,10 +7,10 @@ you through better understanding GitLab's concepts
through our regular docs, and, when available, through articles (guides, through our regular docs, and, when available, through articles (guides,
tutorials, technical overviews, blog posts) and videos. tutorials, technical overviews, blog posts) and videos.
- [GitLab Installation](../install/README.md) - [Authentication](authentication/index.md)
- [Continuous Integration (GitLab CI)](../ci/README.md) - [Continuous Integration (GitLab CI)](../ci/README.md)
- [Git](git/index.md)
- [GitLab Installation](../install/README.md)
- [GitLab Pages](../user/project/pages/index.md) - [GitLab Pages](../user/project/pages/index.md)
>**Note:** >**Note:** More topics will be available soon.
Non-linked topics are currently under development and subjected to change.
More topics will be available soon.
# From 9.0 to 9.1 # From 9.0 to 9.1
** TODO: **
# TODO clean out 9.0-specific stuff
Make sure you view this update guide from the tag (version) of GitLab you would Make sure you view this update guide from the tag (version) of GitLab you would
like to install. In most cases this should be the highest numbered production like to install. In most cases this should be the highest numbered production
tag (without rc in it). You can select the tag in the version dropdown at the tag (without rc in it). You can select the tag in the version dropdown at the
......
...@@ -48,6 +48,23 @@ GitLab provides official Docker images for both Community and Enterprise ...@@ -48,6 +48,23 @@ GitLab provides official Docker images for both Community and Enterprise
editions. They are based on the Omnibus package and instructions on how to editions. They are based on the Omnibus package and instructions on how to
update them are in [a separate document][omnidocker]. update them are in [a separate document][omnidocker].
## Upgrading without downtime
Starting with GitLab 9.1.0 it's possible to upgrade to a newer version of GitLab
without having to take your GitLab instance offline. However, for this to work
there are the following requirements:
1. You can only upgrade 1 release at a time. For example, if 9.1.15 is the last
release of 9.1 then you can safely upgrade from that version to 9.2.0.
However, if you are running 9.1.14 you first need to upgrade to 9.1.15.
2. You have to use [post-deployment
migrations](../development/post_deployment_migrations.md).
3. You are using PostgreSQL. If you are using MySQL you will still need downtime
when upgrading.
This applies to major, minor, and patch releases unless stated otherwise in a
release post.
## Upgrading between editions ## Upgrading between editions
GitLab comes in two flavors: [Community Edition][ce] which is MIT licensed, GitLab comes in two flavors: [Community Edition][ce] which is MIT licensed,
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
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