summaryrefslogtreecommitdiff
path: root/app
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2020-12-02 12:09:46 +0000
committerGitLab Bot <gitlab-bot@gitlab.com>2020-12-02 12:09:46 +0000
commit21e08b6197f192c983f8527f4bba1f2aaec8abf2 (patch)
treebb9183546ba5a3a1d59ed370675d54ac2c90b632 /app
parent43ae0b9e403cf774060267ee6d1a3dd502638068 (diff)
downloadgitlab-ce-21e08b6197f192c983f8527f4bba1f2aaec8abf2.tar.gz
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'app')
-rw-r--r--app/assets/images/jobs-empty-state.svg33
-rw-r--r--app/assets/javascripts/jira_connect/index.js15
-rw-r--r--app/assets/javascripts/pages/projects/jobs/index/index.js10
-rw-r--r--app/controllers/projects/jobs_controller.rb3
-rw-r--r--app/helpers/icons_helper.rb1
-rw-r--r--app/helpers/notifications_helper.rb3
-rw-r--r--app/models/audit_event.rb2
-rw-r--r--app/models/notification_setting.rb2
-rw-r--r--app/services/concerns/exclusive_lease_guard.rb2
-rw-r--r--app/services/pages/legacy_storage_lease.rb28
-rw-r--r--app/services/projects/update_pages_service.rb14
-rw-r--r--app/views/projects/commits/show.html.haml2
-rw-r--r--app/views/projects/jobs/_table.html.haml16
-rw-r--r--app/views/projects/jobs/index.html.haml4
-rw-r--r--app/workers/all_queues.yml2
-rw-r--r--app/workers/repository_update_remote_mirror_worker.rb3
16 files changed, 123 insertions, 17 deletions
diff --git a/app/assets/images/jobs-empty-state.svg b/app/assets/images/jobs-empty-state.svg
new file mode 100644
index 00000000000..e6e0681a002
--- /dev/null
+++ b/app/assets/images/jobs-empty-state.svg
@@ -0,0 +1,33 @@
+<svg width="234" height="162" viewBox="0 0 234 162" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M174.68 56.344H200.5C215.412 56.344 227.5 44.1787 227.5 29.172C227.5 14.1653 215.412 2 200.5 2C185.588 2 173.5 14.1653 173.5 29.172C173.5 36.2548 176.193 42.7046 180.604 47.5412" stroke="#C2B7E6" stroke-width="4" stroke-linecap="round"/>
+<path d="M145.5 76.4714C145.5 65.3553 154.454 56.344 165.5 56.344" stroke="#C2B7E6" stroke-width="4" stroke-linecap="round"/>
+<path d="M102.5 121.758H29.5C14.5883 121.758 2.5 109.593 2.5 94.586C2.5 79.5794 14.5883 67.4141 29.5 67.4141C44.4117 67.4141 56.5 79.5794 56.5 94.586C56.5 101.669 53.8072 108.119 49.3957 112.955" stroke="#C2B7E6" stroke-width="4" stroke-linecap="round"/>
+<path d="M67.0466 121.758H52.5C42.5589 121.758 34.5 129.868 34.5 139.873C34.5 149.877 42.5589 157.987 52.5 157.987C62.4411 157.987 70.5 149.877 70.5 139.873C70.5 137.478 70.0384 135.192 69.1998 133.1" stroke="#C2B7E6" stroke-width="4" stroke-linecap="round"/>
+<g clip-path="url(#clip0)">
+<path d="M55.0188 135.3C55.1617 134.764 54.8451 134.211 54.3117 134.068C53.7782 133.925 53.2298 134.243 53.0869 134.78L49.9811 146.445C49.8381 146.981 50.1547 147.534 50.6882 147.677C51.2217 147.821 51.77 147.503 51.9129 146.965L55.0188 135.3Z" fill="#FC6D26"/>
+<path d="M49.2071 137.142C49.5976 137.534 49.5976 138.172 49.2071 138.565L46.9142 140.873L49.2071 143.18C49.5976 143.573 49.5976 144.211 49.2071 144.603C48.8166 144.997 48.1834 144.997 47.7929 144.603L44.7929 141.584C44.4024 141.192 44.4024 140.554 44.7929 140.161L47.7929 137.142C48.1834 136.748 48.8166 136.748 49.2071 137.142Z" fill="#FC6D26"/>
+<path d="M55.7929 137.142C55.4024 137.534 55.4024 138.172 55.7929 138.565L58.0858 140.873L55.7929 143.18C55.4024 143.573 55.4024 144.211 55.7929 144.603C56.1834 144.997 56.8166 144.997 57.2071 144.603L60.2071 141.584C60.5976 141.192 60.5976 140.554 60.2071 140.161L57.2071 137.142C56.8166 136.748 56.1834 136.748 55.7929 137.142Z" fill="#FC6D26"/>
+</g>
+<path d="M212.102 160C222.815 160 231.5 151.214 231.5 140.376C231.5 129.537 222.815 120.752 212.102 120.752H151.5" stroke="#C2B7E6" stroke-width="4" stroke-linecap="round"/>
+<path d="M126.5 138.866C107.171 138.866 91.5 123.096 91.5 103.643C91.5 84.191 107.171 68.4204 126.5 68.4204C145.829 68.4204 161.5 84.191 161.5 103.643C161.5 123.096 145.829 138.866 126.5 138.866ZM126.5 131.451C141.76 131.451 154.132 119.001 154.132 103.643C154.132 88.2861 141.76 75.8358 126.5 75.8358C111.24 75.8358 98.8684 88.2861 98.8684 103.643C98.8684 119.001 111.24 131.451 126.5 131.451Z" fill="#FC6D26"/>
+<path fill-rule="evenodd" clip-rule="evenodd" d="M126.126 87.1326C135.355 87.1326 142.906 94.5624 142.906 103.643C142.906 112.724 135.355 120.154 126.126 120.154C120.672 120.154 115.638 117.265 112.281 113.137L126.126 103.643V87.1326Z" fill="#6E49CB"/>
+<g clip-path="url(#clip1)">
+<path d="M29.5 90.2659L24.3571 91.9534V93.1629C24.3571 94.9623 25.087 96.6872 26.3846 97.9546L29.5 100.997V90.2659Z" fill="#FC6D26"/>
+<path fill-rule="evenodd" clip-rule="evenodd" d="M17.5 86.8909L29.5 83.5159L41.5 86.8909V93.1115C41.5 96.6919 40.0551 100.126 37.4832 102.657L29.5 110.516L21.5168 102.657C18.9449 100.126 17.5 96.6919 17.5 93.1115V86.8909ZM20.9286 93.1115V89.4366L29.5 87.0259L38.0714 89.4366V93.1115C38.0714 95.7968 36.9878 98.3721 35.0588 100.271L29.5 105.743L23.9412 100.271C22.0122 98.3721 20.9286 95.7968 20.9286 93.1115Z" fill="#FC6D26"/>
+</g>
+<g clip-path="url(#clip2)">
+<path d="M210.857 19.7297L209.51 24.8237C208.922 27.0445 207.518 28.9576 205.581 30.1752L194.728 36.999L191.862 34.1146L198.642 23.1922C199.852 21.2431 201.753 19.8298 203.96 19.2386L209.022 17.8826C209.822 17.6681 210.644 18.1474 210.857 18.953C210.925 19.2075 210.925 19.4752 210.857 19.7297ZM207.292 21.4702L204.732 22.1561C203.261 22.5503 201.993 23.4925 201.187 24.7918L196.517 32.3146L203.992 27.6148C205.283 26.803 206.219 25.5276 206.611 24.0471L207.292 21.4702ZM196.5 38.2294L204 33.7007V35.2103C204 38.5451 201.314 41.2485 198 41.2485H196.5V38.2294ZM190.5 32.1912H187.5V30.6816C187.5 27.3468 190.186 24.6434 193.5 24.6434H195L190.5 32.1912Z" fill="#FC6D26"/>
+</g>
+<path fill-rule="evenodd" clip-rule="evenodd" d="M209.914 132.822C209.384 132.822 208.875 133.032 208.5 133.407L204.796 137.111C204.613 137.293 204.5 137.544 204.5 137.822V144.822C204.5 145.926 205.395 146.822 206.5 146.822H216.5C217.605 146.822 218.5 145.926 218.5 144.822V137.822C218.5 137.546 218.388 137.296 218.207 137.115L214.5 133.407C214.125 133.032 213.616 132.822 213.086 132.822H209.914ZM215.086 136.822L213.086 134.822H212.5V136.822H215.086ZM210.5 134.822H209.914L207.914 136.822H210.5V134.822ZM206.5 138.822H216.5V144.822H206.5V138.822Z" fill="#FC6D26"/>
+<defs>
+<clipPath id="clip0">
+<rect width="16" height="13.6779" fill="white" transform="translate(44.5 134.033)"/>
+</clipPath>
+<clipPath id="clip1">
+<rect width="24" height="27.172" fill="white" transform="translate(17.5 83.5159)"/>
+</clipPath>
+<clipPath id="clip2">
+<rect width="24" height="24.1529" fill="white" transform="translate(187.5 17.0956)"/>
+</clipPath>
+</defs>
+</svg>
diff --git a/app/assets/javascripts/jira_connect/index.js b/app/assets/javascripts/jira_connect/index.js
index 1723642d36f..a7dc71ced1c 100644
--- a/app/assets/javascripts/jira_connect/index.js
+++ b/app/assets/javascripts/jira_connect/index.js
@@ -10,19 +10,20 @@ const initJiraFormHandlers = () => {
AP.navigator.reload();
};
- const reqFailed = res => {
+ const reqFailed = (res, fallbackErrorMessage) => {
+ const { responseJSON: { error } = {} } = res || {};
// eslint-disable-next-line no-alert
- alert(res.responseJSON.error);
+ alert(error || fallbackErrorMessage);
};
AP.getLocation(location => {
- $('.js-jira-connect-sign-in').each(() => {
+ $('.js-jira-connect-sign-in').each(function updateSignInLink() {
const updatedLink = `${$(this).attr('href')}?return_to=${location}`;
$(this).attr('href', updatedLink);
});
});
- $('#add-subscription-form').on('submit', e => {
+ $('#add-subscription-form').on('submit', function onAddSubscriptionForm(e) {
const actionUrl = $(this).attr('action');
e.preventDefault();
@@ -34,11 +35,11 @@ const initJiraFormHandlers = () => {
format: 'json',
})
.done(reqComplete)
- .fail(reqFailed);
+ .fail(err => reqFailed(err, 'Failed to add namespace. Please try again.'));
});
});
- $('.remove-subscription').on('click', e => {
+ $('.remove-subscription').on('click', function onRemoveSubscriptionClick(e) {
const href = $(this).attr('href');
e.preventDefault();
@@ -53,7 +54,7 @@ const initJiraFormHandlers = () => {
},
})
.done(reqComplete)
- .fail(reqFailed);
+ .fail(err => reqFailed(err, 'Failed to remove namespace. Please try again.'));
});
});
};
diff --git a/app/assets/javascripts/pages/projects/jobs/index/index.js b/app/assets/javascripts/pages/projects/jobs/index/index.js
index 1b57c67f16b..ae04d070e62 100644
--- a/app/assets/javascripts/pages/projects/jobs/index/index.js
+++ b/app/assets/javascripts/pages/projects/jobs/index/index.js
@@ -1,5 +1,6 @@
import Vue from 'vue';
import GlCountdown from '~/vue_shared/components/gl_countdown.vue';
+import Tracking from '~/tracking';
document.addEventListener('DOMContentLoaded', () => {
const remainingTimeElements = document.querySelectorAll('.js-remaining-time');
@@ -13,4 +14,13 @@ document.addEventListener('DOMContentLoaded', () => {
},
}),
);
+
+ const trackButtonClick = () => {
+ if (gon.tracking_data) {
+ const { category, action, ...data } = gon.tracking_data;
+ Tracking.event(category, action, data);
+ }
+ };
+ const buttons = document.querySelectorAll('.js-empty-state-button');
+ buttons.forEach(button => button.addEventListener('click', trackButtonClick));
});
diff --git a/app/controllers/projects/jobs_controller.rb b/app/controllers/projects/jobs_controller.rb
index 07e38c80291..b45d9abc36f 100644
--- a/app/controllers/projects/jobs_controller.rb
+++ b/app/controllers/projects/jobs_controller.rb
@@ -17,6 +17,9 @@ class Projects::JobsController < Projects::ApplicationController
before_action do
push_frontend_feature_flag(:ci_job_line_links, @project)
end
+ before_action only: :index do
+ frontend_experimentation_tracking_data(:jobs_empty_state, 'click_button')
+ end
layout 'project'
diff --git a/app/helpers/icons_helper.rb b/app/helpers/icons_helper.rb
index dc6164ee898..23b04febe25 100644
--- a/app/helpers/icons_helper.rb
+++ b/app/helpers/icons_helper.rb
@@ -13,6 +13,7 @@ module IconsHelper
# Right now this method simply delegates directly to `fa_icon` from the
# font-awesome-rails gem, but should we ever use a different icon pack in the
# future we won't have to change hundreds of method calls.
+ # @deprecated use sprite_icon to render a SVG icon
def icon(names, options = {})
if (options.keys & %w[aria-hidden aria-label data-hidden]).empty?
# Add 'aria-hidden' and 'data-hidden' if they are not set in options.
diff --git a/app/helpers/notifications_helper.rb b/app/helpers/notifications_helper.rb
index 61fcda6a504..2b68d953431 100644
--- a/app/helpers/notifications_helper.rb
+++ b/app/helpers/notifications_helper.rb
@@ -106,7 +106,8 @@ module NotificationsHelper
when :success_pipeline
s_('NotificationEvent|Successful pipeline')
else
- s_(event.to_s.humanize)
+ event_name = "NotificationEvent|#{event.to_s.humanize}"
+ s_(event_name)
end
end
diff --git a/app/models/audit_event.rb b/app/models/audit_event.rb
index 55e8a5d4535..a4d991b040c 100644
--- a/app/models/audit_event.rb
+++ b/app/models/audit_event.rb
@@ -13,6 +13,8 @@ class AuditEvent < ApplicationRecord
:target_id
].freeze
+ self.primary_key = :id
+
serialize :details, Hash # rubocop:disable Cop/ActiveRecordSerialize
belongs_to :user, foreign_key: :author_id
diff --git a/app/models/notification_setting.rb b/app/models/notification_setting.rb
index 6066046a722..82e39e4f207 100644
--- a/app/models/notification_setting.rb
+++ b/app/models/notification_setting.rb
@@ -30,6 +30,7 @@ class NotificationSetting < ApplicationRecord
scope :preload_source_route, -> { preload(source: [:route]) }
+ # NOTE: Applicable unfound_translations.rb also needs to be updated when below events are changed.
EMAIL_EVENTS = [
:new_release,
:new_note,
@@ -51,7 +52,6 @@ class NotificationSetting < ApplicationRecord
:moved_project
].freeze
- # Update unfound_translations.rb when events are changed
def self.email_events(source = nil)
EMAIL_EVENTS
end
diff --git a/app/services/concerns/exclusive_lease_guard.rb b/app/services/concerns/exclusive_lease_guard.rb
index a58e9aefcec..76d59cf2159 100644
--- a/app/services/concerns/exclusive_lease_guard.rb
+++ b/app/services/concerns/exclusive_lease_guard.rb
@@ -21,7 +21,7 @@ module ExclusiveLeaseGuard
lease = exclusive_lease.try_obtain
unless lease
- log_error("Cannot obtain an exclusive lease for #{self.class.name}. There must be another instance already in execution.")
+ log_error("Cannot obtain an exclusive lease for #{lease_key}. There must be another instance already in execution.")
return
end
diff --git a/app/services/pages/legacy_storage_lease.rb b/app/services/pages/legacy_storage_lease.rb
new file mode 100644
index 00000000000..c39796dff91
--- /dev/null
+++ b/app/services/pages/legacy_storage_lease.rb
@@ -0,0 +1,28 @@
+# frozen_string_literal: true
+
+module Pages
+ module LegacyStorageLease
+ extend ActiveSupport::Concern
+
+ include ::ExclusiveLeaseGuard
+
+ LEASE_TIMEOUT = 1.hour
+
+ # override method from exclusive lease guard to guard it by feature flag
+ # TODO: just remove this method after testing this in production
+ # https://gitlab.com/gitlab-org/gitlab/-/issues/282464
+ def try_obtain_lease
+ return yield unless Feature.enabled?(:pages_use_legacy_storage_lease, project)
+
+ super
+ end
+
+ def lease_key
+ "pages_legacy_storage:#{project.id}"
+ end
+
+ def lease_timeout
+ LEASE_TIMEOUT
+ end
+ end
+end
diff --git a/app/services/projects/update_pages_service.rb b/app/services/projects/update_pages_service.rb
index f4a08169af7..53872c67f49 100644
--- a/app/services/projects/update_pages_service.rb
+++ b/app/services/projects/update_pages_service.rb
@@ -4,6 +4,9 @@ module Projects
class UpdatePagesService < BaseService
InvalidStateError = Class.new(StandardError)
FailedToExtractError = Class.new(StandardError)
+ ExclusiveLeaseTaken = Class.new(StandardError)
+
+ include ::Pages::LegacyStorageLease
BLOCK_SIZE = 32.kilobytes
PUBLIC_DIR = 'public'
@@ -109,6 +112,17 @@ module Projects
end
def deploy_page!(archive_public_path)
+ deployed = try_obtain_lease do
+ deploy_page_unsafe!(archive_public_path)
+ true
+ end
+
+ unless deployed
+ raise ExclusiveLeaseTaken, "Failed to deploy pages - other deployment is in progress"
+ end
+ end
+
+ def deploy_page_unsafe!(archive_public_path)
# Do atomic move of pages
# Move and removal may not be atomic, but they are significantly faster then extracting and removal
# 1. We move deployed public to previous public path (file removal is slow)
diff --git a/app/views/projects/commits/show.html.haml b/app/views/projects/commits/show.html.haml
index 94bdab53cd0..a14f75259ec 100644
--- a/app/views/projects/commits/show.html.haml
+++ b/app/views/projects/commits/show.html.haml
@@ -24,7 +24,7 @@
.control
= form_tag(project_commits_path(@project, @id), method: :get, class: 'commits-search-form js-signature-container', data: { 'signatures-path' => namespace_project_signatures_path }) do
- = search_field_tag :search, params[:search], { placeholder: _('Search by message'), id: 'commits-search', class: 'form-control search-text-input input-short gl-mt-3 gl-sm-mt-0 gl-min-w-full', spellcheck: false }
+ = search_field_tag :search, params[:search], { placeholder: _('Search by message'), id: 'commits-search', class: 'form-control gl-form-input input-short gl-mt-3 gl-sm-mt-0 gl-min-w-full gl-inset-border-1-gray-200!', spellcheck: false }
.control.d-none.d-md-block
= link_to project_commits_path(@project, @ref, rss_url_options), title: _("Commits feed"), class: 'btn gl-button btn-svg' do
= sprite_icon('rss', css_class: 'qa-rss-icon')
diff --git a/app/views/projects/jobs/_table.html.haml b/app/views/projects/jobs/_table.html.haml
index b08223546f7..b126b452dea 100644
--- a/app/views/projects/jobs/_table.html.haml
+++ b/app/views/projects/jobs/_table.html.haml
@@ -1,8 +1,20 @@
- admin = local_assigns.fetch(:admin, false)
- if builds.blank?
- %div
- .nothing-here-block No jobs to show
+ - if experiment_enabled?(:jobs_empty_state)
+ .row.empty-state
+ .col-12
+ .svg-content.svg-250
+ = image_tag('jobs-empty-state.svg')
+ .col-12
+ .text-content.gl-text-center
+ %h4
+ = s_('Jobs|Use jobs to automate your tasks')
+ %p
+ = s_('Jobs|Jobs are the building blocks of a GitLab CI/CD pipeline. Each job has a specific task, like testing code. To set up jobs in a CI/CD pipeline, add a CI/CD configuration file to your project.')
+ = link_to s_('Jobs|Create CI/CD configuration file'), help_page_path('ci/quick_start/README'), class: 'btn gl-button btn-info js-empty-state-button'
+ - else
+ .nothing-here-block= s_('Jobs|No jobs to show')
- else
.table-holder
%table.table.ci-table.builds-page
diff --git a/app/views/projects/jobs/index.html.haml b/app/views/projects/jobs/index.html.haml
index a1960fc99cf..cd062fcf675 100644
--- a/app/views/projects/jobs/index.html.haml
+++ b/app/views/projects/jobs/index.html.haml
@@ -7,8 +7,8 @@
.nav-controls
- if can?(current_user, :update_build, @project)
- - unless @repository.gitlab_ci_yml
- = link_to 'Get started with Pipelines', help_page_path('ci/quick_start/README'), class: 'btn gl-button btn-info'
+ - if !@repository.gitlab_ci_yml && !experiment_enabled?(:jobs_empty_state)
+ = link_to 'Get started with Pipelines', help_page_path('ci/quick_start/README'), class: 'btn gl-button btn-info js-empty-state-button'
= link_to project_ci_lint_path(@project), class: 'btn gl-button btn-default' do
%span CI lint
diff --git a/app/workers/all_queues.yml b/app/workers/all_queues.yml
index ec64467f46d..56978287583 100644
--- a/app/workers/all_queues.yml
+++ b/app/workers/all_queues.yml
@@ -2021,7 +2021,7 @@
:urgency: :low
:resource_boundary: :unknown
:weight: 1
- :idempotent:
+ :idempotent: true
:tags: []
- :name: self_monitoring_project_create
:feature_category: :metrics
diff --git a/app/workers/repository_update_remote_mirror_worker.rb b/app/workers/repository_update_remote_mirror_worker.rb
index 21b5916f459..483aae84a3b 100644
--- a/app/workers/repository_update_remote_mirror_worker.rb
+++ b/app/workers/repository_update_remote_mirror_worker.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-class RepositoryUpdateRemoteMirrorWorker # rubocop:disable Scalability/IdempotentWorker
+class RepositoryUpdateRemoteMirrorWorker
UpdateError = Class.new(StandardError)
include ApplicationWorker
@@ -11,6 +11,7 @@ class RepositoryUpdateRemoteMirrorWorker # rubocop:disable Scalability/Idempoten
sidekiq_options retry: 3, dead: false
feature_category :source_code_management
loggable_arguments 1
+ idempotent!
LOCK_WAIT_TIME = 30.seconds
MAX_TRIES = 3