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:
script:
- git fetch origin v8.14.10
- 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 exec rake db:drop db:create db:schema:load db:seed_fu
- git checkout $CI_COMMIT_SHA
......
......@@ -25,14 +25,20 @@ logs, and code as it's very hard to read otherwise.)
#### Results of GitLab environment info
<details>
(For installations with omnibus-gitlab package run and paste the output of:
`sudo gitlab-rake gitlab:env:info`)
(For installations from source run and paste the output of:
`sudo -u git -H bundle exec rake gitlab:env:info RAILS_ENV=production`)
</details>
#### Results of GitLab application Check
<details>
(For installations with omnibus-gitlab package run and paste the output of:
`sudo gitlab-rake gitlab:check SANITIZE=true`)
......@@ -41,6 +47,8 @@ logs, and code as it's very hard to read otherwise.)
(we will only investigate if the tests are passing)
</details>
### Possible fixes
(If you can, link to the line of code that might be responsible for the problem)
......@@ -363,7 +363,7 @@ GEM
grape-entity (0.6.0)
activesupport
multi_json (>= 1.3.2)
grpc (1.1.2)
grpc (1.2.2)
google-protobuf (~> 3.1)
googleauth (~> 0.5.1)
gssapi (1.2.0)
......
......@@ -101,6 +101,7 @@ $(() => {
if (list.type === 'closed') {
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 = {
template: '<li>${title}</li>'
},
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: {
sorter: function(query, items, searchKey) {
......
......@@ -20,57 +20,60 @@ class Issue {
});
Issue.initIssueBtnEventListeners();
}
Issue.$btnNewBranch = $('#new-branch');
Issue.initMergeRequests();
Issue.initRelatedBranches();
Issue.initCanCreateBranch();
}
static initIssueBtnEventListeners() {
var issueFailMessage;
issueFailMessage = 'Unable to update this issue at this time.';
return $('a.btn-close, a.btn-reopen').on('click', function(e) {
var $this, isClose, shouldSubmit, url;
const issueFailMessage = 'Unable to update this issue at this time.';
const closeButtons = $('a.btn-close');
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.stopImmediatePropagation();
$this = $(this);
isClose = $this.hasClass('btn-close');
shouldSubmit = $this.hasClass('btn-comment');
if (shouldSubmit) {
Issue.submitNoteForm($this.closest('form'));
}
$this.prop('disabled', true);
Issue.setNewBranchButtonState(true, null);
url = $this.attr('href');
return $.ajax({
type: 'PUT',
url: url,
error: function(jqXHR, textStatus, errorThrown) {
var issueStatus;
issueStatus = isClose ? 'close' : 'open';
return new Flash(issueFailMessage, 'alert');
},
success: function(data, textStatus, jqXHR) {
if ('id' in data) {
$(document).trigger('issuable:change');
let total = Number($('.issue_counter').text().replace(/[^\d]/, ''));
if (isClose) {
$('a.btn-close').addClass('hidden');
$('a.btn-reopen').removeClass('hidden');
$('div.status-box-closed').removeClass('hidden');
$('div.status-box-open').addClass('hidden');
total -= 1;
} else {
$('a.btn-reopen').addClass('hidden');
$('a.btn-close').removeClass('hidden');
$('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);
url: url
}).fail(function(jqXHR, textStatus, errorThrown) {
new Flash(issueFailMessage);
Issue.initCanCreateBranch();
}).done(function(data, textStatus, jqXHR) {
if ('id' in data) {
$(document).trigger('issuable:change');
const isClosed = $this.hasClass('btn-close');
closeButtons.toggleClass('hidden', isClosed);
reopenButtons.toggleClass('hidden', !isClosed);
isClosedBadge.toggleClass('hidden', !isClosed);
isOpenBadge.toggleClass('hidden', isClosed);
let numProjectIssues = Number(projectIssuesCounter.text().replace(/[^\d]/, ''));
numProjectIssues = isClosed ? numProjectIssues - 1 : numProjectIssues + 1;
projectIssuesCounter.text(gl.text.addDelimiter(numProjectIssues));
} else {
new Flash(issueFailMessage);
}
$this.prop('disabled', false);
Issue.initCanCreateBranch();
});
});
}
......@@ -86,9 +89,9 @@ class Issue {
static initMergeRequests() {
var $container;
$container = $('#merge-requests');
return $.getJSON($container.data('url')).error(function() {
return new Flash('Failed to load referenced merge requests', 'alert');
}).success(function(data) {
return $.getJSON($container.data('url')).fail(function() {
return new Flash('Failed to load referenced merge requests');
}).done(function(data) {
if ('html' in data) {
return $container.html(data.html);
}
......@@ -98,9 +101,9 @@ class Issue {
static initRelatedBranches() {
var $container;
$container = $('#related-branches');
return $.getJSON($container.data('url')).error(function() {
return new Flash('Failed to load related branches', 'alert');
}).success(function(data) {
return $.getJSON($container.data('url')).fail(function() {
return new Flash('Failed to load related branches');
}).done(function(data) {
if ('html' in data) {
return $container.html(data.html);
}
......@@ -108,24 +111,27 @@ class Issue {
}
static initCanCreateBranch() {
var $container;
$container = $('#new-branch');
// If the user doesn't have the required permissions the container isn't
// rendered at all.
if ($container.length === 0) {
if (Issue.$btnNewBranch.length === 0) {
return;
}
return $.getJSON($container.data('path')).error(function() {
$container.find('.unavailable').show();
return new Flash('Failed to check if a new branch can be created.', 'alert');
}).success(function(data) {
if (data.can_create_branch) {
$container.find('.available').show();
} else {
return $container.find('.unavailable').show();
}
return $.getJSON(Issue.$btnNewBranch.data('path')).fail(function() {
Issue.setNewBranchButtonState(false, false);
new Flash('Failed to check if a new branch can be created.');
}).done(function(data) {
Issue.setNewBranchButtonState(false, data.can_create_branch);
});
}
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;
......@@ -5,7 +5,7 @@
direction: rtl;
@media (min-width: $screen-sm-min) and (max-width: $screen-md-max) {
overflow-x: scroll;
overflow-x: auto;
}
}
......
......@@ -82,7 +82,7 @@
.input-token:last-child {
flex: 1;
-webkit-flex: 1;
max-width: initial;
max-width: inherit;
}
}
......@@ -246,17 +246,17 @@
}
}
.filtered-search-history-dropdown-toggle-button {
.filtered-search-history-dropdown-wrapper {
position: static;
display: flex;
align-items: center;
flex-direction: column;
}
.filtered-search-history-dropdown-toggle-button {
flex: 1;
width: auto;
height: 100%;
padding-top: 0;
padding-left: 0.75em;
padding-bottom: 0;
padding-right: 0.5em;
padding-right: 10px;
background-color: transparent;
border-radius: 0;
border-top: 0;
border-left: 0;
......@@ -264,6 +264,7 @@
border-right: 1px solid $border-color;
color: $gl-text-color-secondary;
line-height: 1;
transition: color 0.1s linear;
......@@ -275,24 +276,21 @@
}
.dropdown-toggle-text {
display: inline-block;
color: inherit;
.fa {
vertical-align: middle;
color: inherit;
}
}
.fa {
position: initial;
position: static;
}
}
.filtered-search-history-dropdown-wrapper {
position: initial;
flex-shrink: 0;
}
.filtered-search-history-dropdown {
width: 40%;
......
......@@ -39,7 +39,7 @@
overflow-y: hidden;
font-size: 12px;
.fa-refresh {
.fa-spinner {
font-size: 24px;
margin-left: 20px;
}
......@@ -219,7 +219,7 @@
font-size: 12px;
position: relative;
.fa-refresh {
.fa-spinner {
font-size: 24px;
}
......@@ -366,7 +366,7 @@
background-color: $row-hover;
}
.fa-refresh {
.fa-spinner {
font-size: 13px;
margin-left: 3px;
}
......
......@@ -523,7 +523,6 @@
}
.content-block {
border-top: 1px solid $border-color;
padding: $gl-padding-top $gl-padding;
}
......
......@@ -18,12 +18,12 @@ ul.notes {
float: left;
svg {
width: 18px;
height: 18px;
width: 16px;
height: 16px;
fill: $gray-darkest;
position: absolute;
left: 30px;
top: 15px;
left: 0;
top: 16px;
}
}
......@@ -144,6 +144,10 @@ ul.notes {
padding: 0;
clear: both;
@media (min-width: $screen-sm-min) {
margin-left: 65px;
}
&.timeline-entry::after {
clear: none;
}
......@@ -172,6 +176,10 @@ ul.notes {
.timeline-content {
padding: 14px 10px;
@media (min-width: $screen-sm-min) {
margin-left: 20px;
}
}
.note-header {
......
......@@ -10,7 +10,7 @@ class Projects::HooksController < Projects::ApplicationController
@hook = @project.hooks.new(hook_params)
@hook.save
unless @hook.valid?
unless @hook.valid?
@hooks = @project.hooks.select(&:persisted?)
flash[:alert] = @hook.errors.full_messages.join.html_safe
end
......@@ -49,7 +49,7 @@ class Projects::HooksController < Projects::ApplicationController
def hook_params
params.require(:hook).permit(
:build_events,
:job_events,
:pipeline_events,
:enable_ssl_verification,
:issues_events,
......
......@@ -41,7 +41,7 @@ class Projects::MergeRequestsController < Projects::ApplicationController
@collection_type = "MergeRequest"
@merge_requests = merge_requests_collection
@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)
if @merge_requests.out_of_range? && @merge_requests.total_pages != 0
......
......@@ -363,7 +363,11 @@ class ProjectsController < Projects::ApplicationController
end
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
# Override extract_ref from ExtractsPath, which returns the branch and file path
......@@ -384,4 +388,8 @@ class ProjectsController < Projects::ApplicationController
@id = get_id
tree
end
def project_view_files_allowed?
!project.empty_repo? && can?(current_user, :download_code, project)
end
end
......@@ -3,7 +3,8 @@ module JavascriptHelper
javascript_include_tag asset_path(js)
end
def page_specific_javascript_bundle_tag(js)
javascript_include_tag(*webpack_asset_paths(js))
# deprecated; use webpack_bundle_tag directly instead
def page_specific_javascript_bundle_tag(bundle)
webpack_bundle_tag(bundle)
end
end
......@@ -63,6 +63,10 @@ module PreferencesHelper
end
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
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
belongs_to :project
belongs_to :owner, class_name: "User"
has_many :trigger_requests, dependent: :destroy
has_many :trigger_requests
has_one :trigger_schedule, dependent: :destroy
validates :token, presence: true, uniqueness: true
......
......@@ -2,9 +2,9 @@
module DiscussionOnDiff
extend ActiveSupport::Concern
included do
NUMBER_OF_TRUNCATED_DIFF_LINES = 16
NUMBER_OF_TRUNCATED_DIFF_LINES = 16
included do
delegate :line_code,
:original_line_code,
:diff_file,
......
......@@ -23,6 +23,10 @@ class ContainerRepository < ActiveRecord::Base
@path ||= [project.full_path, name].select(&:present?).join('/')
end
def location
File.join(registry.path, path)
end
def tag(tag)
ContainerRegistry::Tag.new(self, tag)
end
......
......@@ -34,8 +34,6 @@ class Issue < ActiveRecord::Base
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 :without_due_date, -> { where(due_date: nil) }
......
......@@ -21,6 +21,8 @@ class Label < ActiveRecord::Base
has_many :issues, through: :label_links, source: :target, source_type: 'Issue'
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
# Don't allow ',' for label titles
......@@ -193,4 +195,8 @@ class Label < ActiveRecord::Base
def sanitize_title(value)
CGI.unescapeHTML(Sanitize.clean(value.to_s))
end
def strip_whitespace_from_title_and_color
%w(color title).each { |attr| self[attr] = self[attr]&.strip }
end
end
......@@ -110,7 +110,6 @@ class MergeRequest < ActiveRecord::Base
scope :by_source_or_target_branch, ->(branch_name) do
where("source_branch = :branch OR target_branch = :branch", branch: branch_name)
end
scope :cared, ->(user) { where('assignee_id = :user OR author_id = :user', user: user.id) }
scope :by_milestone, ->(milestone) { where(milestone_id: milestone) }
scope :of_projects, ->(ids) { where(target_project_id: ids) }
scope :from_project, ->(project) { where(source_project_id: project.id) }
......
......@@ -98,6 +98,7 @@ class Note < ActiveRecord::Base
before_validation :set_discussion_id, on: :create
after_save :keep_around_commit, unless: :for_personal_snippet?
after_save :expire_etag_cache
after_destroy :expire_etag_cache
class << self
def model_name
......
......@@ -613,10 +613,6 @@ class User < ActiveRecord::Base
name.split.first unless name.blank?
end
def cared_merge_requests
MergeRequest.cared(self)
end
def projects_limit_left
projects_limit - personal_projects.count
end
......
......@@ -31,6 +31,7 @@ class GroupPolicy < BasePolicy
can! :admin_namespace
can! :admin_group_member
can! :change_visibility_level
can! :create_subgroup if @user.can_create_group
end
if globally_viewable && @subject.request_access_enabled && !member
......
......@@ -13,7 +13,7 @@
= button_to reset_health_check_token_admin_application_settings_path,
method: :put, class: 'btn btn-default',
data: { confirm: 'Are you sure you want to reset the health check token?' } do
= icon('refresh')
= icon('spinner')
Reset health check access token
%p.light
Health information can be retrieved as plain text, JSON, or XML using:
......
......@@ -21,7 +21,7 @@
= button_to reset_runners_token_admin_application_settings_path,
method: :put, class: 'btn btn-default',
data: { confirm: 'Are you sure you want to reset registration token?' } do
= icon('refresh')
= icon('spinner')
Reset runners registration token
.bs-callout
......
......@@ -9,7 +9,7 @@
.nav-controls
= 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
- 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
New Subgroup
......
......@@ -252,7 +252,7 @@
= icon('chevron-down')
.dropdown-menu.dropdown-select.dropdown-menu-selectable
.dropdown-title
%span Dropdown Title
%span Dropdown title
%button.dropdown-title-button.dropdown-menu-close{ aria: { label: "Close" } }
= icon('times')
.dropdown-input
......@@ -291,7 +291,7 @@
= icon('chevron-down')
.dropdown-menu.dropdown-select.dropdown-menu-selectable.is-loading
.dropdown-title
%span Dropdown Title
%span Dropdown title
%button.dropdown-title-button.dropdown-menu-close{ aria: { label: "Close" } }
= icon('times')
.dropdown-input
......@@ -335,7 +335,7 @@
= icon('chevron-down')
.dropdown-menu.dropdown-select.dropdown-menu-selectable.dropdown-menu-user
.dropdown-title
%span Dropdown Title
%span Dropdown title
%button.dropdown-title-button.dropdown-menu-close{ aria: { label: "Close" } }
= icon('times')
.dropdown-input
......@@ -362,7 +362,7 @@
.dropdown-title
%button.dropdown-title-button.dropdown-menu-back{ aria: { label: "Go back" } }
= icon('arrow-left')
%span Dropdown Title
%span Dropdown title
%button.dropdown-title-button.dropdown-menu-close{ aria: { label: "Close" } }
= icon('times')
.dropdown-input
......
......@@ -28,9 +28,9 @@
= stylesheet_link_tag "application", media: "all"
= stylesheet_link_tag "print", media: "print"
= javascript_include_tag(*webpack_asset_paths("runtime"))
= javascript_include_tag(*webpack_asset_paths("common"))
= javascript_include_tag(*webpack_asset_paths("main"))
= webpack_bundle_tag "runtime"
= webpack_bundle_tag "common"
= webpack_bundle_tag "main"
- if content_for?(:page_specific_javascripts)
= yield :page_specific_javascripts
......
%ul
= 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
Projects
= 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
Groups
= 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
Snippets
%li.divider
= nav_link(controller: :help) do
= link_to help_path, title: 'Help' do
%span
......
......@@ -23,7 +23,7 @@
Registry
- 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
%span
Issues
......@@ -31,7 +31,7 @@
%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
= 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
%span
Merge Requests
......
......@@ -136,7 +136,7 @@
- else
= build.id
- 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
new Sidebar();
......@@ -36,7 +36,7 @@
= icon('warning', class: 'text-warning has-tooltip', title: 'Job is stuck. Check runners.')
- 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
- if job.tags.any?
......
- @no_container = true
- page_title "Edit", @label.name, "Labels"
= render "projects/issues/head"
= render "shared/mr_head"
%div{ class: container_class }
%h3.page-title
......
- @no_container = true
- page_title "Labels"
- hide_class = ''
= render "projects/issues/head"
= render "shared/mr_head"
- if @labels.exists? || @prioritized_labels.exists?
%div{ class: container_class }
......
- @no_container = true
- page_title "New Label"
= render "projects/issues/head"
= render "shared/mr_head"
%div{ class: container_class }
%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 @@
- @bulk_edit = can?(current_user, :admin_merge_request, @project)
- page_title "Merge Requests"
- unless @project.default_issues_tracker?
= content_for :sub_nav do
= render "projects/merge_requests/head"
= render 'projects/last_push'
- content_for :page_specific_javascripts do
......
......@@ -18,7 +18,7 @@
Select merge moment
%ul.js-merge-dropdown.dropdown-menu.dropdown-menu-right{ role: 'menu' }
%li
= link_to "#", class: "merge_when_pipeline_succeeds" do
= link_to "#", class: "merge-when-pipeline-succeeds" do
= icon('check fw')
Merge when pipeline succeeds
%li
......
- @no_container = true
- page_title "Edit", @milestone.title, "Milestones"
= render "projects/issues/head"
= render "shared/mr_head"
%div{ class: container_class }
......
- @no_container = true
- page_title 'Milestones'
= render 'projects/issues/head'
= render "shared/mr_head"
%div{ class: container_class }
.top-area
......
- @no_container = true
- page_title "New Milestone"
= render "projects/issues/head"
= render "shared/mr_head"
%div{ class: container_class }
%h3.page-title
......
- @no_container = true
- page_title @milestone.title, "Milestones"
- page_description @milestone.description
= render "projects/issues/head"
= render "shared/mr_head"
%div{ class: container_class }
.detail-page-header.milestone-page-header
......
......@@ -4,7 +4,7 @@
= icon('chevron-down', 'aria-hidden': 'true')
= 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
= link_to namespace_project_container_registry_path(@project.namespace, @project, image),
......
%tr.tag
%td
= escape_once(tag.name)
= clipboard_button(text: "docker pull #{tag.path}")
= clipboard_button(text: "docker pull #{tag.location}")
%td
- if 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
include BuildQueue
def perform(build_id)
Ci::Build.find_by(id: build_id)
.try(:update_coverage)
Ci::Build.find_by(id: build_id)&.update_coverage
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
var ROOT_PATH = path.resolve(__dirname, '..');
var IS_PRODUCTION = process.env.NODE_ENV === 'production';
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_LIVERELOAD = process.env.DEV_SERVER_LIVERELOAD !== 'false';
var WEBPACK_REPORT = process.env.WEBPACK_REPORT;
......@@ -187,12 +188,13 @@ if (IS_PRODUCTION) {
if (IS_DEV_SERVER) {
config.devtool = 'cheap-module-eval-source-map';
config.devServer = {
host: DEV_SERVER_HOST,
port: DEV_SERVER_PORT,
headers: { 'Access-Control-Allow-Origin': '*' },
stats: 'errors-only',
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(
// watch node_modules for changes if we encounter a missing module compile error
new WatchMissingNodeModulesPlugin(path.join(ROOT_PATH, 'node_modules'))
......
......@@ -223,7 +223,9 @@ class Gitlab::Seeder::CycleAnalytics
end
Gitlab::Seeder.quiet do
if ENV['SEED_CYCLE_ANALYTICS']
flag = 'SEED_CYCLE_ANALYTICS'
if ENV[flag]
Project.all.each do |project|
seeder = Gitlab::Seeder::CycleAnalytics.new(project)
seeder.seed!
......@@ -235,6 +237,6 @@ Gitlab::Seeder.quiet do
seeder = Gitlab::Seeder::CycleAnalytics.new(Project.order(:id).first, perf: true)
seeder.seed_metrics!
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
......@@ -27,43 +27,49 @@ end
Sidekiq::Testing.inline! do
Gitlab::Seeder.quiet do
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'
]
flag = 'SEED_NESTED_GROUPS'
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|
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)
user = User.admins.first
params = {
import_url: url,
namespace_id: group.id,
path: project_path,
name: project_path,
description: FFaker::Lorem.sentence,
visibility_level: Gitlab::VisibilityLevel.values.sample
}
project_urls.each_with_index do |url, i|
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)
project = Projects::CreateService.new(user, params).execute
project.send(:_run_after_commit_queue)
params = {
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?
print '.'
else
print 'F'
project = Projects::CreateService.new(user, params).execute
project.send(:_run_after_commit_queue)
if project.valid?
print '.'
else
print 'F'
end
end
else
puts "Skipped. Use the `#{flag}` environment variable to enable."
end
end
end
# rubocop:disable all
class ConvertClosedToStateInIssue < ActiveRecord::Migration
include Gitlab::Database
include Gitlab::Database::MigrationHelpers
def up
execute "UPDATE #{table_name} SET state = 'closed' WHERE closed = #{true_value}"
......
# rubocop:disable all
class ConvertClosedToStateInMergeRequest < ActiveRecord::Migration
include Gitlab::Database
include Gitlab::Database::MigrationHelpers
def up
execute "UPDATE #{table_name} SET state = 'merged' WHERE closed = #{true_value} AND merged = #{true_value}"
......
# rubocop:disable all
class ConvertClosedToStateInMilestone < ActiveRecord::Migration
include Gitlab::Database
include Gitlab::Database::MigrationHelpers
def up
execute "UPDATE #{table_name} SET state = 'closed' WHERE closed = #{true_value}"
......
# rubocop:disable all
class UserColorScheme < ActiveRecord::Migration
include Gitlab::Database
include Gitlab::Database::MigrationHelpers
def up
add_column :users, :color_scheme_id, :integer, null: false, default: 1
......
# rubocop:disable all
class AddVisibilityLevelToProjects < ActiveRecord::Migration
include Gitlab::Database
include Gitlab::Database::MigrationHelpers
def self.up
add_column :projects, :visibility_level, :integer, :default => 0, :null => false
......
# rubocop:disable all
class MigrateAlreadyImportedProjects < ActiveRecord::Migration
include Gitlab::Database
include Gitlab::Database::MigrationHelpers
def up
execute("UPDATE projects SET import_status = 'finished' WHERE imported = #{true_value}")
......
# rubocop:disable all
class AddVisibilityLevelToSnippet < ActiveRecord::Migration
include Gitlab::Database
include Gitlab::Database::MigrationHelpers
def up
add_column :snippets, :visibility_level, :integer, :default => 0, :null => false
......
# rubocop:disable all
class MigrateCiWebHooks < ActiveRecord::Migration
include Gitlab::Database
include Gitlab::Database::MigrationHelpers
def up
execute(
......
# rubocop:disable all
class MigrateCiEmails < ActiveRecord::Migration
include Gitlab::Database
include Gitlab::Database::MigrationHelpers
def up
# This inserts a new service: BuildsEmailService
......
# rubocop:disable all
class MigrateCiSlackService < ActiveRecord::Migration
include Gitlab::Database
include Gitlab::Database::MigrationHelpers
def up
properties_query = 'SELECT properties FROM ci_services ' \
......
# rubocop:disable all
class MigrateCiHipChatService < ActiveRecord::Migration
include Gitlab::Database
include Gitlab::Database::MigrationHelpers
def up
# 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
include Gitlab::Database::MigrationHelpers
include Gitlab::Database
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
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_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_triggers", "users", column: "owner_id", name: "fk_e8e10d1964", on_delete: :cascade
add_foreign_key "container_repositories", "projects"
......
......@@ -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)
- **Blog posts**
- [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/)
- [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/)
- [Using GitLab CI for iOS projects](https://about.gitlab.com/2016/03/10/setting-up-gitlab-ci-for-ios-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 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/)
- [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/)
......
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`:
```haml
- content_for :page_specific_javascripts do
= page_specific_javascript_bundle_tag('lib_chart')
= page_specific_javascript_bundle_tag('graphs')
= webpack_bundle_tag 'lib_chart'
= webpack_bundle_tag 'graphs'
```
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.
## Karma test suite
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
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
`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
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.
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
JavaScript enabled:
```ruby
# For one spec
it 'presents information about abuse report', js: true do
# assertions...
it 'presents information about abuse report', :js do
# assertions...
end
describe "Admin::AbuseReports", js: true do
it 'presents information about abuse report' do
# assertions...
end
it 'shows buttons for adding to abuse report' do
# assertions...
end
describe "Admin::AbuseReports", :js do
it 'presents information about abuse report' do
# assertions...
end
it 'shows buttons for adding to abuse report' do
# assertions...
end
end
```
......@@ -113,13 +121,12 @@ file for the failing spec, add the `@javascript` flag above the Scenario:
```
@javascript
Scenario: Developer can approve merge request
Given I am a "Shop" developer
And I visit project "Shop" merge requests page
And merge request 'Bug NS-04' must be approved
And I click link "Bug NS-04"
When I click link "Approve"
Then I should see approved merge request "Bug NS-04"
Given I am a "Shop" developer
And I visit project "Shop" merge requests page
And merge request 'Bug NS-04' must be approved
And I click link "Bug NS-04"
When I click link "Approve"
Then I should see approved merge request "Bug NS-04"
```
[capybara]: http://teamcapybara.github.io/capybara/
......
......@@ -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
many years of data in their database.
In addition, having to take a server offline for a an upgrade small or big is
a 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.
In addition, having to take a server offline for a a upgrade small or big is a
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 should not require GitLab installations to be taken offline unless
_absolutely_ necessary - see the ["What Requires Downtime?"](what_requires_downtime.md)
page. If a migration requires downtime, this should be clearly mentioned during
the review process, as well as being documented in the monthly release post. For
more information, see the "Downtime Tagging" section below.
Migrations are **not** allowed to require GitLab installations to be taken
offline unless _absolutely necessary_. Downtime assumptions should be based on
the behaviour of a migration when performed using PostgreSQL, as various
operations in MySQL may require downtime without there being alternatives.
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
or inconsistencies and guard for that. Try to make as little assumptions as possible
about the state of the database.
or inconsistencies and guard for that. Try to make as few assumptions as
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.
If needed copy-paste GitLab code into the migration to make it forward compatible.
Each migration **must** be added in its own commit with a descriptive commit
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
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
following two constants to the migration class' body:
require downtime it must also specify a reason for this. This is required even
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.
......@@ -50,12 +75,53 @@ from a migration class.
## 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.
In your migration, add a comment describing how the reversibility of the
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
When removing an index make sure to use the method `remove_concurrent_index` instead
......@@ -78,7 +144,10 @@ end
## 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
of the regular `add_index` method. The `add_concurrent_index` method
......@@ -90,17 +159,22 @@ so:
```ruby
class MyMigration < ActiveRecord::Migration
include Gitlab::Database::MigrationHelpers
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
```
## 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
requiring downtime. This method is not reversible so you must manually define
the `up` and `down` methods in your migration class.
......@@ -123,6 +197,9 @@ class MyMigration < ActiveRecord::Migration
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
......@@ -147,13 +224,15 @@ add_column(:projects, :foo, :integer, default: 10, limit: 8)
## 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.
## 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:
......@@ -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(",")})")
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
### Clone the Source
# 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
......@@ -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
# If you are using non-default settings you need to update config.toml
sudo -u git -H editor config.toml
# Enable Gitaly in the init script
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
through our regular docs, and, when available, through articles (guides,
tutorials, technical overviews, blog posts) and videos.
- [GitLab Installation](../install/README.md)
- [Authentication](authentication/index.md)
- [Continuous Integration (GitLab CI)](../ci/README.md)
- [Git](git/index.md)
- [GitLab Installation](../install/README.md)
- [GitLab Pages](../user/project/pages/index.md)
>**Note:**
Non-linked topics are currently under development and subjected to change.
More topics will be available soon.
>**Note:** More topics will be available soon.
# 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
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
......
......@@ -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
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
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