Merge branch 'master' into 'bootstrap4'
# Conflicts: # app/views/ci/variables/_variable_row.html.haml
This commit is contained in:
commit
2272e95acd
157 changed files with 1572 additions and 652 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -72,3 +72,4 @@ eslint-report.html
|
|||
/locale/**/*.time_stamp
|
||||
/.rspec
|
||||
/plugins/*
|
||||
/.gitlab_pages_secret
|
||||
|
|
|
@ -110,7 +110,7 @@ stages:
|
|||
# Jobs that only need to pull cache
|
||||
.dedicated-no-docs-pull-cache-job: &dedicated-no-docs-pull-cache-job
|
||||
<<: *dedicated-runner
|
||||
<<: *except-docs-and-qa
|
||||
<<: *except-docs
|
||||
<<: *pull-cache
|
||||
dependencies:
|
||||
- setup-test-env
|
||||
|
@ -122,6 +122,10 @@ stages:
|
|||
variables:
|
||||
SETUP_DB: "false"
|
||||
|
||||
.dedicated-no-docs-and-no-qa-pull-cache-job: &dedicated-no-docs-and-no-qa-pull-cache-job
|
||||
<<: *dedicated-no-docs-pull-cache-job
|
||||
<<: *except-docs-and-qa
|
||||
|
||||
.rake-exec: &rake-exec
|
||||
<<: *dedicated-no-docs-no-db-pull-cache-job
|
||||
script:
|
||||
|
@ -222,7 +226,7 @@ stages:
|
|||
- master@gitlab/gitlab-ee
|
||||
|
||||
.gitlab-setup: &gitlab-setup
|
||||
<<: *dedicated-no-docs-pull-cache-job
|
||||
<<: *dedicated-no-docs-and-no-qa-pull-cache-job
|
||||
<<: *use-pg
|
||||
variables:
|
||||
CREATE_DB_USER: "true"
|
||||
|
@ -262,12 +266,12 @@ stages:
|
|||
|
||||
# DB migration, rollback, and seed jobs
|
||||
.db-migrate-reset: &db-migrate-reset
|
||||
<<: *dedicated-no-docs-pull-cache-job
|
||||
<<: *dedicated-no-docs-and-no-qa-pull-cache-job
|
||||
script:
|
||||
- bundle exec rake db:migrate:reset
|
||||
|
||||
.migration-paths: &migration-paths
|
||||
<<: *dedicated-no-docs-pull-cache-job
|
||||
<<: *dedicated-no-docs-and-no-qa-pull-cache-job
|
||||
variables:
|
||||
CREATE_DB_USER: "true"
|
||||
script:
|
||||
|
@ -647,7 +651,7 @@ migration:path-mysql:
|
|||
<<: *use-mysql
|
||||
|
||||
.db-rollback: &db-rollback
|
||||
<<: *dedicated-no-docs-pull-cache-job
|
||||
<<: *dedicated-no-docs-and-no-qa-pull-cache-job
|
||||
script:
|
||||
- bundle exec rake db:migrate VERSION=20170523121229
|
||||
- bundle exec rake db:migrate
|
||||
|
@ -670,7 +674,7 @@ gitlab:setup-mysql:
|
|||
|
||||
# Frontend-related jobs
|
||||
gitlab:assets:compile:
|
||||
<<: *dedicated-no-docs-no-db-pull-cache-job
|
||||
<<: *dedicated-no-docs-and-no-qa-pull-cache-job
|
||||
dependencies: []
|
||||
variables:
|
||||
NODE_ENV: "production"
|
||||
|
@ -691,7 +695,7 @@ gitlab:assets:compile:
|
|||
- webpack-report/
|
||||
|
||||
karma:
|
||||
<<: *dedicated-no-docs-pull-cache-job
|
||||
<<: *dedicated-no-docs-and-no-qa-pull-cache-job
|
||||
<<: *use-pg
|
||||
dependencies:
|
||||
- compile-assets
|
||||
|
@ -815,7 +819,7 @@ coverage:
|
|||
- coverage/assets/
|
||||
|
||||
lint:javascript:report:
|
||||
<<: *dedicated-no-docs-no-db-pull-cache-job
|
||||
<<: *dedicated-no-docs-and-no-qa-pull-cache-job
|
||||
stage: post-test
|
||||
dependencies:
|
||||
- compile-assets
|
||||
|
|
|
@ -1 +1 @@
|
|||
0.8.0
|
||||
0.9.1
|
||||
|
|
3
Gemfile
3
Gemfile
|
@ -51,7 +51,6 @@ gem 'omniauth-shibboleth', '~> 1.2.0'
|
|||
gem 'omniauth-twitter', '~> 1.4'
|
||||
gem 'omniauth_crowd', '~> 2.2.0'
|
||||
gem 'omniauth-authentiq', '~> 0.3.1'
|
||||
gem 'omniauth-jwt', '~> 0.0.2'
|
||||
gem 'rack-oauth2', '~> 1.2.1'
|
||||
gem 'jwt', '~> 1.5.6'
|
||||
|
||||
|
@ -415,7 +414,7 @@ end
|
|||
|
||||
# Gitaly GRPC client
|
||||
gem 'gitaly-proto', '~> 0.97.0', require: 'gitaly'
|
||||
gem 'grpc', '~> 1.10.0'
|
||||
gem 'grpc', '~> 1.11.0'
|
||||
|
||||
# Locked until https://github.com/google/protobuf/issues/4210 is closed
|
||||
gem 'google-protobuf', '= 3.5.1'
|
||||
|
|
|
@ -374,7 +374,7 @@ GEM
|
|||
rake
|
||||
grape_logging (1.7.0)
|
||||
grape
|
||||
grpc (1.10.0)
|
||||
grpc (1.11.0)
|
||||
google-protobuf (~> 3.1)
|
||||
googleapis-common-protos-types (~> 1.0.0)
|
||||
googleauth (>= 0.5.1, < 0.7)
|
||||
|
@ -555,9 +555,6 @@ GEM
|
|||
jwt (>= 1.5)
|
||||
omniauth (>= 1.1.1)
|
||||
omniauth-oauth2 (>= 1.5)
|
||||
omniauth-jwt (0.0.2)
|
||||
jwt
|
||||
omniauth (~> 1.1)
|
||||
omniauth-kerberos (0.3.0)
|
||||
omniauth-multipassword
|
||||
timfel-krb5-auth (~> 0.8)
|
||||
|
@ -1076,7 +1073,7 @@ DEPENDENCIES
|
|||
grape-entity (~> 0.6.0)
|
||||
grape-route-helpers (~> 2.1.0)
|
||||
grape_logging (~> 1.7)
|
||||
grpc (~> 1.10.0)
|
||||
grpc (~> 1.11.0)
|
||||
haml_lint (~> 0.26.0)
|
||||
hamlit (~> 2.6.1)
|
||||
hashie-forbidden_attributes
|
||||
|
@ -1117,7 +1114,6 @@ DEPENDENCIES
|
|||
omniauth-github (~> 1.1.1)
|
||||
omniauth-gitlab (~> 1.0.2)
|
||||
omniauth-google-oauth2 (~> 0.5.3)
|
||||
omniauth-jwt (~> 0.0.2)
|
||||
omniauth-kerberos (~> 0.3.0)
|
||||
omniauth-oauth2-generic (~> 0.2.2)
|
||||
omniauth-saml (~> 1.10)
|
||||
|
|
|
@ -1,66 +1,70 @@
|
|||
<script>
|
||||
import { n__ } from '~/locale';
|
||||
import statusIcon from '../mr_widget_status_icon.vue';
|
||||
import eventHub from '../../event_hub';
|
||||
import { n__ } from '~/locale';
|
||||
import statusIcon from '../mr_widget_status_icon.vue';
|
||||
import eventHub from '../../event_hub';
|
||||
|
||||
export default {
|
||||
name: 'MRWidgetFailedToMerge',
|
||||
export default {
|
||||
name: 'MRWidgetFailedToMerge',
|
||||
|
||||
components: {
|
||||
statusIcon,
|
||||
components: {
|
||||
statusIcon,
|
||||
},
|
||||
|
||||
props: {
|
||||
mr: {
|
||||
type: Object,
|
||||
required: true,
|
||||
default: () => ({}),
|
||||
},
|
||||
},
|
||||
|
||||
props: {
|
||||
mr: {
|
||||
type: Object,
|
||||
required: true,
|
||||
default: () => ({}),
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
timer: 10,
|
||||
isRefreshing: false,
|
||||
intervalId: null,
|
||||
};
|
||||
},
|
||||
|
||||
computed: {
|
||||
timerText() {
|
||||
return n__(
|
||||
'Refreshing in a second to show the updated status...',
|
||||
'Refreshing in %d seconds to show the updated status...',
|
||||
this.timer,
|
||||
);
|
||||
},
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
timer: 10,
|
||||
isRefreshing: false,
|
||||
};
|
||||
mounted() {
|
||||
this.intervalId = setInterval(this.updateTimer, 1000);
|
||||
},
|
||||
|
||||
created() {
|
||||
eventHub.$emit('DisablePolling');
|
||||
},
|
||||
|
||||
beforeDestroy() {
|
||||
if (this.intervalId) {
|
||||
clearInterval(this.intervalId);
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
refresh() {
|
||||
this.isRefreshing = true;
|
||||
eventHub.$emit('MRWidgetUpdateRequested');
|
||||
eventHub.$emit('EnablePolling');
|
||||
},
|
||||
updateTimer() {
|
||||
this.timer = this.timer - 1;
|
||||
|
||||
computed: {
|
||||
timerText() {
|
||||
return n__(
|
||||
'Refreshing in a second to show the updated status...',
|
||||
'Refreshing in %d seconds to show the updated status...',
|
||||
this.timer,
|
||||
);
|
||||
},
|
||||
if (this.timer === 0) {
|
||||
this.refresh();
|
||||
}
|
||||
},
|
||||
|
||||
mounted() {
|
||||
setInterval(() => {
|
||||
this.updateTimer();
|
||||
}, 1000);
|
||||
},
|
||||
|
||||
created() {
|
||||
eventHub.$emit('DisablePolling');
|
||||
},
|
||||
|
||||
methods: {
|
||||
refresh() {
|
||||
this.isRefreshing = true;
|
||||
eventHub.$emit('MRWidgetUpdateRequested');
|
||||
eventHub.$emit('EnablePolling');
|
||||
},
|
||||
updateTimer() {
|
||||
this.timer = this.timer - 1;
|
||||
|
||||
if (this.timer === 0) {
|
||||
this.refresh();
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
};
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<template>
|
||||
<div class="mr-widget-body media">
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
class ListLabel {
|
||||
export default class ListLabel {
|
||||
constructor(obj) {
|
||||
this.id = obj.id;
|
||||
this.title = obj.title;
|
||||
|
|
|
@ -14,6 +14,7 @@ class PipelinesFinder
|
|||
items = by_scope(items)
|
||||
items = by_status(items)
|
||||
items = by_ref(items)
|
||||
items = by_sha(items)
|
||||
items = by_name(items)
|
||||
items = by_username(items)
|
||||
items = by_yaml_errors(items)
|
||||
|
@ -69,6 +70,14 @@ class PipelinesFinder
|
|||
end
|
||||
end
|
||||
|
||||
def by_sha(items)
|
||||
if params[:sha].present?
|
||||
items.where(sha: params[:sha])
|
||||
else
|
||||
items
|
||||
end
|
||||
end
|
||||
|
||||
def by_name(items)
|
||||
if params[:name].present?
|
||||
items.joins(:user).where(users: { name: params[:name] })
|
||||
|
|
|
@ -41,7 +41,7 @@ module DropdownsHelper
|
|||
|
||||
def dropdown_toggle(toggle_text, data_attr, options = {})
|
||||
default_label = data_attr[:default_label]
|
||||
content_tag(:button, class: "dropdown-menu-toggle #{options[:toggle_class] if options.key?(:toggle_class)}", id: (options[:id] if options.key?(:id)), type: "button", data: data_attr) do
|
||||
content_tag(:button, disabled: options[:disabled], class: "dropdown-menu-toggle #{options[:toggle_class] if options.key?(:toggle_class)}", id: (options[:id] if options.key?(:id)), type: "button", data: data_attr) do
|
||||
output = content_tag(:span, toggle_text, class: "dropdown-toggle-text #{'is-default' if toggle_text == default_label}")
|
||||
output << icon('chevron-down')
|
||||
output.html_safe
|
||||
|
|
|
@ -37,20 +37,20 @@ class GroupMember < Member
|
|||
private
|
||||
|
||||
def send_invite
|
||||
notification_service.invite_group_member(self, @raw_invite_token)
|
||||
run_after_commit_or_now { notification_service.invite_group_member(self, @raw_invite_token) }
|
||||
|
||||
super
|
||||
end
|
||||
|
||||
def post_create_hook
|
||||
notification_service.new_group_member(self)
|
||||
run_after_commit_or_now { notification_service.new_group_member(self) }
|
||||
|
||||
super
|
||||
end
|
||||
|
||||
def post_update_hook
|
||||
if access_level_changed?
|
||||
notification_service.update_group_member(self)
|
||||
run_after_commit { notification_service.update_group_member(self) }
|
||||
end
|
||||
|
||||
super
|
||||
|
|
|
@ -92,7 +92,7 @@ class ProjectMember < Member
|
|||
private
|
||||
|
||||
def send_invite
|
||||
notification_service.invite_project_member(self, @raw_invite_token)
|
||||
run_after_commit_or_now { notification_service.invite_project_member(self, @raw_invite_token) }
|
||||
|
||||
super
|
||||
end
|
||||
|
@ -100,7 +100,7 @@ class ProjectMember < Member
|
|||
def post_create_hook
|
||||
unless owner?
|
||||
event_service.join_project(self.project, self.user)
|
||||
notification_service.new_project_member(self)
|
||||
run_after_commit_or_now { notification_service.new_project_member(self) }
|
||||
end
|
||||
|
||||
super
|
||||
|
@ -108,7 +108,7 @@ class ProjectMember < Member
|
|||
|
||||
def post_update_hook
|
||||
if access_level_changed?
|
||||
notification_service.update_project_member(self)
|
||||
run_after_commit { notification_service.update_project_member(self) }
|
||||
end
|
||||
|
||||
super
|
||||
|
|
|
@ -26,7 +26,7 @@ module Issues
|
|||
issue.update(closed_by: current_user)
|
||||
event_service.close_issue(issue, current_user)
|
||||
create_note(issue, commit) if system_note
|
||||
notification_service.close_issue(issue, current_user) if notifications
|
||||
notification_service.async.close_issue(issue, current_user) if notifications
|
||||
todo_service.close_issue(issue, current_user)
|
||||
execute_hooks(issue, 'close')
|
||||
invalidate_cache_counts(issue, users: issue.assignees)
|
||||
|
|
|
@ -139,7 +139,7 @@ module Issues
|
|||
end
|
||||
|
||||
def notify_participants
|
||||
notification_service.issue_moved(@old_issue, @new_issue, @current_user)
|
||||
notification_service.async.issue_moved(@old_issue, @new_issue, @current_user)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -6,7 +6,7 @@ module Issues
|
|||
if issue.reopen
|
||||
event_service.reopen_issue(issue, current_user)
|
||||
create_note(issue, 'reopened')
|
||||
notification_service.reopen_issue(issue, current_user)
|
||||
notification_service.async.reopen_issue(issue, current_user)
|
||||
execute_hooks(issue, 'reopen')
|
||||
invalidate_cache_counts(issue, users: issue.assignees)
|
||||
issue.update_project_counter_caches
|
||||
|
|
|
@ -30,7 +30,7 @@ module Issues
|
|||
|
||||
if issue.assignees != old_assignees
|
||||
create_assignee_note(issue, old_assignees)
|
||||
notification_service.reassigned_issue(issue, current_user, old_assignees)
|
||||
notification_service.async.reassigned_issue(issue, current_user, old_assignees)
|
||||
todo_service.reassigned_issue(issue, current_user, old_assignees)
|
||||
end
|
||||
|
||||
|
@ -41,13 +41,13 @@ module Issues
|
|||
added_labels = issue.labels - old_labels
|
||||
|
||||
if added_labels.present?
|
||||
notification_service.relabeled_issue(issue, added_labels, current_user)
|
||||
notification_service.async.relabeled_issue(issue, added_labels, current_user)
|
||||
end
|
||||
|
||||
added_mentions = issue.mentioned_users - old_mentioned_users
|
||||
|
||||
if added_mentions.present?
|
||||
notification_service.new_mentions_in_issue(issue, added_mentions, current_user)
|
||||
notification_service.async.new_mentions_in_issue(issue, added_mentions, current_user)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@ module MergeRequests
|
|||
if merge_request.close
|
||||
create_event(merge_request)
|
||||
create_note(merge_request)
|
||||
notification_service.close_mr(merge_request, current_user)
|
||||
notification_service.async.close_mr(merge_request, current_user)
|
||||
todo_service.close_merge_request(merge_request, current_user)
|
||||
execute_hooks(merge_request, 'close')
|
||||
invalidate_cache_counts(merge_request, users: merge_request.assignees)
|
||||
|
|
|
@ -6,7 +6,7 @@ module MergeRequests
|
|||
if merge_request.reopen
|
||||
create_event(merge_request)
|
||||
create_note(merge_request, 'reopened')
|
||||
notification_service.reopen_mr(merge_request, current_user)
|
||||
notification_service.async.reopen_mr(merge_request, current_user)
|
||||
execute_hooks(merge_request, 'reopen')
|
||||
merge_request.reload_diff(current_user)
|
||||
merge_request.mark_as_unchecked
|
||||
|
|
|
@ -4,7 +4,7 @@ module MergeRequests
|
|||
return unless merge_request.discussions_resolved?
|
||||
|
||||
SystemNoteService.resolve_all_discussions(merge_request, project, current_user)
|
||||
notification_service.resolve_all_discussions(merge_request, current_user)
|
||||
notification_service.async.resolve_all_discussions(merge_request, current_user)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -21,6 +21,7 @@ module MergeRequests
|
|||
update(merge_request)
|
||||
end
|
||||
|
||||
# rubocop:disable Metrics/AbcSize
|
||||
def handle_changes(merge_request, options)
|
||||
old_associations = options.fetch(:old_associations, {})
|
||||
old_labels = old_associations.fetch(:labels, [])
|
||||
|
@ -42,8 +43,11 @@ module MergeRequests
|
|||
end
|
||||
|
||||
if merge_request.previous_changes.include?('assignee_id')
|
||||
old_assignee_id = merge_request.previous_changes['assignee_id'].first
|
||||
old_assignee = User.find(old_assignee_id) if old_assignee_id
|
||||
|
||||
create_assignee_note(merge_request)
|
||||
notification_service.reassigned_merge_request(merge_request, current_user)
|
||||
notification_service.async.reassigned_merge_request(merge_request, current_user, old_assignee)
|
||||
todo_service.reassigned_merge_request(merge_request, current_user)
|
||||
end
|
||||
|
||||
|
@ -54,7 +58,7 @@ module MergeRequests
|
|||
|
||||
added_labels = merge_request.labels - old_labels
|
||||
if added_labels.present?
|
||||
notification_service.relabeled_merge_request(
|
||||
notification_service.async.relabeled_merge_request(
|
||||
merge_request,
|
||||
added_labels,
|
||||
current_user
|
||||
|
@ -63,13 +67,14 @@ module MergeRequests
|
|||
|
||||
added_mentions = merge_request.mentioned_users - old_mentioned_users
|
||||
if added_mentions.present?
|
||||
notification_service.new_mentions_in_merge_request(
|
||||
notification_service.async.new_mentions_in_merge_request(
|
||||
merge_request,
|
||||
added_mentions,
|
||||
current_user
|
||||
)
|
||||
end
|
||||
end
|
||||
# rubocop:enable Metrics/AbcSize
|
||||
|
||||
def merge_from_quick_action(merge_request)
|
||||
last_diff_sha = params.delete(:merge)
|
||||
|
|
|
@ -7,7 +7,32 @@
|
|||
# Ex.
|
||||
# NotificationService.new.new_issue(issue, current_user)
|
||||
#
|
||||
# When calculating the recipients of a notification is expensive (for instance,
|
||||
# in the new issue case), `#async` will make that calculation happen in Sidekiq
|
||||
# instead:
|
||||
#
|
||||
# NotificationService.new.async.new_issue(issue, current_user)
|
||||
#
|
||||
class NotificationService
|
||||
class Async
|
||||
attr_reader :parent
|
||||
delegate :respond_to_missing, to: :parent
|
||||
|
||||
def initialize(parent)
|
||||
@parent = parent
|
||||
end
|
||||
|
||||
def method_missing(meth, *args)
|
||||
return super unless parent.respond_to?(meth)
|
||||
|
||||
MailScheduler::NotificationServiceWorker.perform_async(meth.to_s, *args)
|
||||
end
|
||||
end
|
||||
|
||||
def async
|
||||
@async ||= Async.new(self)
|
||||
end
|
||||
|
||||
# Always notify user about ssh key added
|
||||
# only if ssh key is not deploy key
|
||||
#
|
||||
|
@ -142,8 +167,23 @@ class NotificationService
|
|||
# * merge_request assignee if their notification level is not Disabled
|
||||
# * users with custom level checked with "reassign merge request"
|
||||
#
|
||||
def reassigned_merge_request(merge_request, current_user)
|
||||
reassign_resource_email(merge_request, current_user, :reassigned_merge_request_email)
|
||||
def reassigned_merge_request(merge_request, current_user, previous_assignee)
|
||||
recipients = NotificationRecipientService.build_recipients(
|
||||
merge_request,
|
||||
current_user,
|
||||
action: "reassign",
|
||||
previous_assignee: previous_assignee
|
||||
)
|
||||
|
||||
recipients.each do |recipient|
|
||||
mailer.reassigned_merge_request_email(
|
||||
recipient.user.id,
|
||||
merge_request.id,
|
||||
previous_assignee&.id,
|
||||
current_user.id,
|
||||
recipient.reason
|
||||
).deliver_later
|
||||
end
|
||||
end
|
||||
|
||||
# When we add labels to a merge request we should send an email to:
|
||||
|
@ -421,29 +461,6 @@ class NotificationService
|
|||
end
|
||||
end
|
||||
|
||||
def reassign_resource_email(target, current_user, method)
|
||||
previous_assignee_id = previous_record(target, 'assignee_id')
|
||||
previous_assignee = User.find_by(id: previous_assignee_id) if previous_assignee_id
|
||||
|
||||
recipients = NotificationRecipientService.build_recipients(
|
||||
target,
|
||||
current_user,
|
||||
action: "reassign",
|
||||
previous_assignee: previous_assignee
|
||||
)
|
||||
|
||||
recipients.each do |recipient|
|
||||
mailer.send(
|
||||
method,
|
||||
recipient.user.id,
|
||||
target.id,
|
||||
previous_assignee_id,
|
||||
current_user.id,
|
||||
recipient.reason
|
||||
).deliver_later
|
||||
end
|
||||
end
|
||||
|
||||
def relabeled_resource_email(target, labels, current_user, method)
|
||||
recipients = labels.flat_map { |l| l.subscribers(target.project) }.uniq
|
||||
recipients = notifiable_users(
|
||||
|
@ -471,14 +488,6 @@ class NotificationService
|
|||
Notify
|
||||
end
|
||||
|
||||
def previous_record(object, attribute)
|
||||
return unless object && attribute
|
||||
|
||||
if object.previous_changes.include?(attribute)
|
||||
object.previous_changes[attribute].first
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def recipients_for_pages_domain(domain)
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
module Projects
|
||||
class UpdatePagesService < BaseService
|
||||
InvaildStateError = Class.new(StandardError)
|
||||
InvalidStateError = Class.new(StandardError)
|
||||
FailedToExtractError = Class.new(StandardError)
|
||||
|
||||
BLOCK_SIZE = 32.kilobytes
|
||||
|
@ -21,8 +21,8 @@ module Projects
|
|||
@status.enqueue!
|
||||
@status.run!
|
||||
|
||||
raise InvaildStateError, 'missing pages artifacts' unless build.artifacts?
|
||||
raise InvaildStateError, 'pages are outdated' unless latest?
|
||||
raise InvalidStateError, 'missing pages artifacts' unless build.artifacts?
|
||||
raise InvalidStateError, 'pages are outdated' unless latest?
|
||||
|
||||
# Create temporary directory in which we will extract the artifacts
|
||||
FileUtils.mkdir_p(tmp_path)
|
||||
|
@ -31,16 +31,16 @@ module Projects
|
|||
|
||||
# Check if we did extract public directory
|
||||
archive_public_path = File.join(archive_path, 'public')
|
||||
raise InvaildStateError, 'pages miss the public folder' unless Dir.exist?(archive_public_path)
|
||||
raise InvaildStateError, 'pages are outdated' unless latest?
|
||||
raise InvalidStateError, 'pages miss the public folder' unless Dir.exist?(archive_public_path)
|
||||
raise InvalidStateError, 'pages are outdated' unless latest?
|
||||
|
||||
deploy_page!(archive_public_path)
|
||||
success
|
||||
end
|
||||
rescue InvaildStateError => e
|
||||
rescue InvalidStateError => e
|
||||
error(e.message)
|
||||
rescue => e
|
||||
error(e.message, false)
|
||||
error(e.message)
|
||||
raise e
|
||||
end
|
||||
|
||||
|
@ -48,17 +48,15 @@ module Projects
|
|||
|
||||
def success
|
||||
@status.success
|
||||
delete_artifact!
|
||||
super
|
||||
end
|
||||
|
||||
def error(message, allow_delete_artifact = true)
|
||||
def error(message)
|
||||
register_failure
|
||||
log_error("Projects::UpdatePagesService: #{message}")
|
||||
@status.allow_failure = !latest?
|
||||
@status.description = message
|
||||
@status.drop(:script_failure)
|
||||
delete_artifact! if allow_delete_artifact
|
||||
super
|
||||
end
|
||||
|
||||
|
@ -77,18 +75,18 @@ module Projects
|
|||
if artifacts.ends_with?('.zip')
|
||||
extract_zip_archive!(temp_path)
|
||||
else
|
||||
raise InvaildStateError, 'unsupported artifacts format'
|
||||
raise InvalidStateError, 'unsupported artifacts format'
|
||||
end
|
||||
end
|
||||
|
||||
def extract_zip_archive!(temp_path)
|
||||
raise InvaildStateError, 'missing artifacts metadata' unless build.artifacts_metadata?
|
||||
raise InvalidStateError, 'missing artifacts metadata' unless build.artifacts_metadata?
|
||||
|
||||
# Calculate page size after extract
|
||||
public_entry = build.artifacts_metadata_entry(SITE_PATH, recursive: true)
|
||||
|
||||
if public_entry.total_size > max_size
|
||||
raise InvaildStateError, "artifacts for pages are too large: #{public_entry.total_size}"
|
||||
raise InvalidStateError, "artifacts for pages are too large: #{public_entry.total_size}"
|
||||
end
|
||||
|
||||
# Requires UnZip at least 6.00 Info-ZIP.
|
||||
|
@ -162,11 +160,6 @@ module Projects
|
|||
build.artifacts_file.path
|
||||
end
|
||||
|
||||
def delete_artifact!
|
||||
build.reload # Reload stable object to prevent erase artifacts with old state
|
||||
build.erase_artifacts! unless build.has_expiring_artifacts?
|
||||
end
|
||||
|
||||
def latest_sha
|
||||
project.commit(build.ref).try(:sha).to_s
|
||||
ensure
|
||||
|
|
|
@ -159,7 +159,7 @@ module SystemNoteService
|
|||
body = if noteable.time_estimate == 0
|
||||
"removed time estimate"
|
||||
else
|
||||
"changed time estimate to #{parsed_time},"
|
||||
"changed time estimate to #{parsed_time}"
|
||||
end
|
||||
|
||||
create_note(NoteSummary.new(noteable, project, author, body, action: 'time_tracking'))
|
||||
|
|
|
@ -17,14 +17,14 @@
|
|||
.ci-variable-row-body
|
||||
%input.js-ci-variable-input-id{ type: "hidden", name: id_input_name, value: id }
|
||||
%input.js-ci-variable-input-destroy{ type: "hidden", name: destroy_input_name }
|
||||
%input.js-ci-variable-input-key.ci-variable-body-item.form-control{ type: "text",
|
||||
%input.js-ci-variable-input-key.ci-variable-body-item.qa-ci-variable-input-key.form-control{ type: "text",
|
||||
name: key_input_name,
|
||||
value: key,
|
||||
placeholder: s_('CiVariables|Input variable key') }
|
||||
.ci-variable-body-item
|
||||
.form-control.js-secret-value-placeholder{ class: ('hidden' unless id) }
|
||||
.form-control.js-secret-value-placeholder.qa-ci-variable-input-value{ class: ('hide' unless id) }
|
||||
= '*' * 20
|
||||
%textarea.js-ci-variable-input-value.js-secret-value.form-control{ class: ('hidden' if id),
|
||||
%textarea.js-ci-variable-input-value.js-secret-value.qa-ci-variable-input-value.form-control{ class: ('hide' if id),
|
||||
rows: 1,
|
||||
name: value_input_name,
|
||||
placeholder: s_('CiVariables|Input variable value') }
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
- can_admin_project = can?(current_user, :admin_project, @project)
|
||||
|
||||
= render layout: 'projects/protected_branches/shared/branches_list', locals: { can_admin_project: can_admin_project } do
|
||||
= render partial: 'projects/protected_branches/protected_branch', collection: @protected_branches, locals: { can_admin_project: can_admin_project}
|
||||
= render partial: 'projects/protected_branches/protected_branch', collection: @protected_branches
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
- content_for :merge_access_levels do
|
||||
.merge_access_levels-container
|
||||
= dropdown_tag('Select',
|
||||
options: { toggle_class: 'js-allowed-to-merge wide',
|
||||
dropdown_class: 'dropdown-menu-selectable capitalize-header',
|
||||
options: { toggle_class: 'js-allowed-to-merge qa-allowed-to-merge-select wide',
|
||||
dropdown_class: 'dropdown-menu-selectable qa-allowed-to-merge-dropdown capitalize-header',
|
||||
data: { field_name: 'protected_branch[merge_access_levels_attributes][0][access_level]', input_id: 'merge_access_levels_attributes' }})
|
||||
- content_for :push_access_levels do
|
||||
.push_access_levels-container
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
%td
|
||||
= hidden_field_tag "allowed_to_merge_#{protected_branch.id}", protected_branch.merge_access_levels.first.access_level
|
||||
= dropdown_tag( (protected_branch.merge_access_levels.first.humanize || 'Select') ,
|
||||
options: { toggle_class: 'js-allowed-to-merge', dropdown_class: 'dropdown-menu-selectable js-allowed-to-merge-container capitalize-header',
|
||||
options: { toggle_class: 'js-allowed-to-merge qa-allowed-to-merge', dropdown_class: 'dropdown-menu-selectable js-allowed-to-merge-container capitalize-header',
|
||||
data: { field_name: "allowed_to_merge_#{protected_branch.id}", access_level_id: protected_branch.merge_access_levels.first.id }})
|
||||
%td
|
||||
= hidden_field_tag "allowed_to_push_#{protected_branch.id}", protected_branch.push_access_levels.first.access_level
|
||||
|
|
|
@ -21,4 +21,4 @@
|
|||
|
||||
- if can_admin_project
|
||||
%td
|
||||
= link_to 'Unprotect', [@project.namespace.becomes(Namespace), @project, protected_branch], data: { confirm: 'Branch will be writable for developers. Are you sure?' }, method: :delete, class: 'btn btn-warning'
|
||||
= link_to 'Unprotect', [@project.namespace.becomes(Namespace), @project, protected_branch], disabled: local_assigns[:disabled], data: { confirm: 'Branch will be writable for developers. Are you sure?' }, method: :delete, class: "btn btn-warning"
|
||||
|
|
|
@ -36,5 +36,6 @@
|
|||
= form.text_field :domain, class: 'form-control', placeholder: 'domain.com'
|
||||
.help-block
|
||||
= s_('CICD|You need to specify a domain if you want to use Auto Review Apps and Auto Deploy stages.')
|
||||
= link_to icon('question-circle'), help_page_path('topics/autodevops/index.md', anchor: 'auto-devops-base-domain'), target: '_blank'
|
||||
|
||||
= f.submit 'Save changes', class: "btn btn-success prepend-top-15"
|
||||
|
|
|
@ -41,6 +41,7 @@
|
|||
- github_importer:github_import_stage_import_repository
|
||||
|
||||
- mail_scheduler:mail_scheduler_issue_due
|
||||
- mail_scheduler:mail_scheduler_notification_service
|
||||
|
||||
- object_storage_upload
|
||||
- object_storage:object_storage_background_move
|
||||
|
|
|
@ -4,4 +4,8 @@ module MailSchedulerQueue
|
|||
included do
|
||||
queue_namespace :mail_scheduler
|
||||
end
|
||||
|
||||
def notification_service
|
||||
@notification_service ||= NotificationService.new
|
||||
end
|
||||
end
|
||||
|
|
|
@ -4,8 +4,6 @@ module MailScheduler
|
|||
include MailSchedulerQueue
|
||||
|
||||
def perform(project_id)
|
||||
notification_service = NotificationService.new
|
||||
|
||||
Issue.opened.due_tomorrow.in_projects(project_id).preload(:project).find_each do |issue|
|
||||
notification_service.issue_due(issue)
|
||||
end
|
||||
|
|
19
app/workers/mail_scheduler/notification_service_worker.rb
Normal file
19
app/workers/mail_scheduler/notification_service_worker.rb
Normal file
|
@ -0,0 +1,19 @@
|
|||
require 'active_job/arguments'
|
||||
|
||||
module MailScheduler
|
||||
class NotificationServiceWorker
|
||||
include ApplicationWorker
|
||||
include MailSchedulerQueue
|
||||
|
||||
def perform(meth, *args)
|
||||
deserialized_args = ActiveJob::Arguments.deserialize(args)
|
||||
|
||||
notification_service.public_send(meth, *deserialized_args) # rubocop:disable GitlabSecurity/PublicSend
|
||||
rescue ActiveJob::DeserializationError
|
||||
end
|
||||
|
||||
def self.perform_async(*args)
|
||||
super(*ActiveJob::Arguments.serialize(args))
|
||||
end
|
||||
end
|
||||
end
|
6
changelogs/unreleased/45481-sane-pages-artifacts.yml
Normal file
6
changelogs/unreleased/45481-sane-pages-artifacts.yml
Normal file
|
@ -0,0 +1,6 @@
|
|||
---
|
||||
title: Don't automatically remove artifacts for pages jobs after pages:deploy has
|
||||
run
|
||||
merge_request: 18628
|
||||
author:
|
||||
type: fixed
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Ensure member notifications are sent after the member actual creation/update in the DB
|
||||
merge_request: 18538
|
||||
author:
|
||||
type: fixed
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Ports omniauth-jwt gem onto GitLab OmniAuth Strategies suite
|
||||
merge_request: 18580
|
||||
author:
|
||||
type: fixed
|
5
changelogs/unreleased/bvl-fix-openid-redirect.yml
Normal file
5
changelogs/unreleased/bvl-fix-openid-redirect.yml
Normal file
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Fix redirection error for applications using OpenID
|
||||
merge_request: 18599
|
||||
author:
|
||||
type: fixed
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Add sha filter to pipelines list API
|
||||
merge_request: 18125
|
||||
author:
|
||||
type: changed
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Compute notification recipients in background jobs
|
||||
merge_request:
|
||||
author:
|
||||
type: performance
|
5
changelogs/unreleased/zj-repository-exist-mandatory.yml
Normal file
5
changelogs/unreleased/zj-repository-exist-mandatory.yml
Normal file
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Repository#exists? is always executed through Gitaly
|
||||
merge_request:
|
||||
author:
|
||||
type: performance
|
|
@ -184,18 +184,18 @@ production: &base
|
|||
# base_dir: uploads/-/system
|
||||
object_store:
|
||||
enabled: false
|
||||
# remote_directory: uploads # Bucket name
|
||||
remote_directory: uploads # Bucket name
|
||||
# direct_upload: false # Use Object Storage directly for uploads instead of background uploads if enabled (Default: false)
|
||||
# background_upload: false # Temporary option to limit automatic upload (Default: true)
|
||||
# proxy_download: false # Passthrough all downloads via GitLab instead of using Redirects to Object Storage
|
||||
connection:
|
||||
provider: AWS
|
||||
aws_access_key_id: AWS_ACCESS_KEY_ID
|
||||
aws_secret_access_key: AWS_SECRET_ACCESS_KEY
|
||||
region: us-east-1
|
||||
# host: 'localhost' # default: s3.amazonaws.com
|
||||
# endpoint: 'http://127.0.0.1:9000' # default: nil
|
||||
# path_style: true # Use 'host/bucket_name/object' instead of 'bucket_name.host/object'
|
||||
connection:
|
||||
provider: AWS
|
||||
aws_access_key_id: AWS_ACCESS_KEY_ID
|
||||
aws_secret_access_key: AWS_SECRET_ACCESS_KEY
|
||||
region: us-east-1
|
||||
# host: 'localhost' # default: s3.amazonaws.com
|
||||
# endpoint: 'http://127.0.0.1:9000' # default: nil
|
||||
# path_style: true # Use 'host/bucket_name/object' instead of 'bucket_name.host/object'
|
||||
|
||||
## GitLab Pages
|
||||
pages:
|
||||
|
@ -212,6 +212,8 @@ production: &base
|
|||
artifacts_server: true
|
||||
# external_http: ["1.1.1.1:80", "[2001::1]:80"] # If defined, enables custom domain support in GitLab Pages
|
||||
# external_https: ["1.1.1.1:443", "[2001::1]:443"] # If defined, enables custom domain and certificate support in GitLab Pages
|
||||
admin:
|
||||
address: unix:/home/git/gitlab/tmp/sockets/private/pages-admin.socket # TCP connections are supported too (e.g. tcp://host:port)
|
||||
|
||||
## Mattermost
|
||||
## For enabling Add to Mattermost button
|
||||
|
@ -532,7 +534,7 @@ production: &base
|
|||
# required_claims: ["name", "email"],
|
||||
# info_map: { name: "name", email: "email" },
|
||||
# auth_url: 'https://example.com/',
|
||||
# valid_within: nil,
|
||||
# valid_within: null,
|
||||
# }
|
||||
# }
|
||||
# - { name: 'saml',
|
||||
|
@ -823,7 +825,7 @@ test:
|
|||
required_claims: ["name", "email"],
|
||||
info_map: { name: "name", email: "email" },
|
||||
auth_url: 'https://example.com/',
|
||||
valid_within: nil,
|
||||
valid_within: null,
|
||||
}
|
||||
}
|
||||
- { name: 'auth0',
|
||||
|
|
|
@ -215,6 +215,9 @@ Settings.pages['external_http'] ||= false unless Settings.pages['external_ht
|
|||
Settings.pages['external_https'] ||= false unless Settings.pages['external_https'].present?
|
||||
Settings.pages['artifacts_server'] ||= Settings.pages['enabled'] if Settings.pages['artifacts_server'].nil?
|
||||
|
||||
Settings.pages['admin'] ||= Settingslogic.new({})
|
||||
Settings.pages.admin['certificate'] ||= ''
|
||||
|
||||
#
|
||||
# Git LFS
|
||||
#
|
||||
|
|
|
@ -104,5 +104,5 @@ Doorkeeper.configure do
|
|||
# set to true if you want this to be allowed
|
||||
# wildcard_redirect_uri false
|
||||
|
||||
base_controller 'ApplicationController'
|
||||
base_controller '::Gitlab::BaseDoorkeeperController'
|
||||
end
|
||||
|
|
|
@ -25,5 +25,6 @@ end
|
|||
module OmniAuth
|
||||
module Strategies
|
||||
autoload :Bitbucket, Rails.root.join('lib', 'omni_auth', 'strategies', 'bitbucket')
|
||||
autoload :Jwt, Rails.root.join('lib', 'omni_auth', 'strategies', 'jwt')
|
||||
end
|
||||
end
|
||||
|
|
2
config/initializers/pages.rb
Normal file
2
config/initializers/pages.rb
Normal file
|
@ -0,0 +1,2 @@
|
|||
Gitlab::PagesClient.read_or_create_token
|
||||
Gitlab::PagesClient.load_certificate
|
|
@ -15,8 +15,8 @@ To understand what features you have access to, check the [GitLab subscriptions]
|
|||
|
||||
| General documentation | GitLab CI/CD docs |
|
||||
| :----- | :----- |
|
||||
| [User documentation](user/index.md) | [GitLab CI/CD](ci/README.md) |
|
||||
| [Administrator documentation](administration/index.md) | [GitLab CI/CD quick start guide](ci/quick_start/README.md) |
|
||||
| [User documentation](user/index.md) | [GitLab CI/CD quick start guide](ci/quick_start/README.md) |
|
||||
| [Administrator documentation](administration/index.md) | [GitLab CI/CD examples](ci/examples/README.md) |
|
||||
| [Contributor documentation](#contributor-documentation) | [Configuring `.gitlab-ci.yml`](ci/yaml/README.md) |
|
||||
| [Getting started with GitLab](#getting-started-with-gitlab) | [Using Docker images](ci/docker/using_docker_images.md) |
|
||||
| [API](api/README.md) | [Auto DevOps](topics/autodevops/index.md) |
|
||||
|
@ -90,6 +90,7 @@ Manage your [repositories](user/project/repository/index.md) from the UI (user i
|
|||
- [Create a file](user/project/repository/web_editor.md#create-a-file)
|
||||
- [Upload a file](user/project/repository/web_editor.md#upload-a-file)
|
||||
- [File templates](user/project/repository/web_editor.md#template-dropdowns)
|
||||
- [Jupyter Notebook files](user/project/repository/index.md#jupyter-notebook-files)
|
||||
- [Create a directory](user/project/repository/web_editor.md#create-a-directory)
|
||||
- [Start a merge request](user/project/repository/web_editor.md#tips) (when committing via UI)
|
||||
- [Branches](user/project/repository/branches/index.md)
|
||||
|
@ -100,6 +101,14 @@ Manage your [repositories](user/project/repository/index.md) from the UI (user i
|
|||
- [Commits](user/project/repository/index.md#commits)
|
||||
- [Signing commits](user/project/repository/gpg_signed_commits/index.md): use GPG to sign your commits.
|
||||
|
||||
#### Merge Requests
|
||||
|
||||
- [Merge Requests](user/project/merge_requests/index.md)
|
||||
- [Work In Progress "WIP" Merge Requests](user/project/merge_requests/work_in_progress_merge_requests.md)
|
||||
- [Merge Request discussion resolution](user/discussions/index.md#moving-a-single-discussion-to-a-new-issue): Resolve discussions, move discussions in a merge request to an issue, only allow merge requests to be merged if all discussions are resolved.
|
||||
- [Checkout merge requests locally](user/project/merge_requests/index.md#checkout-merge-requests-locally)
|
||||
- [Cherry-pick](user/project/merge_requests/cherry_pick_changes.md)
|
||||
|
||||
#### Integrations
|
||||
|
||||
- [Project Services](user/project/integrations/project_services.md): Integrate a project with external services, such as CI and chat.
|
||||
|
@ -113,18 +122,16 @@ Manage your [repositories](user/project/repository/index.md) from the UI (user i
|
|||
|
||||
### Verify
|
||||
|
||||
Spot errors sooner and shorten feedback cycles with built-in code review, code testing,
|
||||
Code Quality, and Review Apps. Customize your approval workflow controls, automatically
|
||||
test the quality of your code, and spin up a staging environment for every code change.
|
||||
GitLab Continuous Integration is the most popular next generation testing system that
|
||||
auto scales to run your tests faster.
|
||||
Spot errors sooner, improve security and shorten feedback cycles with built-in
|
||||
static code analysis, code testing, code quality, dependency checking and review
|
||||
apps. Customize your approval workflow controls, automatically test the quality
|
||||
of your code, and spin up a staging environment for every code change. GitLab
|
||||
Continuous Integration is the most popular next generation testing system that
|
||||
scales to run your tests faster.
|
||||
|
||||
- [Merge Requests](user/project/merge_requests/index.md)
|
||||
- [Work In Progress Merge Requests](user/project/merge_requests/work_in_progress_merge_requests.md)
|
||||
- [Merge Request discussion resolution](user/discussions/index.md#moving-a-single-discussion-to-a-new-issue): Resolve discussions, move discussions in a merge request to an issue, only allow merge requests to be merged if all discussions are resolved.
|
||||
- [Checkout merge requests locally](user/project/merge_requests/index.md#checkout-merge-requests-locally)
|
||||
- [Cherry-pick](user/project/merge_requests/cherry_pick_changes.md)
|
||||
- [GitLab CI/CD](ci/README.md): Explore the features and capabilities of Continuous Integration, Continuous Delivery, and Continuous Deployment with GitLab.
|
||||
- [Review Apps](ci/review_apps/index.md): Preview changes to your app right from a merge request.
|
||||
- [Pipeline Graphs](ci/pipelines.md#pipeline-graphs)
|
||||
|
||||
### Package
|
||||
|
||||
|
@ -132,7 +139,6 @@ GitLab Container Registry gives you the enhanced security and access controls of
|
|||
custom Docker images without 3rd party add-ons. Easily upload and download images
|
||||
from GitLab CI/CD with full Git repository management integration.
|
||||
|
||||
- [GitLab CI/CD](ci/README.md): Explore the features and capabilities of Continuous Integration, Continuous Delivery, and Continuous Deployment with GitLab.
|
||||
- [GitLab Container Registry](user/project/container_registry.md): Learn how to use GitLab's built-in Container Registry.
|
||||
|
||||
### Release
|
||||
|
@ -141,9 +147,11 @@ Spend less time configuring your tools, and more time creating. Whether you’re
|
|||
deploying to one server or thousands, build, test, and release your code
|
||||
confidently and securely with GitLab’s built-in Continuous Delivery and Deployment.
|
||||
|
||||
- [GitLab Pages](user/project/pages/index.md): Build, test, and deploy a static site directly from GitLab.
|
||||
- [Auto Deploy](topics/autodevops/index.md#auto-deploy): Configure GitLab CI for the deployment of your application.
|
||||
- [Environments and deployments](ci/environments.md): With environments, you can control the continuous deployment of your software within GitLab.
|
||||
- [GitLab Pages](user/project/pages/index.md): Build, test, and deploy a static site directly from GitLab.
|
||||
- [Scheduled Pipelines](user/project/pipelines/schedules.md)
|
||||
- [Protected Runners](ci/runners/README.md#protected-runners)
|
||||
|
||||
### Configure
|
||||
|
||||
|
@ -152,6 +160,9 @@ Auto Devops. Best practice templates get you started with minimal to zero
|
|||
configuration. Then customize everything from buildpacks to CI/CD.
|
||||
|
||||
- [Auto DevOps](topics/autodevops/index.md)
|
||||
- [Deployment of Helm, Ingress, and Prometheus on Kubernetes](user/project/clusters/index.md#installing-applications)
|
||||
- [Protected secret variables](ci/variables/README.md#protected-secret-variables)
|
||||
- [Easy creation of Kubernetes clusters on GKE](user/project/clusters/index.md#adding-and-creating-a-new-gke-cluster-via-gitlab)
|
||||
|
||||
### Monitor
|
||||
|
||||
|
|
|
@ -50,7 +50,7 @@ JWT will provide you with a secret key for you to use.
|
|||
required_claims: ["name", "email"],
|
||||
info_map: { name: "name", email: "email" },
|
||||
auth_url: 'https://example.com/',
|
||||
valid_within: nil,
|
||||
valid_within: null,
|
||||
}
|
||||
}
|
||||
```
|
||||
|
|
|
@ -323,7 +323,7 @@ The prerequisites for a HA Redis setup are the following:
|
|||
# machines to connect to it.
|
||||
redis['port'] = 6379
|
||||
|
||||
# The same password for Redeis authentication you set up for the master node.
|
||||
# The same password for Redis authentication you set up for the master node.
|
||||
redis['password'] = 'redis-password-goes-here'
|
||||
|
||||
# The IP of the master Redis node.
|
||||
|
|
|
@ -107,7 +107,7 @@ For source installations the following settings are nested under `artifacts:` an
|
|||
| Setting | Description | Default |
|
||||
|---------|-------------|---------|
|
||||
| `enabled` | Enable/disable object storage | `false` |
|
||||
| `remote_directory` | The bucket name where Artfacts will be stored| |
|
||||
| `remote_directory` | The bucket name where Artifacts will be stored| |
|
||||
| `direct_upload` | Set to true to enable direct upload of Artifacts without the need of local shared storage. Option may be removed once we decide to support only single storage for all files. Currently only `Google` provider is supported | `false` |
|
||||
| `background_upload` | Set to false to disable automatic upload. Option may be removed once upload is direct to S3 | `true` |
|
||||
| `proxy_download` | Set to true to enable proxying all files served. Option allows to reduce egress traffic as this allows clients to download directly from remote storage instead of proxying all data | `false` |
|
||||
|
@ -148,7 +148,7 @@ _The artifacts are stored by default in
|
|||
```
|
||||
|
||||
NOTE: For GitLab 9.4+, if you are using AWS IAM profiles, be sure to omit the
|
||||
AWS access key and secret acces key/value pairs. For example:
|
||||
AWS access key and secret access key/value pairs. For example:
|
||||
|
||||
```ruby
|
||||
gitlab_rails['artifacts_object_store_connection'] = {
|
||||
|
|
|
@ -46,7 +46,7 @@ In this experimental phase, only a few metrics are available:
|
|||
| redis_ping_latency_seconds | Gauge | 9.4 | Round trip time of the redis ping |
|
||||
| user_session_logins_total | Counter | 9.4 | Counter of how many users have logged in |
|
||||
| filesystem_circuitbreaker_latency_seconds | Gauge | 9.5 | Time spent validating if a storage is accessible |
|
||||
| filesystem_circuitbreaker | Gauge | 9.5 | Wether or not the circuit for a certain shard is broken or not |
|
||||
| filesystem_circuitbreaker | Gauge | 9.5 | Whether or not the circuit for a certain shard is broken or not |
|
||||
| circuitbreaker_storage_check_duration_seconds | Histogram | 10.3 | Time a single storage probe took |
|
||||
|
||||
## Metrics shared directory
|
||||
|
|
|
@ -31,7 +31,7 @@ GitLab Shell provides a way to authorize SSH users via a fast, indexed lookup
|
|||
to the GitLab database. GitLab Shell uses the fingerprint of the SSH key to
|
||||
check whether the user is authorized to access GitLab.
|
||||
|
||||
Add the following to your `sshd_config` file. This is usuaully located at
|
||||
Add the following to your `sshd_config` file. This is usually located at
|
||||
`/etc/ssh/sshd_config`, but it will be `/assets/sshd_config` if you're using
|
||||
Omnibus Docker:
|
||||
|
||||
|
|
|
@ -104,7 +104,7 @@ _The uploads are stored by default in
|
|||
```
|
||||
|
||||
>**Note:**
|
||||
If you are using AWS IAM profiles, be sure to omit the AWS access key and secret acces key/value pairs.
|
||||
If you are using AWS IAM profiles, be sure to omit the AWS access key and secret access key/value pairs.
|
||||
|
||||
```ruby
|
||||
gitlab_rails['uploads_object_store_connection'] = {
|
||||
|
|
|
@ -293,7 +293,7 @@ The following table gives an overview of how the API functions generally behave.
|
|||
| `GET` | Access one or more resources and return the result as JSON. |
|
||||
| `POST` | Return `201 Created` if the resource is successfully created and return the newly created resource as JSON. |
|
||||
| `GET` / `PUT` | Return `200 OK` if the resource is accessed or modified successfully. The (modified) result is returned as JSON. |
|
||||
| `DELETE` | Returns `204 No Content` if the resuource was deleted successfully. |
|
||||
| `DELETE` | Returns `204 No Content` if the resource was deleted successfully. |
|
||||
|
||||
The following table shows the possible return codes for API requests.
|
||||
|
||||
|
|
|
@ -12,7 +12,7 @@ Badges support placeholders that will be replaced in real time in both the link
|
|||
- **%{default_branch}**: will be replaced by the project default branch.
|
||||
- **%{commit_sha}**: will be replaced by the last project's commit sha.
|
||||
|
||||
Because these enpoints aren't inside a project's context, the information used to replace the placeholders will be
|
||||
Because these endpoints aren't inside a project's context, the information used to replace the placeholders will be
|
||||
from the first group's project by creation date. If the group hasn't got any project the original URL with the placeholders will be returned.
|
||||
|
||||
## List all badges of a group
|
||||
|
|
|
@ -108,7 +108,7 @@ POST /projects/:id/pipeline_schedules
|
|||
| `description` | string | yes | The description of pipeline schedule |
|
||||
| `ref` | string | yes | The branch/tag name will be triggered |
|
||||
| `cron ` | string | yes | The cron (e.g. `0 1 * * *`) ([Cron syntax](https://en.wikipedia.org/wiki/Cron)) |
|
||||
| `cron_timezone ` | string | no | The timezone supproted by `ActiveSupport::TimeZone` (e.g. `Pacific Time (US & Canada)`) (default: `'UTC'`) |
|
||||
| `cron_timezone ` | string | no | The timezone supported by `ActiveSupport::TimeZone` (e.g. `Pacific Time (US & Canada)`) (default: `'UTC'`) |
|
||||
| `active ` | boolean | no | The activation of pipeline schedule. If false is set, the pipeline schedule will deactivated initially (default: `true`) |
|
||||
|
||||
```sh
|
||||
|
@ -153,7 +153,7 @@ PUT /projects/:id/pipeline_schedules/:pipeline_schedule_id
|
|||
| `description` | string | no | The description of pipeline schedule |
|
||||
| `ref` | string | no | The branch/tag name will be triggered |
|
||||
| `cron ` | string | no | The cron (e.g. `0 1 * * *`) ([Cron syntax](https://en.wikipedia.org/wiki/Cron)) |
|
||||
| `cron_timezone ` | string | no | The timezone supproted by `ActiveSupport::TimeZone` (e.g. `Pacific Time (US & Canada)`) or `TZInfo::Timezone` (e.g. `America/Los_Angeles`) |
|
||||
| `cron_timezone ` | string | no | The timezone supported by `ActiveSupport::TimeZone` (e.g. `Pacific Time (US & Canada)`) or `TZInfo::Timezone` (e.g. `America/Los_Angeles`) |
|
||||
| `active ` | boolean | no | The activation of pipeline schedule. If false is set, the pipeline schedule will deactivated initially. |
|
||||
|
||||
```sh
|
||||
|
|
|
@ -14,6 +14,7 @@ GET /projects/:id/pipelines
|
|||
| `scope` | string | no | The scope of pipelines, one of: `running`, `pending`, `finished`, `branches`, `tags` |
|
||||
| `status` | string | no | The status of pipelines, one of: `running`, `pending`, `success`, `failed`, `canceled`, `skipped` |
|
||||
| `ref` | string | no | The ref of pipelines |
|
||||
| `sha` | string | no | The sha or pipelines |
|
||||
| `yaml_errors`| boolean | no | Returns pipelines with invalid configurations |
|
||||
| `name`| string | no | The name of the user who triggered pipelines |
|
||||
| `username`| string | no | The username of the user who triggered pipelines |
|
||||
|
|
|
@ -509,7 +509,7 @@ and unit tests, all running and deployed at every push to master - with shocking
|
|||
Errors can be easily debugged through GitLab's build logs, and within minutes of a successful commit,
|
||||
you can see the changes live on your game.
|
||||
|
||||
Setting up Continous Integration and Continuous Deployment from the start with Dark Nova enables
|
||||
Setting up Continuous Integration and Continuous Deployment from the start with Dark Nova enables
|
||||
rapid but stable development. We can easily test changes in a separate [environment](../../../ci/environments.md#introduction-to-environments-and-deployments),
|
||||
or multiple environments if needed. Balancing and updating a multiplayer game can be ongoing
|
||||
and tedious, but having faith in a stable deployment with GitLab CI/CD allows
|
||||
|
|
|
@ -30,7 +30,7 @@ and GitLab UI._
|
|||
|
||||
Many components and concepts are similar to Ruby on Rails or Python's Django. High developer
|
||||
productivity and high application performance are only a few advantages on learning how to use it.
|
||||
Working on the MVC pattern, it's was designed to be modular and flexible. Easy to mantain a growing
|
||||
Working on the MVC pattern, it's was designed to be modular and flexible. Easy to maintain a growing
|
||||
app is a plus.
|
||||
|
||||
Phoenix can run in any OS where Erlang is supported:
|
||||
|
@ -48,7 +48,7 @@ Check the [Phoenix learning guide][phoenix-learning-guide] for more information.
|
|||
### What is Elixir?
|
||||
|
||||
[Elixir][elixir-site] is a dynamic, functional language created to use all the maturity of Erlang
|
||||
(30 years old!) in these days, in an easy way. It has similarities with Ruby, specially on sintax,
|
||||
(30 years old!) in these days, in an easy way. It has similarities with Ruby, specially on syntax,
|
||||
so Ruby developers are quite excited with the rapid growing of Elixir. A full-stack Ruby developer
|
||||
can learn how to use Elixir and Phoenix in just a few weeks!
|
||||
|
||||
|
@ -162,7 +162,7 @@ productive, because every time we, or our co-workers push any code, GitLab CI/CD
|
|||
test the changes, telling us in realtime if anything goes wrong.
|
||||
|
||||
Certainly, when our application starts to grow, we'll need more developers working on the same
|
||||
project and this process of building and testing can easely become a mess without proper management.
|
||||
project and this process of building and testing can easily become a mess without proper management.
|
||||
That's also why GitLab CI/CD is so important to our application. Every time someone pushes its code to
|
||||
GitLab, we'll quickly know if their changes broke something or not. We don't need to stop everything
|
||||
we're doing to test manually and locally every change our team does.
|
||||
|
@ -237,7 +237,7 @@ Finished in 0.7 seconds
|
|||
Randomized with seed 610000
|
||||
```
|
||||
|
||||
Our test was successfull. It's time to push our files to GitLab.
|
||||
Our test was successful. It's time to push our files to GitLab.
|
||||
|
||||
## Configuring CI/CD Pipeline
|
||||
|
||||
|
@ -302,7 +302,7 @@ template** and select **Elixir**:
|
|||
```
|
||||
|
||||
It's important to install `postgresql-client` to let GitLab CI/CD access PostgreSQL and create our
|
||||
database with the login information provided earlier. More important is to respect the identation,
|
||||
database with the login information provided earlier. More important is to respect the indentation,
|
||||
to avoid syntax errors when running the build.
|
||||
|
||||
- And finally, we'll let `mix` session intact.
|
||||
|
@ -333,7 +333,7 @@ mix:
|
|||
- mix test
|
||||
```
|
||||
|
||||
For safety, we can check if we get any syntax errors before submiting this file to GitLab. Copy the
|
||||
For safety, we can check if we get any syntax errors before submitting this file to GitLab. Copy the
|
||||
contents of `.gitlab-ci.yml` and paste it on [GitLab CI/CD Lint tool][ci-lint]. Please note that
|
||||
this link will only work for logged in users.
|
||||
|
||||
|
@ -384,7 +384,7 @@ working properly.
|
|||
|
||||
When we have a growing application with many developers working on it, or when we have an open
|
||||
source project being watched and contributed by the community, it is really important to have our
|
||||
code permanently working. GitLab CI/CD is a time saving powerfull tool to help us mantain our code
|
||||
code permanently working. GitLab CI/CD is a time saving powerful tool to help us maintain our code
|
||||
organized and working.
|
||||
|
||||
As we could see in this post, GitLab CI/CD is really really easy to configure and use. We have [many
|
||||
|
|
|
@ -551,7 +551,7 @@ You can find a full list of unsupported variables below:
|
|||
- `CI_DEPLOY_USER`
|
||||
- `CI_DEPLOY_PASSWORD`
|
||||
|
||||
These variables are also not supported in a contex of a
|
||||
These variables are also not supported in a context of a
|
||||
[dynamic environment name][dynamic-environments].
|
||||
|
||||
[ce-13784]: https://gitlab.com/gitlab-org/gitlab-ce/issues/13784 "Simple protection of CI secret variables"
|
||||
|
|
|
@ -41,6 +41,7 @@ comments: false
|
|||
- [Avoid modules with instance variables](module_with_instance_variables.md) if possible
|
||||
- [How to dump production data to staging](db_dump.md)
|
||||
- [Working with the GitHub importer](github_importer.md)
|
||||
- [Working with Merge Request diffs](diffs.md)
|
||||
|
||||
## Performance guides
|
||||
|
||||
|
|
|
@ -24,7 +24,7 @@ Some examples where background migrations can be useful:
|
|||
|
||||
* Migrating events from one table to multiple separate tables.
|
||||
* Populating one column based on JSON stored in another column.
|
||||
* Migrating data that depends on the output of exernal services (e.g. an API).
|
||||
* Migrating data that depends on the output of external services (e.g. an API).
|
||||
|
||||
## Isolation
|
||||
|
||||
|
@ -46,7 +46,7 @@ See [Sidekiq best practices guidelines](https://github.com/mperham/sidekiq/wiki/
|
|||
for more details.
|
||||
|
||||
Make sure that in case that your migration job is going to be retried data
|
||||
integrity is guarateed.
|
||||
integrity is guaranteed.
|
||||
|
||||
## How It Works
|
||||
|
||||
|
|
115
doc/development/diffs.md
Normal file
115
doc/development/diffs.md
Normal file
|
@ -0,0 +1,115 @@
|
|||
# Working with Merge Request diffs
|
||||
|
||||
Currently we rely on different sources to present merge request diffs, these include:
|
||||
|
||||
- Rugged gem
|
||||
- Gitaly service
|
||||
- Database (through `merge_request_diff_files`)
|
||||
- Redis (cached highlighted diffs)
|
||||
|
||||
We're constantly moving Rugged calls to Gitaly and the progress can be followed through [Gitaly repo](https://gitlab.com/gitlab-org/gitaly).
|
||||
|
||||
## Architecture overview
|
||||
|
||||
When refreshing a Merge Request (pushing to a source branch, force-pushing to target branch, or if the target branch now contains any commits from the MR)
|
||||
we fetch the comparison information using `Gitlab::Git::Compare`, which fetches `base` and `head` data using Gitaly and diff between them through
|
||||
`Gitlab::Git::Diff.between` (which uses _Gitaly_ if it's enabled, otherwise _Rugged_).
|
||||
The diffs fetching process _limits_ single file diff sizes and the overall size of the whole diff through a series of constant values. Raw diff files are
|
||||
then persisted on `merge_request_diff_files` table.
|
||||
|
||||
Even though diffs higher than 10kb are collapsed (`Gitlab::Git::Diff::COLLAPSE_LIMIT`), we still keep them on Postgres. However, diff files over _safety limits_
|
||||
(see the [Diff limits section](#diff-limits)) are _not_ persisted.
|
||||
|
||||
In order to present diffs information on the Merge Request diffs page, we:
|
||||
|
||||
1. Fetch all diff files from database `merge_request_diff_files`
|
||||
2. Fetch the _old_ and _new_ file blobs in batch to:
|
||||
1. Highlight old and new file content
|
||||
2. Know which viewer it should use for each file (text, image, deleted, etc)
|
||||
3. Know if the file content changed
|
||||
4. Know if it was stored externally
|
||||
5. Know if it had storage errors
|
||||
3. If the diff file is cacheable (text-based), it's cached on Redis
|
||||
using `Gitlab::Diff::FileCollection::MergeRequestDiff`
|
||||
|
||||
## Diff limits
|
||||
|
||||
As explained above, we limit single diff files and the size of the whole diff. There are scenarios where we collapse the diff file,
|
||||
and cases where the diff file is not presented at all, and the user is guided to the Blob view. Here we'll go into details about
|
||||
these limits.
|
||||
|
||||
### Diff collection limits
|
||||
|
||||
Limits that act onto all diff files collection. Files number, lines number and files size are considered.
|
||||
|
||||
```ruby
|
||||
Gitlab::Git::DiffCollection.collection_limits[:safe_max_files] = Gitlab::Git::DiffCollection::DEFAULT_LIMITS[:max_files] = 100
|
||||
```
|
||||
|
||||
File diffs will be collapsed (but be expandable) if 100 files have already been rendered.
|
||||
|
||||
|
||||
```ruby
|
||||
Gitlab::Git::DiffCollection.collection_limits[:safe_max_lines] = Gitlab::Git::DiffCollection::DEFAULT_LIMITS[:max_lines] = 5000
|
||||
```
|
||||
|
||||
File diffs will be collapsed (but be expandable) if 5000 lines have already been rendered.
|
||||
|
||||
|
||||
```ruby
|
||||
Gitlab::Git::DiffCollection.collection_limits[:safe_max_bytes] = Gitlab::Git::DiffCollection.collection_limits[:safe_max_files] * 5.kilobytes = 500.kilobytes
|
||||
```
|
||||
|
||||
File diffs will be collapsed (but be expandable) if 500 kilobytes have already been rendered.
|
||||
|
||||
|
||||
```ruby
|
||||
Gitlab::Git::DiffCollection.collection_limits[:max_files] = Commit::DIFF_HARD_LIMIT_FILES = 1000
|
||||
```
|
||||
|
||||
No more files will be rendered at all if 1000 files have already been rendered.
|
||||
|
||||
|
||||
```ruby
|
||||
Gitlab::Git::DiffCollection.collection_limits[:max_lines] = Commit::DIFF_HARD_LIMIT_LINES = 50000
|
||||
```
|
||||
|
||||
No more files will be rendered at all if 50,000 lines have already been rendered.
|
||||
|
||||
```ruby
|
||||
Gitlab::Git::DiffCollection.collection_limits[:max_bytes] = Gitlab::Git::DiffCollection.collection_limits[:max_files] * 5.kilobytes = 5000.kilobytes
|
||||
```
|
||||
|
||||
No more files will be rendered at all if 5 megabytes have already been rendered.
|
||||
|
||||
|
||||
### Individual diff file limits
|
||||
|
||||
Limits that act onto each diff file of a collection. Files number, lines number and files size are considered.
|
||||
|
||||
```ruby
|
||||
Gitlab::Git::Diff::COLLAPSE_LIMIT = 10.kilobytes
|
||||
```
|
||||
|
||||
File diff will be collapsed (but be expandable) if it is larger than 10 kilobytes.
|
||||
|
||||
```ruby
|
||||
Gitlab::Git::Diff::SIZE_LIMIT = 100.kilobytes
|
||||
```
|
||||
|
||||
File diff will not be rendered if it's larger than 100 kilobytes.
|
||||
|
||||
|
||||
```ruby
|
||||
Commit::DIFF_SAFE_LINES = Gitlab::Git::DiffCollection::DEFAULT_LIMITS[:max_lines] = 5000
|
||||
```
|
||||
|
||||
File diff will be suppressed (technically different from collapsed, but behaves the same, and is expandable) if it has more than 5000 lines.
|
||||
|
||||
## Viewers
|
||||
|
||||
Diff Viewers, which can be found on `models/diff_viewer/*` are classes used to map metadata about each type of Diff File. It has information
|
||||
whether it's a binary, which partial should be used to render it or which File extensions this class accounts for.
|
||||
|
||||
`DiffViewer::Base` validates _blobs_ (old and new versions) content, extension and file type in order to check if it can be rendered.
|
||||
|
|
@ -4,7 +4,7 @@ The documentation style guide defines the markup structure used in
|
|||
GitLab documentation. Check the
|
||||
[documentation guidelines](writing_documentation.md) for general development instructions.
|
||||
|
||||
Check the GitLab hanbook for the [writing styles guidelines](https://about.gitlab.com/handbook/communication/#writing-style-guidelines).
|
||||
Check the GitLab handbook for the [writing styles guidelines](https://about.gitlab.com/handbook/communication/#writing-style-guidelines).
|
||||
|
||||
## Text
|
||||
|
||||
|
@ -19,7 +19,7 @@ Check the GitLab hanbook for the [writing styles guidelines](https://about.gitla
|
|||
- Unless there's a logical reason not to, add documents in alphabetical order
|
||||
- Write in US English
|
||||
- Use [single spaces][] instead of double spaces
|
||||
- Jump a line between different markups (e.g., after every paragraph, hearder, list, etc)
|
||||
- Jump a line between different markups (e.g., after every paragraph, header, list, etc)
|
||||
- Capitalize "G" and "L" in GitLab
|
||||
- Capitalize feature, products, and methods names. E.g.: GitLab Runner, Geo,
|
||||
Issue Boards, Git, Prometheus, Continuous Integration.
|
||||
|
|
|
@ -279,7 +279,7 @@ end
|
|||
```
|
||||
|
||||
In `lib/gitlab/visibility_level.rb` this method is used to return the
|
||||
allowed visibilty levels:
|
||||
allowed visibility levels:
|
||||
|
||||
```ruby
|
||||
def levels_for_user(user = nil)
|
||||
|
|
|
@ -236,7 +236,7 @@ export class Foo {
|
|||
}
|
||||
```
|
||||
|
||||
On the other hand, if a class only needs to extend a third party/add event listeners in some specific cases, they should be initialized oustside of the constructor.
|
||||
On the other hand, if a class only needs to extend a third party/add event listeners in some specific cases, they should be initialized outside of the constructor.
|
||||
|
||||
1. Prefer `.map`, `.reduce` or `.filter` over `.forEach`
|
||||
A forEach will most likely cause side effects, it will be mutating the array being iterated. Prefer using `.map`,
|
||||
|
|
|
@ -84,7 +84,7 @@ The `RecordsUploads::Concern` concern will create an `Upload` entry for every fi
|
|||
By including the `ObjectStorage::Concern` in the `GitlabUploader` derived class, you may enable the object storage for this uploader. To enable the object storage
|
||||
in your uploader, you need to either 1) include `RecordsUpload::Concern` and prepend `ObjectStorage::Extension::RecordsUploads` or 2) mount the uploader and create a new field named `<mount>_store`.
|
||||
|
||||
The `CarrierWave::Uploader#store_dir` is overriden to
|
||||
The `CarrierWave::Uploader#store_dir` is overridden to
|
||||
|
||||
- `GitlabUploader.base_dir` + `GitlabUploader.dynamic_segment` when the store is LOCAL
|
||||
- `GitlabUploader.dynamic_segment` when the store is REMOTE (the bucket name is used to namespace)
|
||||
|
|
|
@ -270,7 +270,7 @@ If there are merge conflicts in the `gitlab.pot` file, you can delete the file
|
|||
and regenerate it using the same command. Confirm that you are not deleting any strings accidentally by looking over the diff.
|
||||
|
||||
The command also updates the translation files for each language: `locale/*/gitlab.po`
|
||||
These changes can be discarded, the languange files will be updated by Crowdin
|
||||
These changes can be discarded, the language files will be updated by Crowdin
|
||||
automatically.
|
||||
|
||||
Discard all of them at once like this:
|
||||
|
|
|
@ -162,7 +162,7 @@ need for running complex operations to fetch the data. You should use Redis if
|
|||
data should be cached for a certain time period instead of the duration of the
|
||||
transaction.
|
||||
|
||||
For example, say you process multiple snippets of text containiner username
|
||||
For example, say you process multiple snippets of text containing username
|
||||
mentions (e.g. `Hello @alice` and `How are you doing @alice?`). By caching the
|
||||
user objects for every username we can remove the need for running the same
|
||||
query for every mention of `@alice`.
|
||||
|
|
|
@ -30,7 +30,7 @@ example) at the end.
|
|||
|
||||
## Type Sizes
|
||||
|
||||
While the PostgreSQL docuemntation
|
||||
While the PostgreSQL documentation
|
||||
(https://www.postgresql.org/docs/current/static/datatype.html) contains plenty
|
||||
of information we will list the sizes of common types here so it's easier to
|
||||
look them up. Here "word" refers to the word size, which is 4 bytes for a 32
|
||||
|
|
|
@ -28,7 +28,7 @@ records should use stubs/doubles as much as possible.
|
|||
| `app/uploaders/` | `spec/uploaders/` | RSpec | |
|
||||
| `app/views/` | `spec/views/` | RSpec | |
|
||||
| `app/workers/` | `spec/workers/` | RSpec | |
|
||||
| `app/assets/javascripts/` | `spec/javascripts/` | Karma | More details in the [Frontent Testing guide](frontend_testing.md) section. |
|
||||
| `app/assets/javascripts/` | `spec/javascripts/` | Karma | More details in the [Frontend Testing guide](frontend_testing.md) section. |
|
||||
|
||||
## Integration tests
|
||||
|
||||
|
|
|
@ -219,7 +219,7 @@ Blocks are a way to group related information.
|
|||
|
||||
#### Content blocks
|
||||
|
||||
Content blocks (`.content-block`) are the basic grouping of content. They are commonly used in [lists](#lists), and are separated by a botton border.
|
||||
Content blocks (`.content-block`) are the basic grouping of content. They are commonly used in [lists](#lists), and are separated by a button border.
|
||||
|
||||
![Content block](img/components-contentblock.png)
|
||||
|
||||
|
@ -281,7 +281,7 @@ Modals are only used for having a conversation and confirmation with the user. T
|
|||
|
||||
| Modal with 2 actions | Modal with 3 actions | Special confirmation |
|
||||
| --------------------- | --------------------- | -------------------- |
|
||||
| ![two-actions](img/modals-general-confimation-dialog.png) | ![three-actions](img/modals-three-buttons.png) | ![spcial-confirmation](img/modals-special-confimation-dialog.png) |
|
||||
| ![two-actions](img/modals-general-confimation-dialog.png) | ![three-actions](img/modals-three-buttons.png) | ![special-confirmation](img/modals-special-confimation-dialog.png) |
|
||||
|
||||
> TODO: Special case for modal.
|
||||
|
||||
|
|
|
@ -255,7 +255,7 @@ otherwise it will raise a `TypeError`.
|
|||
## Adding Indexes
|
||||
|
||||
Adding indexes is an expensive process that blocks INSERT and UPDATE queries for
|
||||
the duration. When using PostgreSQL one can work arounds this by using the
|
||||
the duration. When using PostgreSQL one can work around this by using the
|
||||
`CONCURRENTLY` option:
|
||||
|
||||
```sql
|
||||
|
|
|
@ -49,7 +49,7 @@ do before.
|
|||
|
||||
**Use cases**: provide at least two, ideally three, use cases for every major feature.
|
||||
You should answer this question: what can you do with this feature/change? Use cases
|
||||
are examples of how this feauture or change can be used in real life.
|
||||
are examples of how this feature or change can be used in real life.
|
||||
|
||||
Examples:
|
||||
- CE and EE: [Issues](../user/project/issues/index.md#use-cases)
|
||||
|
|
|
@ -91,7 +91,7 @@ Follow the below instructions to ensure you use the most up to date requirements
|
|||
|
||||
#### Check for InnoDB File-Per-Table Tablespaces
|
||||
|
||||
We need to check, enable and maybe convert your existing GitLab DB tables to the [InnoDB File-Per-Table Tablespaces](http://dev.mysql.com/doc/refman/5.7/en/innodb-multiple-tablespaces.html) as a prerequise for supporting **utfb8mb4 with long indexes** required by recent GitLab databases.
|
||||
We need to check, enable and maybe convert your existing GitLab DB tables to the [InnoDB File-Per-Table Tablespaces](http://dev.mysql.com/doc/refman/5.7/en/innodb-multiple-tablespaces.html) as a prerequisite for supporting **utfb8mb4 with long indexes** required by recent GitLab databases.
|
||||
|
||||
# Login to MySQL
|
||||
mysql -u root -p
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
![GCP landing page](img/gcp_landing.png)
|
||||
|
||||
Gettung started with GitLab on a [Google Cloud Platform (GCP)][gcp] instance is quick and easy.
|
||||
Getting started with GitLab on a [Google Cloud Platform (GCP)][gcp] instance is quick and easy.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
|
|
|
@ -50,12 +50,12 @@ Here is a snippet of the important settings:
|
|||
gitlabUrl: http://gitlab.your-domain.com/
|
||||
|
||||
## The Registration Token for adding new Runners to the GitLab Server. This must
|
||||
## be retreived from your GitLab Instance.
|
||||
## be retrieved from your GitLab Instance.
|
||||
## ref: https://docs.gitlab.com/ce/ci/runners/README.html#creating-and-registering-a-runner
|
||||
##
|
||||
runnerRegistrationToken: ""
|
||||
|
||||
## Set the certsSecretName in order to pass custom certficates for GitLab Runner to use
|
||||
## Set the certsSecretName in order to pass custom certificates for GitLab Runner to use
|
||||
## Provide resource name for a Kubernetes Secret Object in the same namespace,
|
||||
## this is used to populate the /etc/gitlab-runner/certs directory
|
||||
## ref: https://docs.gitlab.com/runner/configuration/tls-self-signed.html#supported-options-for-self-signed-certificates
|
||||
|
@ -130,7 +130,7 @@ runners:
|
|||
|
||||
### Enabling RBAC support
|
||||
|
||||
If your cluster has RBAC enabled, you can choose to either have the chart create its own sevice account or provide one.
|
||||
If your cluster has RBAC enabled, you can choose to either have the chart create its own service account or provide one.
|
||||
|
||||
To have the chart create the service account for you, set `rbac.create` to true.
|
||||
|
||||
|
@ -208,7 +208,7 @@ You then need to provide the secret's name to the GitLab Runner chart.
|
|||
Add the following to your `values.yaml`
|
||||
|
||||
```yaml
|
||||
## Set the certsSecretName in order to pass custom certficates for GitLab Runner to use
|
||||
## Set the certsSecretName in order to pass custom certificates for GitLab Runner to use
|
||||
## Provide resource name for a Kubernetes Secret Object in the same namespace,
|
||||
## this is used to populate the /etc/gitlab-runner/certs directory
|
||||
## ref: https://docs.gitlab.com/runner/configuration/tls-self-signed.html#supported-options-for-self-signed-certificates
|
||||
|
|
|
@ -43,7 +43,7 @@ exclude shibboleth URLs from rewriting, add "RewriteCond %{REQUEST_URI} !/Shibbo
|
|||
RequestHeader set X_FORWARDED_PROTO 'https'
|
||||
```
|
||||
|
||||
1. Edit /etc/gitlab/gitlab.rb configuration file, your shibboleth attributes should be in form of "HTTP_ATTRIBUTE" and you should addjust them to your need and environment. Add any other configuration you need.
|
||||
1. Edit /etc/gitlab/gitlab.rb configuration file, your shibboleth attributes should be in form of "HTTP_ATTRIBUTE" and you should adjust them to your need and environment. Add any other configuration you need.
|
||||
|
||||
File should look like this:
|
||||
```
|
||||
|
|
|
@ -196,7 +196,7 @@ This is really useful for integrating repositories to secured, shared Continuous
|
|||
Integration (CI) services or other shared services.
|
||||
GitLab administrators can set up the Global Shared Deploy key in GitLab and
|
||||
add the private key to any shared systems. Individual repositories opt into
|
||||
exposing their repsitory using these keys when a project masters (or higher)
|
||||
exposing their repository using these keys when a project masters (or higher)
|
||||
authorizes a Global Shared Deploy key to be used with their project.
|
||||
|
||||
Global Shared Keys can provide greater security compared to Per-Project Deploy
|
||||
|
@ -224,7 +224,7 @@ if there is at least one Global Deploy Key configured.
|
|||
|
||||
CAUTION: **Warning:**
|
||||
Defining Global Deploy Keys does not expose any given repository via
|
||||
the key until that respository adds the Global Deploy Key to their project.
|
||||
the key until that repository adds the Global Deploy Key to their project.
|
||||
In this way the Global Deploy Keys enable access by other systems, but do
|
||||
not implicitly give any access just by setting them up.
|
||||
|
||||
|
|
|
@ -135,6 +135,11 @@ and `1.2.3.4` is the IP address of your load balancer; generally NGINX
|
|||
([see prerequisites](#prerequisites)). How to set up the DNS record is beyond
|
||||
the scope of this document; you should check with your DNS provider.
|
||||
|
||||
Alternatively you can use free public services like [xip.io](http://xip.io) or
|
||||
[nip.io](http://nip.io) which provide automatic wildcard DNS without any
|
||||
configuration. Just set the Auto DevOps base domain to `1.2.3.4.xip.io` or
|
||||
`1.2.3.4.nip.io`.
|
||||
|
||||
Once set up, all requests will hit the load balancer, which in turn will route
|
||||
them to the Kubernetes pods that run your application(s).
|
||||
|
||||
|
|
|
@ -89,7 +89,7 @@ A [copy](https://git-scm.com/docs/git-clone) of a repository stored on your mach
|
|||
|
||||
### Code Review
|
||||
|
||||
Examination of a progam's code. The main aim is to maintain high quality standards of code that is being shipped. Merge requests [serve as a code review tool](https://about.gitlab.com/2014/09/29/gitlab-flow/) in GitLab.
|
||||
Examination of a program's code. The main aim is to maintain high quality standards of code that is being shipped. Merge requests [serve as a code review tool](https://about.gitlab.com/2014/09/29/gitlab-flow/) in GitLab.
|
||||
|
||||
### Code Snippet
|
||||
|
||||
|
|
|
@ -354,11 +354,11 @@ add the following script to the User Data section:
|
|||
- mount -a -t nfs
|
||||
- sudo gitlab-ctl reconfigure
|
||||
|
||||
On the security group section we can chosse our existing
|
||||
On the security group section we can choose our existing
|
||||
`gitlab-ec2-security-group` group which has already been tested.
|
||||
|
||||
After this is launched we are able to start creating our Auto Scaling
|
||||
Group. Start by giving it a name and assinging it our VPC and private
|
||||
Group. Start by giving it a name and assigning it our VPC and private
|
||||
subnets. We also want to always start with two instances and if you
|
||||
scroll down to Advanced Details we can choose to receive traffic from ELBs.
|
||||
Lets enable that option and select our ELB. We also want to use the ELB's
|
||||
|
|
|
@ -163,7 +163,7 @@ Some tickets need specific knowledge or a deep understanding of a particular com
|
|||
|
||||
- Aim to have a good understanding of the problems that customers are facing
|
||||
- Aim to have gained experience in scheduling and participating in calls with customers
|
||||
- Aim to have a good understanding of ticket flow through Zendesk and how to interat with our various channels
|
||||
- Aim to have a good understanding of ticket flow through Zendesk and how to interact with our various channels
|
||||
|
||||
### Stage 4
|
||||
|
||||
|
|
|
@ -27,7 +27,7 @@ project.
|
|||
|
||||
### Short Story of Git
|
||||
|
||||
- 1991-2002: The Linux kernel was being maintaned by sharing archived files
|
||||
- 1991-2002: The Linux kernel was being maintained by sharing archived files
|
||||
and patches.
|
||||
- 2002: The Linux kernel project began using a DVCS called BitKeeper
|
||||
- 2005: BitKeeper revoked the free-of-charge status and Git was created
|
||||
|
|
|
@ -9,7 +9,7 @@ comments: false
|
|||
- Useful for marking deployments and releases
|
||||
- Annotated tags are an unchangeable part of Git history
|
||||
- Soft/lightweight tags can be set and removed at will
|
||||
- Many projects combine an anotated release tag with a stable branch
|
||||
- Many projects combine an annotated release tag with a stable branch
|
||||
- Consider setting deployment/release tags automatically
|
||||
|
||||
----------
|
||||
|
|
|
@ -279,7 +279,7 @@ See GitLab merge requests for examples:
|
|||
- Useful for marking deployments and releases
|
||||
- Annotated tags are an unchangeable part of Git history
|
||||
- Soft/lightweight tags can be set and removed at will
|
||||
- Many projects combine an anotated release tag with a stable branch
|
||||
- Many projects combine an annotated release tag with a stable branch
|
||||
- Consider setting deployment/release tags automatically
|
||||
|
||||
---
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
# Sign-up restrictions
|
||||
|
||||
You can block email addresses of specific domains, or whitelist only some
|
||||
specifc domains via the **Application Settings** in the Admin area.
|
||||
specific domains via the **Application Settings** in the Admin area.
|
||||
|
||||
>**Note**: These restrictions are only applied during sign-up. An admin is
|
||||
able to add add a user through the admin panel with a disallowed domain. Also
|
||||
|
|
|
@ -55,7 +55,7 @@ first group being the name of the distro and subsequent groups split like:
|
|||
Another example of GitLab as a company would be the following:
|
||||
|
||||
- Organization Group - GitLab
|
||||
- Category Subroup - Marketing
|
||||
- Category Subgroup - Marketing
|
||||
- (project) Design
|
||||
- (project) General
|
||||
- Category Subgroup - Software
|
||||
|
|
|
@ -56,7 +56,7 @@ With GitLab Enterprise Edition, you can also:
|
|||
[Merge Request Approvals](https://docs.gitlab.com/ee/user/project/merge_requests/index.html#merge-request-approvals),
|
||||
[Multiple Assignees for Issues](https://docs.gitlab.com/ee/user/project/issues/multiple_assignees_for_issues.html),
|
||||
and [Multiple Issue Boards](https://docs.gitlab.com/ee/user/project/issue_board.html#multiple-issue-boards)
|
||||
- Create formal relashionships between issues with [Related Issues](https://docs.gitlab.com/ee/user/project/issues/related_issues.html)
|
||||
- Create formal relationships between issues with [Related Issues](https://docs.gitlab.com/ee/user/project/issues/related_issues.html)
|
||||
- Use [Burndown Charts](https://docs.gitlab.com/ee/user/project/milestones/burndown_charts.html) to track progress during a sprint or while working on a new version of their software.
|
||||
- Leverage [Elasticsearch](https://docs.gitlab.com/ee/integration/elasticsearch.html) with [Advanced Global Search](https://docs.gitlab.com/ee/user/search/advanced_global_search.html) and [Advanced Syntax Search](https://docs.gitlab.com/ee/user/search/advanced_search_syntax.html) for faster, more advanced code search across your entire GitLab instance
|
||||
- [Authenticate users with Kerberos](https://docs.gitlab.com/ee/integration/kerberos.html)
|
||||
|
|
|
@ -238,6 +238,7 @@ work.
|
|||
The default environment scope is `*`, which means all jobs, regardless of their
|
||||
environment, will use that cluster. Each scope can only be used by a single
|
||||
cluster in a project, and a validation error will occur if otherwise.
|
||||
Also, jobs that don't have an environment keyword set will not be able to access any cluster.
|
||||
|
||||
---
|
||||
|
||||
|
|
|
@ -48,12 +48,12 @@ link to each other, but the MR will NOT close the issue(s) when merged.
|
|||
|
||||
## From the Issue Board
|
||||
|
||||
You can close an issue from [Issue Boards](../issue_board.md) by draging an issue card
|
||||
You can close an issue from [Issue Boards](../issue_board.md) by dragging an issue card
|
||||
from its list and dropping into **Closed**.
|
||||
|
||||
![close issue from the Issue Board](img/close_issue_from_board.gif)
|
||||
|
||||
## Customizing the issue closing patern
|
||||
## Customizing the issue closing pattern
|
||||
|
||||
Alternatively, a GitLab **administrator** can
|
||||
[customize the issue closing patern](../../../administration/issue_closing_pattern.md).
|
||||
[customize the issue closing pattern](../../../administration/issue_closing_pattern.md).
|
||||
|
|
|
@ -60,4 +60,4 @@ or simply link both issue and merge request as described in the
|
|||
|
||||
### Close an issue by merging a merge request
|
||||
|
||||
To [close an issue when a merge request is merged](closing_issues.md#via-merge-request), use the [automatic issue closing patern](automatic_issue_closing.md).
|
||||
To [close an issue when a merge request is merged](closing_issues.md#via-merge-request), use the [automatic issue closing pattern](automatic_issue_closing.md).
|
||||
|
|
|
@ -152,7 +152,7 @@ know you like it without spamming them.
|
|||
These text fields also fully support
|
||||
[GitLab Flavored Markdown](../../markdown.md#gitlab-flavored-markdown-gfm).
|
||||
|
||||
#### 17. Comment, start a discusion, or comment and close
|
||||
#### 17. Comment, start a discussion, or comment and close
|
||||
|
||||
Once you wrote your comment, you can either:
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@ Milestones allow you to organize issues and merge requests into a cohesive group
|
|||
|
||||
- **Project milestones** can be assigned to issues or merge requests in that project only.
|
||||
- **Group milestones** can be assigned to any issue or merge request of any project in that group.
|
||||
- In the [future](https://gitlab.com/gitlab-org/gitlab-ce/issues/36862), you will be able to assign group milestones to issues and merge reqeusts of projects in [subgroups](../../group/subgroups/index.md).
|
||||
- In the [future](https://gitlab.com/gitlab-org/gitlab-ce/issues/36862), you will be able to assign group milestones to issues and merge requests of projects in [subgroups](../../group/subgroups/index.md).
|
||||
|
||||
## Creating milestones
|
||||
|
||||
|
|
|
@ -50,14 +50,14 @@ created for the steps below.
|
|||
1. [Fork a sample project](../../../gitlab-basics/fork-project.md) from the [Pages group](https://gitlab.com/pages)
|
||||
1. Trigger a build (push a change to any file)
|
||||
1. As soon as the build passes, your website will have been deployed with GitLab Pages. Your website URL will be available under your project's **Settings** > **Pages**
|
||||
1. Optionally, remove the fork relationship by navigating to your project's **Settings** > expanding **Advanced settings** and scrolling down to **Remove fork relashionship**:
|
||||
1. Optionally, remove the fork relationship by navigating to your project's **Settings** > expanding **Advanced settings** and scrolling down to **Remove fork relationship**:
|
||||
|
||||
![remove fork relashionship](img/remove_fork_relashionship.png)
|
||||
![remove fork relationship](img/remove_fork_relationship.png)
|
||||
|
||||
To turn a **project website** forked from the Pages group into a **user/group** website, you'll need to:
|
||||
|
||||
- Rename it to `namespace.gitlab.io`: navigate to project's **Settings** > expand **Advanced settings** > and scroll down to **Rename repository**
|
||||
- Adjust your SSG's [base URL](#urls-and-baseurls) to from `"project-name"` to `""`. This setting will be at a different place for each SSG, as each of them have their own structure and file tree. Most likelly, it will be in the SSG's config file.
|
||||
- Adjust your SSG's [base URL](#urls-and-baseurls) to from `"project-name"` to `""`. This setting will be at a different place for each SSG, as each of them have their own structure and file tree. Most likely, it will be in the SSG's config file.
|
||||
|
||||
> **Notes:**
|
||||
>
|
||||
|
|
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 13 KiB |
|
@ -1,23 +1,22 @@
|
|||
# GitLab Pages
|
||||
|
||||
With GitLab Pages you can host your website at no cost.
|
||||
|
||||
Your files live in a GitLab project's [repository](../repository/index.md),
|
||||
from which you can deploy [static websites](#explore-gitlab-pages).
|
||||
GitLab Pages supports all static site generators (SSGs).
|
||||
With GitLab Pages it's easy to publish your project website. GitLab Pages is a hosting service for static websites, at no additional cost.
|
||||
|
||||
## Getting Started
|
||||
|
||||
Follow the steps below to get your website live. They shouldn't take more than
|
||||
5 minutes to complete:
|
||||
[Create a project from scratch](getting_started_part_two.md#create-a-project-from-scratch)
|
||||
to get you started quickly, or,
|
||||
alternatively, start from an existing project as follows:
|
||||
|
||||
- 1. [Fork](../../../gitlab-basics/fork-project.md#how-to-fork-a-project) an [example project](https://gitlab.com/pages)
|
||||
- 2. Change a file to trigger a GitLab CI/CD pipeline
|
||||
- 3. Visit your project's **Settings > Pages** to see your **website link**, and click on it. Bam! Your website is live.
|
||||
- 1. [Fork](../../../gitlab-basics/fork-project.md#how-to-fork-a-project) an [example project](https://gitlab.com/pages):
|
||||
by forking a project, you create a copy of the codebase you're forking from to start from a template instead of starting from scratch.
|
||||
- 2. Change a file to trigger a GitLab CI/CD pipeline: GitLab CI/CD will build and deploy your site to GitLab Pages.
|
||||
- 3. Visit your project's **Settings > Pages** to see your **website link**, and click on it. Bam! Your website is live! :)
|
||||
|
||||
_Further steps (optional):_
|
||||
|
||||
- 4. Remove the [fork relationship](getting_started_part_two.md#fork-a-project-to-get-started-from) (_You don't need the relationship unless you intent to contribute back to the example project you forked from_).
|
||||
- 4. Remove the [fork relationship](getting_started_part_two.md#fork-a-project-to-get-started-from)
|
||||
(_You don't need the relationship unless you intent to contribute back to the example project you forked from_).
|
||||
- 5. Make it a [user/group website](getting_started_part_one.md#user-and-group-websites)
|
||||
|
||||
**Watch a video with the steps above: https://www.youtube.com/watch?v=TWqh9MtT4Bg**
|
||||
|
@ -27,14 +26,23 @@ _Advanced options:_
|
|||
- [Use a custom domain](getting_started_part_three.md#adding-your-custom-domain-to-gitlab-pages)
|
||||
- Apply [SSL/TLS certification](getting_started_part_three.md#ssl-tls-certificates) to your custom domain
|
||||
|
||||
## Explore GitLab Pages
|
||||
## How Does It Work?
|
||||
|
||||
With GitLab Pages you can create [static websites](getting_started_part_one.md#what-you-need-to-know-before-getting-started)
|
||||
for your GitLab projects, groups, or user accounts. You can use any static
|
||||
website generator: Jekyll, Middleman, Hexo, Hugo, Pelican, you name it!
|
||||
for your GitLab projects, groups, or user accounts.
|
||||
|
||||
It supports plain static content, such as HTML, and **all** [static site generators (SSGs)](https://about.gitlab.com/2016/06/03/ssg-overview-gitlab-pages-part-1-dynamic-x-static/), such as Jekyll, Middleman, Hexo, Hugo, and Pelican.
|
||||
|
||||
Connect as many custom domains as you like and bring your own TLS certificate
|
||||
to secure them.
|
||||
|
||||
Your files live in a project [repository](../repository/index.md) on GitLab.
|
||||
[GitLab CI](../../../ci/README.md) picks up those files and makes them available at, typically,
|
||||
`http://<username>.gilab.io/<projectname>`. Please read through the docs on
|
||||
[GitLab Pages domains](getting_started_part_one.md#gitlab-pages-domain) for more info.
|
||||
|
||||
## Explore GitLab Pages
|
||||
|
||||
Read the following tutorials to know more about:
|
||||
|
||||
- [Static websites and GitLab Pages domains](getting_started_part_one.md): Understand what is a static website, and how GitLab Pages default domains work
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
# Reducing the repository size using Git
|
||||
|
||||
A GitLab Entrerprise Edition administrator can set a [repository size limit][admin-repo-size]
|
||||
A GitLab Enterprise Edition administrator can set a [repository size limit][admin-repo-size]
|
||||
which will prevent you to exceed it.
|
||||
|
||||
When a project has reached its size limit, you will not be able to push to it,
|
||||
|
|
|
@ -96,7 +96,7 @@ On the field **Filter by name**, type the project or group name you want to find
|
|||
will filter them for you as you type.
|
||||
|
||||
You can also look for the projects you starred (**Starred projects**), and **Explore** all
|
||||
public and internal projects available in GitLab.com, from which you can filter by visibitily,
|
||||
public and internal projects available in GitLab.com, from which you can filter by visibility,
|
||||
through **Trending**, best rated with **Most starts**, or **All** of them.
|
||||
|
||||
You can also sort them by **Name**, **Last created**, **Oldest created**, **Last updated**,
|
||||
|
|
|
@ -243,7 +243,7 @@ GitLab checks files to detect LFS pointers on push. If LFS pointers are detected
|
|||
|
||||
Verify that LFS in installed locally and consider a manual push with `git lfs push --all`.
|
||||
|
||||
If you are storing LFS files outside of GitLab you can disable LFS on the project by settting `lfs_enabled: false` with the [projects api](../../api/projects.md#edit-project).
|
||||
If you are storing LFS files outside of GitLab you can disable LFS on the project by setting `lfs_enabled: false` with the [projects api](../../api/projects.md#edit-project).
|
||||
|
||||
### Hosting LFS objects externally
|
||||
|
||||
|
|
|
@ -19,6 +19,7 @@ module API
|
|||
optional :status, type: String, values: HasStatus::AVAILABLE_STATUSES,
|
||||
desc: 'The status of pipelines'
|
||||
optional :ref, type: String, desc: 'The ref of pipelines'
|
||||
optional :sha, type: String, desc: 'The sha of pipelines'
|
||||
optional :yaml_errors, type: Boolean, desc: 'Returns pipelines with invalid configurations'
|
||||
optional :name, type: String, desc: 'The name of the user who triggered pipelines'
|
||||
optional :username, type: String, desc: 'The username of the user who triggered pipelines'
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue