Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2019-11-13 09:06:41 +00:00
parent 213ce78058
commit 4f01ac5ba0
33 changed files with 359 additions and 279 deletions

View File

@ -124,8 +124,10 @@ export default {
:diff-viewer-mode="diffViewerMode"
:new-path="diffFile.new_path"
:new-sha="diffFile.diff_refs.head_sha"
:new-size="diffFile.new_size"
:old-path="diffFile.old_path"
:old-sha="diffFile.diff_refs.base_sha"
:old-size="diffFile.old_size"
:file-hash="diffFileHash"
:project-path="projectPath"
:a-mode="diffFile.a_mode"

View File

@ -26,8 +26,11 @@ export default (resolvers = {}, config = {}) => {
createUploadLink(httpOptions),
new BatchHttpLink(httpOptions),
),
cache: new InMemoryCache({ ...config.cacheConfig, freezeResults: true }),
cache: new InMemoryCache({
...config.cacheConfig,
freezeResults: config.assumeImmutableResults,
}),
resolvers,
assumeImmutableResults: true,
assumeImmutableResults: config.assumeImmutableResults,
});
};

View File

@ -187,8 +187,11 @@ export default {
firstDashboard() {
return this.allDashboards[0] || {};
},
selectedDashboard() {
return this.allDashboards.find(d => d.path === this.currentDashboard) || this.firstDashboard;
},
selectedDashboardText() {
return this.currentDashboard || this.firstDashboard.display_name;
return this.selectedDashboard.display_name;
},
showRearrangePanelsBtn() {
return !this.showEmptyState && this.rearrangePanelsAvailable;
@ -199,6 +202,14 @@ export default {
alertWidgetAvailable() {
return IS_EE && this.prometheusAlertsAvailable && this.alertsEndpoint;
},
hasHeaderButtons() {
return (
this.addingMetricsAvailable ||
this.showRearrangePanelsBtn ||
this.selectedDashboard.can_edit ||
this.externalDashboardUrl.length
);
},
},
created() {
this.setEndpoints({
@ -390,7 +401,7 @@ export default {
</template>
<gl-form-group
v-if="addingMetricsAvailable || showRearrangePanelsBtn || externalDashboardUrl.length"
v-if="hasHeaderButtons"
label-for="prometheus-graphs-dropdown-buttons"
class="dropdown-buttons col-md d-md-flex col-lg d-lg-flex align-items-end"
>
@ -437,6 +448,14 @@ export default {
</div>
</gl-modal>
<gl-button
v-if="selectedDashboard.can_edit"
class="mt-1 js-edit-link"
:href="selectedDashboard.project_blob_path"
>
{{ __('Edit dashboard') }}
</gl-button>
<gl-button
v-if="externalDashboardUrl.length"
class="mt-1 js-external-dashboard-link"

View File

@ -6,8 +6,6 @@ import initSettingsPanels from '~/settings_panels';
document.addEventListener('DOMContentLoaded', () => {
mountErrorTrackingForm();
mountOperationSettings();
if (gon.features.gfmGrafanaIntegration) {
mountGrafanaIntegration();
}
mountGrafanaIntegration();
initSettingsPanels();
});

View File

@ -23,6 +23,11 @@ export default {
type: String,
required: true,
},
newSize: {
type: Number,
required: false,
default: 0,
},
oldPath: {
type: String,
required: true,
@ -31,6 +36,11 @@ export default {
type: String,
required: true,
},
oldSize: {
type: Number,
required: false,
default: 0,
},
projectPath: {
type: String,
required: false,
@ -85,6 +95,8 @@ export default {
:diff-mode="diffMode"
:new-path="fullNewPath"
:old-path="fullOldPath"
:old-size="oldSize"
:new-size="newSize"
:project-path="projectPath"
:a-mode="aMode"
:b-mode="bMode"

View File

@ -14,6 +14,16 @@ export default {
type: String,
required: true,
},
newSize: {
type: Number,
required: false,
default: 0,
},
oldSize: {
type: Number,
required: false,
default: 0,
},
},
};
</script>
@ -22,12 +32,14 @@ export default {
<div class="two-up view d-flex">
<image-viewer
:path="oldPath"
:file-size="oldSize"
:render-info="true"
inner-css-classes="frame deleted"
class="wrap w-50"
/>
<image-viewer
:path="newPath"
:file-size="newSize"
:render-info="true"
:inner-css-classes="['frame', 'added']"
class="wrap w-50"

View File

@ -22,6 +22,16 @@ export default {
type: String,
required: true,
},
newSize: {
type: Number,
required: false,
default: 0,
},
oldSize: {
type: Number,
required: false,
default: 0,
},
},
data() {
return {

View File

@ -20,11 +20,11 @@ class ApplicationController < ActionController::Base
before_action :authenticate_user!, except: [:route_not_found]
before_action :enforce_terms!, if: :should_enforce_terms?
before_action :validate_user_service_ticket!
before_action :check_password_expiration
before_action :check_password_expiration, if: :html_request?
before_action :ldap_security_check
before_action :sentry_context
before_action :default_headers
before_action :add_gon_variables, unless: [:peek_request?, :json_request?]
before_action :add_gon_variables, if: :html_request?
before_action :configure_permitted_parameters, if: :devise_controller?
before_action :require_email, unless: :devise_controller?
before_action :active_user_check, unless: :devise_controller?
@ -455,8 +455,8 @@ class ApplicationController < ActionController::Base
response.headers['Page-Title'] = URI.escape(page_title('GitLab'))
end
def peek_request?
request.path.start_with?('/-/peek')
def html_request?
request.format.html?
end
def json_request?
@ -466,7 +466,7 @@ class ApplicationController < ActionController::Base
def should_enforce_terms?
return false unless Gitlab::CurrentSettings.current_application_settings.enforce_terms
!(peek_request? || devise_controller?)
html_request? && !devise_controller?
end
def set_usage_stats_consent_flag

View File

@ -4,15 +4,18 @@ module ConfirmEmailWarning
extend ActiveSupport::Concern
included do
before_action :set_confirm_warning, if: -> { Feature.enabled?(:soft_email_confirmation) }
before_action :set_confirm_warning, if: :show_confirm_warning?
end
protected
def show_confirm_warning?
html_request? && request.get? && Feature.enabled?(:soft_email_confirmation)
end
def set_confirm_warning
return unless current_user
return if current_user.confirmed?
return if peek_request? || json_request? || !request.get?
email = current_user.unconfirmed_email || current_user.email

View File

@ -1,11 +1,16 @@
# frozen_string_literal: true
module UploadsActions
extend ActiveSupport::Concern
include Gitlab::Utils::StrongMemoize
include SendFileUpload
UPLOAD_MOUNTS = %w(avatar attachment file logo header_logo favicon).freeze
included do
prepend_before_action :set_request_format_from_path_extension
end
def create
uploader = UploadService.new(model, params[:file], uploader_class).execute
@ -64,6 +69,18 @@ module UploadsActions
private
# From ActionDispatch::Http::MimeNegotiation. We have an initializer that
# monkey-patches this method out (so that repository paths don't guess a
# format based on extension), but we do want this behaviour when serving
# uploads.
def set_request_format_from_path_extension
path = request.headers['action_dispatch.original_path'] || request.headers['PATH_INFO']
if match = path&.match(/\.(\w+)\z/)
request.format = match.captures.first
end
end
def uploader_class
raise NotImplementedError
end

View File

@ -4,8 +4,6 @@ class Projects::GrafanaApiController < Projects::ApplicationController
include RenderServiceResults
include MetricsDashboard
before_action :validate_feature_enabled!, only: [:metrics_dashboard]
def proxy
result = ::Grafana::ProxyService.new(
project,
@ -26,10 +24,6 @@ class Projects::GrafanaApiController < Projects::ApplicationController
params.permit(:embedded, :grafana_url)
end
def validate_feature_enabled!
render_403 unless Feature.enabled?(:gfm_grafana_integration)
end
def query_params
params.permit(:query, :start, :end, :step)
end

View File

@ -7,25 +7,6 @@ class ExpireBuildArtifactsWorker
feature_category :continuous_integration
def perform
if Feature.enabled?(:ci_new_expire_job_artifacts_service, default_enabled: true)
perform_efficient_artifacts_removal
else
perform_legacy_artifacts_removal
end
end
def perform_efficient_artifacts_removal
Ci::DestroyExpiredJobArtifactsService.new.execute
end
# rubocop: disable CodeReuse/ActiveRecord
def perform_legacy_artifacts_removal
Rails.logger.info 'Scheduling removal of build artifacts' # rubocop:disable Gitlab/RailsLogger
build_ids = Ci::Build.with_expired_artifacts.pluck(:id)
build_ids = build_ids.map { |build_id| [build_id] }
ExpireBuildInstanceArtifactsWorker.bulk_perform_async(build_ids)
end
# rubocop: enable CodeReuse/ActiveRecord
end

View File

@ -0,0 +1,5 @@
---
title: Add edit button to metrics dashboard
merge_request: 19279
author:
type: added

View File

@ -0,0 +1,5 @@
---
title: Update SaaS trial header to include the tier Gold
merge_request: 19970
author:
type: changed

View File

@ -0,0 +1,5 @@
---
title: Re-add missing file sizes in 2-Up diff file viewer
merge_request: 19710
author:
type: fixed

View File

@ -0,0 +1,5 @@
---
title: Allow Grafana charts to be embedded in Gitlab Flavored Markdown
merge_request: 18486
author:
type: added

View File

@ -18,8 +18,6 @@ module Banzai
end
def embed_params(node)
return unless Feature.enabled?(:gfm_grafana_integration)
query_params = Gitlab::Metrics::Dashboard::Url.parse_query(node['href'])
return unless [:panelId, :from, :to].all? do |param|
query_params.include?(param)

View File

@ -42,9 +42,6 @@ module Gitlab
# Initialize gon.features with any flags that should be
# made globally available to the frontend
push_frontend_feature_flag(:suppress_ajax_navigation_errors, default_enabled: true)
# Flag controls a GFM feature used across many routes.
push_frontend_feature_flag(:gfm_grafana_integration)
end
# Exposes the state of a feature flag to the frontend code.

View File

@ -6022,6 +6022,9 @@ msgstr ""
msgid "Edit comment"
msgstr ""
msgid "Edit dashboard"
msgstr ""
msgid "Edit description"
msgstr ""
@ -6442,6 +6445,9 @@ msgstr ""
msgid "Environments|No deployments yet"
msgstr ""
msgid "Environments|No pods to display"
msgstr ""
msgid "Environments|Note that this action will stop the environment, but it will %{emphasisStart}not%{emphasisEnd} have an effect on any existing deployment due to no “stop environment action” being defined in the %{ciConfigLinkStart}.gitlab-ci.yml%{ciConfigLinkEnd} file."
msgstr ""
@ -16145,7 +16151,7 @@ msgstr ""
msgid "Start a %{new_merge_request} with these changes"
msgstr ""
msgid "Start a Free Trial"
msgid "Start a Free Gold Trial"
msgstr ""
msgid "Start a new discussion..."

View File

@ -41,7 +41,7 @@
"@gitlab/ui": "7.5.0",
"@gitlab/visual-review-tools": "1.0.3",
"@sentry/browser": "^5.7.1",
"apollo-cache-inmemory": "^1.5.1",
"apollo-cache-inmemory": "^1.6.3",
"apollo-client": "^2.6.4",
"apollo-link": "^1.2.11",
"apollo-link-batch-http": "^1.2.11",

View File

@ -90,14 +90,6 @@ describe ApplicationController do
let(:format) { :html }
it_behaves_like 'setting gon variables'
context 'for peek requests' do
before do
request.path = '/-/peek'
end
it_behaves_like 'not setting gon variables'
end
end
context 'with json format' do
@ -105,6 +97,12 @@ describe ApplicationController do
it_behaves_like 'not setting gon variables'
end
context 'with atom format' do
let(:format) { :atom }
it_behaves_like 'not setting gon variables'
end
end
describe 'session expiration' do

View File

@ -164,17 +164,5 @@ describe Projects::GrafanaApiController do
it_behaves_like 'error response', :bad_request
end
end
context 'when grafana embeds are not enabled' do
before do
stub_feature_flags(gfm_grafana_integration: false)
end
it 'returns 403 immediately' do
get :metrics_dashboard, params: params
expect(response).to have_gitlab_http_status(:forbidden)
end
end
end
end

View File

@ -228,10 +228,10 @@ describe UploadsController do
user.block
end
it "redirects to the sign in page" do
it "responds with status 401" do
get :show, params: { model: "user", mounted_as: "avatar", id: user.id, filename: "dk.png" }
expect(response).to redirect_to(new_user_session_path)
expect(response).to have_gitlab_http_status(401)
end
end
@ -320,10 +320,10 @@ describe UploadsController do
end
context "when not signed in" do
it "redirects to the sign in page" do
it "responds with status 401" do
get :show, params: { model: "project", mounted_as: "avatar", id: project.id, filename: "dk.png" }
expect(response).to redirect_to(new_user_session_path)
expect(response).to have_gitlab_http_status(401)
end
end
@ -343,10 +343,10 @@ describe UploadsController do
project.add_maintainer(user)
end
it "redirects to the sign in page" do
it "responds with status 401" do
get :show, params: { model: "project", mounted_as: "avatar", id: project.id, filename: "dk.png" }
expect(response).to redirect_to(new_user_session_path)
expect(response).to have_gitlab_http_status(401)
end
end
@ -439,10 +439,10 @@ describe UploadsController do
user.block
end
it "redirects to the sign in page" do
it "responds with status 401" do
get :show, params: { model: "group", mounted_as: "avatar", id: group.id, filename: "dk.png" }
expect(response).to redirect_to(new_user_session_path)
expect(response).to have_gitlab_http_status(401)
end
end
@ -526,10 +526,10 @@ describe UploadsController do
end
context "when not signed in" do
it "redirects to the sign in page" do
it "responds with status 401" do
get :show, params: { model: "note", mounted_as: "attachment", id: note.id, filename: "dk.png" }
expect(response).to redirect_to(new_user_session_path)
expect(response).to have_gitlab_http_status(401)
end
end
@ -549,10 +549,10 @@ describe UploadsController do
project.add_maintainer(user)
end
it "redirects to the sign in page" do
it "responds with status 401" do
get :show, params: { model: "note", mounted_as: "attachment", id: note.id, filename: "dk.png" }
expect(response).to redirect_to(new_user_session_path)
expect(response).to have_gitlab_http_status(401)
end
end

View File

@ -104,17 +104,7 @@ describe 'Projects > Settings > For a forked project', :js do
end
context 'grafana integration settings form' do
it 'is not present when the feature flag is disabled' do
stub_feature_flags(gfm_grafana_integration: false)
visit project_settings_operations_path(project)
wait_for_requests
expect(page).to have_no_css('.js-grafana-integration')
end
it 'is present when the feature flag is enabled' do
it 'successfully fills and completes the form' do
visit project_settings_operations_path(project)
wait_for_requests

View File

@ -0,0 +1,45 @@
import { shallowMount } from '@vue/test-utils';
import ImageViewer from '~/vue_shared/components/content_viewer/viewers/image_viewer.vue';
import { GREEN_BOX_IMAGE_URL } from 'spec/test_constants';
describe('Image Viewer', () => {
const requiredProps = {
path: GREEN_BOX_IMAGE_URL,
renderInfo: true,
};
let wrapper;
let imageInfo;
function createElement({ props, includeRequired = true } = {}) {
const data = includeRequired ? { ...requiredProps, ...props } : { ...props };
wrapper = shallowMount(ImageViewer, {
propsData: data,
});
imageInfo = wrapper.find('.image-info');
}
describe('file sizes', () => {
it('should show the humanized file size when `renderInfo` is true and there is size info', () => {
createElement({ props: { fileSize: 1024 } });
expect(imageInfo.text()).toContain('1.00 KiB');
});
it('should not show the humanized file size when `renderInfo` is true and there is no size', () => {
const FILESIZE_RE = /\d+(\.\d+)?\s*([KMGTP]i)*B/;
createElement({ props: { fileSize: 0 } });
// It shouldn't show any filesize info
expect(imageInfo.text()).not.toMatch(FILESIZE_RE);
});
it('should not show any image information when `renderInfo` is false', () => {
createElement({ props: { renderInfo: false } });
expect(imageInfo.exists()).toBe(false);
});
});
});

View File

@ -623,6 +623,49 @@ describe('Dashboard', () => {
});
});
describe('dashboard edit link', () => {
let wrapper;
const findEditLink = () => wrapper.find('.js-edit-link');
beforeEach(done => {
mock.onGet(mockApiEndpoint).reply(200, metricsGroupsAPIResponse);
wrapper = shallowMount(DashboardComponent, {
localVue,
sync: false,
attachToDocument: true,
propsData: { ...propsData, hasMetrics: true },
store,
});
wrapper.vm.$store.commit(
`monitoringDashboard/${types.SET_ALL_DASHBOARDS}`,
dashboardGitResponse,
);
wrapper.vm.$nextTick(done);
});
afterEach(() => {
wrapper.destroy();
});
it('is not present for the default dashboard', () => {
expect(findEditLink().exists()).toBe(false);
});
it('is present for a custom dashboard, and links to its edit_path', done => {
const dashboard = dashboardGitResponse[1]; // non-default dashboard
const currentDashboard = dashboard.path;
wrapper.setProps({ currentDashboard });
wrapper.vm.$nextTick(() => {
expect(findEditLink().exists()).toBe(true);
expect(findEditLink().attributes('href')).toBe(dashboard.project_blob_path);
done();
});
});
});
describe('external dashboard link', () => {
beforeEach(() => {
mock.onGet(mockApiEndpoint).reply(200, metricsGroupsAPIResponse);

View File

@ -931,14 +931,25 @@ export const metricsDashboardResponse = {
export const dashboardGitResponse = [
{
path: 'config/prometheus/common_metrics.yml',
display_name: 'Common Metrics',
default: true,
display_name: 'Default',
can_edit: false,
project_blob_path: null,
path: 'config/prometheus/common_metrics.yml',
},
{
path: '.gitlab/dashboards/super.yml',
display_name: 'Custom Dashboard 1',
default: false,
display_name: 'Custom Dashboard 1',
can_edit: true,
project_blob_path: `${mockProjectPath}/blob/master/dashboards/.gitlab/dashboards/dashboard_1.yml`,
path: '.gitlab/dashboards/dashboard_1.yml',
},
{
default: false,
display_name: 'Custom Dashboard 2',
can_edit: true,
project_blob_path: `${mockProjectPath}/blob/master/dashboards/.gitlab/dashboards/dashboard_2.yml`,
path: '.gitlab/dashboards/dashboard_2.yml',
},
];

View File

@ -1,13 +1,23 @@
import Vue from 'vue';
import diffViewer from '~/vue_shared/components/diff_viewer/diff_viewer.vue';
import mountComponent from 'spec/helpers/vue_mount_component_helper';
import { GREEN_BOX_IMAGE_URL, RED_BOX_IMAGE_URL } from 'spec/test_constants';
describe('DiffViewer', () => {
const requiredProps = {
diffMode: 'replaced',
diffViewerMode: 'image',
newPath: GREEN_BOX_IMAGE_URL,
newSha: 'ABC',
oldPath: RED_BOX_IMAGE_URL,
oldSha: 'DEF',
};
let vm;
function createComponent(props) {
const DiffViewer = Vue.extend(diffViewer);
vm = mountComponent(DiffViewer, props);
}
@ -20,15 +30,11 @@ describe('DiffViewer', () => {
relative_url_root: '',
};
createComponent({
diffMode: 'replaced',
diffViewerMode: 'image',
newPath: GREEN_BOX_IMAGE_URL,
newSha: 'ABC',
oldPath: RED_BOX_IMAGE_URL,
oldSha: 'DEF',
projectPath: '',
});
createComponent(
Object.assign({}, requiredProps, {
projectPath: '',
}),
);
setTimeout(() => {
expect(vm.$el.querySelector('.deleted img').getAttribute('src')).toBe(
@ -44,14 +50,13 @@ describe('DiffViewer', () => {
});
it('renders fallback download diff display', done => {
createComponent({
diffMode: 'replaced',
diffViewerMode: 'added',
newPath: 'test.abc',
newSha: 'ABC',
oldPath: 'testold.abc',
oldSha: 'DEF',
});
createComponent(
Object.assign({}, requiredProps, {
diffViewerMode: 'added',
newPath: 'test.abc',
oldPath: 'testold.abc',
}),
);
setTimeout(() => {
expect(vm.$el.querySelector('.deleted .file-info').textContent.trim()).toContain(
@ -72,29 +77,28 @@ describe('DiffViewer', () => {
});
it('renders renamed component', () => {
createComponent({
diffMode: 'renamed',
diffViewerMode: 'renamed',
newPath: 'test.abc',
newSha: 'ABC',
oldPath: 'testold.abc',
oldSha: 'DEF',
});
createComponent(
Object.assign({}, requiredProps, {
diffMode: 'renamed',
diffViewerMode: 'renamed',
newPath: 'test.abc',
oldPath: 'testold.abc',
}),
);
expect(vm.$el.textContent).toContain('File moved');
});
it('renders mode changed component', () => {
createComponent({
diffMode: 'mode_changed',
diffViewerMode: 'image',
newPath: 'test.abc',
newSha: 'ABC',
oldPath: 'testold.abc',
oldSha: 'DEF',
aMode: '123',
bMode: '321',
});
createComponent(
Object.assign({}, requiredProps, {
diffMode: 'mode_changed',
newPath: 'test.abc',
oldPath: 'testold.abc',
aMode: '123',
bMode: '321',
}),
);
expect(vm.$el.textContent).toContain('File mode changed from 123 to 321');
});

View File

@ -4,6 +4,11 @@ import mountComponent from 'spec/helpers/vue_mount_component_helper';
import { GREEN_BOX_IMAGE_URL, RED_BOX_IMAGE_URL } from 'spec/test_constants';
describe('ImageDiffViewer', () => {
const requiredProps = {
diffMode: 'replaced',
newPath: GREEN_BOX_IMAGE_URL,
oldPath: RED_BOX_IMAGE_URL,
};
let vm;
function createComponent(props) {
@ -45,11 +50,7 @@ describe('ImageDiffViewer', () => {
});
it('renders image diff for replaced', done => {
createComponent({
diffMode: 'replaced',
newPath: GREEN_BOX_IMAGE_URL,
oldPath: RED_BOX_IMAGE_URL,
});
createComponent(requiredProps);
setTimeout(() => {
expect(vm.$el.querySelector('.added img').getAttribute('src')).toBe(GREEN_BOX_IMAGE_URL);
@ -70,11 +71,12 @@ describe('ImageDiffViewer', () => {
});
it('renders image diff for new', done => {
createComponent({
diffMode: 'new',
newPath: GREEN_BOX_IMAGE_URL,
oldPath: '',
});
createComponent(
Object.assign({}, requiredProps, {
diffMode: 'new',
oldPath: '',
}),
);
setTimeout(() => {
expect(vm.$el.querySelector('.added img').getAttribute('src')).toBe(GREEN_BOX_IMAGE_URL);
@ -84,11 +86,12 @@ describe('ImageDiffViewer', () => {
});
it('renders image diff for deleted', done => {
createComponent({
diffMode: 'deleted',
newPath: '',
oldPath: RED_BOX_IMAGE_URL,
});
createComponent(
Object.assign({}, requiredProps, {
diffMode: 'deleted',
newPath: '',
}),
);
setTimeout(() => {
expect(vm.$el.querySelector('.deleted img').getAttribute('src')).toBe(RED_BOX_IMAGE_URL);
@ -119,11 +122,7 @@ describe('ImageDiffViewer', () => {
describe('swipeMode', () => {
beforeEach(done => {
createComponent({
diffMode: 'replaced',
newPath: GREEN_BOX_IMAGE_URL,
oldPath: RED_BOX_IMAGE_URL,
});
createComponent(requiredProps);
setTimeout(() => {
done();
@ -142,11 +141,7 @@ describe('ImageDiffViewer', () => {
describe('onionSkin', () => {
beforeEach(done => {
createComponent({
diffMode: 'replaced',
newPath: GREEN_BOX_IMAGE_URL,
oldPath: RED_BOX_IMAGE_URL,
});
createComponent(requiredProps);
setTimeout(() => {
done();

View File

@ -18,16 +18,6 @@ describe Banzai::Filter::InlineGrafanaMetricsFilter do
'&var-instance=All&panelId=14'
end
context 'when feature flag is disabled' do
before do
stub_feature_flags(gfm_grafana_integration: false)
end
it 'leaves the markdown unchanged' do
expect(unescape(doc.to_s)).to eq(input)
end
end
it 'appends a metrics charts placeholder with dashboard url after metrics links' do
node = doc.at_css('.js-render-metrics')
expect(node).to be_present

View File

@ -0,0 +1,36 @@
# frozen_string_literal: true
require 'spec_helper'
describe 'Loading a user avatar' do
let(:user) { create(:user, :with_avatar) }
context 'when logged in' do
# The exact query count will vary depending on the 2FA settings of the
# instance, group, and user. Removing those extra 2FA queries in this case
# may not be a good idea, so we just set up the ideal case.
before do
stub_application_setting(require_two_factor_authentication: true)
login_as(create(:user, :two_factor))
end
# One each for: current user, avatar user, and upload record
it 'only performs three SQL queries' do
get user.avatar_url # Skip queries on first application load
expect(response).to have_gitlab_http_status(200)
expect { get user.avatar_url }.not_to exceed_query_limit(3)
end
end
context 'when logged out' do
# One each for avatar user and upload record
it 'only performs two SQL queries' do
get user.avatar_url # Skip queries on first application load
expect(response).to have_gitlab_http_status(200)
expect { get user.avatar_url }.not_to exceed_query_limit(2)
end
end
end

View File

@ -3,62 +3,11 @@
require 'spec_helper'
describe ExpireBuildArtifactsWorker do
include RepoHelpers
let(:worker) { described_class.new }
before do
Sidekiq::Worker.clear_all
end
describe '#perform' do
before do
stub_feature_flags(ci_new_expire_job_artifacts_service: false)
build
end
subject! do
Sidekiq::Testing.fake! { worker.perform }
end
context 'with expired artifacts' do
let(:build) { create(:ci_build, :artifacts, artifacts_expire_at: Time.now - 7.days) }
it 'enqueues that build' do
expect(jobs_enqueued.size).to eq(1)
expect(jobs_enqueued[0]["args"]).to eq([build.id])
end
end
context 'with not yet expired artifacts' do
let(:build) { create(:ci_build, :artifacts, artifacts_expire_at: Time.now + 7.days) }
it 'does not enqueue that build' do
expect(jobs_enqueued.size).to eq(0)
end
end
context 'without expire date' do
let(:build) { create(:ci_build, :artifacts) }
it 'does not enqueue that build' do
expect(jobs_enqueued.size).to eq(0)
end
end
def jobs_enqueued
Sidekiq::Queues.jobs_by_worker['ExpireBuildInstanceArtifactsWorker']
end
end
describe '#perform with ci_new_expire_job_artifacts_service feature flag' do
before do
stub_feature_flags(ci_new_expire_job_artifacts_service: true)
end
it 'executes a service' do
expect_any_instance_of(Ci::DestroyExpiredJobArtifactsService).to receive(:execute)
expect(ExpireBuildInstanceArtifactsWorker).not_to receive(:bulk_perform_async)
worker.perform
end

View File

@ -1052,7 +1052,7 @@
resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-3.0.3.tgz#3dca0e3f33b200fc7d1139c0cd96c1268cadfd9d"
integrity sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA==
"@types/node@*", "@types/node@^10.11.7":
"@types/node@*", "@types/node@>=6", "@types/node@^10.11.7":
version "10.12.9"
resolved "https://registry.yarnpkg.com/@types/node/-/node-10.12.9.tgz#a07bfa74331471e1dc22a47eb72026843f7b95c8"
integrity sha512-eajkMXG812/w3w4a1OcBlaTwsFPO5F7fJ/amy+tieQxEMWBlbV1JGSjkFM+zkHNf81Cad+dfIRA+IBkvmvdAeA==
@ -1310,6 +1310,14 @@
"@webassemblyjs/wast-parser" "1.8.5"
"@xtuc/long" "4.2.2"
"@wry/context@^0.4.0":
version "0.4.4"
resolved "https://registry.yarnpkg.com/@wry/context/-/context-0.4.4.tgz#e50f5fa1d6cfaabf2977d1fda5ae91717f8815f8"
integrity sha512-LrKVLove/zw6h2Md/KZyWxIkFM6AoyKp71OqpH9Hiip1csjPVoD3tPxlbQUNxEnHENks3UGgNpSBCAfq9KWuag==
dependencies:
"@types/node" ">=6"
tslib "^1.9.3"
"@wry/equality@^0.1.2":
version "0.1.9"
resolved "https://registry.yarnpkg.com/@wry/equality/-/equality-0.1.9.tgz#b13e18b7a8053c6858aa6c85b54911fb31e3a909"
@ -1473,18 +1481,18 @@ anymatch@^3.0.1:
normalize-path "^3.0.0"
picomatch "^2.0.4"
apollo-cache-inmemory@^1.5.1:
version "1.5.1"
resolved "https://registry.yarnpkg.com/apollo-cache-inmemory/-/apollo-cache-inmemory-1.5.1.tgz#265d1ee67b0bf0aca9c37629d410bfae44e62953"
integrity sha512-D3bdpPmWfaKQkWy8lfwUg+K8OBITo3sx0BHLs1B/9vIdOIZ7JNCKq3EUcAgAfInomJUdN0QG1yOfi8M8hxkN1g==
apollo-cache-inmemory@^1.6.3:
version "1.6.3"
resolved "https://registry.yarnpkg.com/apollo-cache-inmemory/-/apollo-cache-inmemory-1.6.3.tgz#826861d20baca4abc45f7ca7a874105905b8525d"
integrity sha512-S4B/zQNSuYc0M/1Wq8dJDTIO9yRgU0ZwDGnmlqxGGmFombOZb9mLjylewSfQKmjNpciZ7iUIBbJ0mHlPJTzdXg==
dependencies:
apollo-cache "^1.2.1"
apollo-utilities "^1.2.1"
optimism "^0.6.9"
ts-invariant "^0.2.1"
apollo-cache "^1.3.2"
apollo-utilities "^1.3.2"
optimism "^0.10.0"
ts-invariant "^0.4.0"
tslib "^1.9.3"
apollo-cache@1.3.2, apollo-cache@^1.2.1:
apollo-cache@1.3.2, apollo-cache@^1.3.2:
version "1.3.2"
resolved "https://registry.yarnpkg.com/apollo-cache/-/apollo-cache-1.3.2.tgz#df4dce56240d6c95c613510d7e409f7214e6d26a"
integrity sha512-+KA685AV5ETEJfjZuviRTEImGA11uNBp/MJGnaCvkgr+BYRrGLruVKBv6WvyFod27WEB2sp7SsG8cNBKANhGLg==
@ -3475,7 +3483,7 @@ d3@^4.13.0:
d3-voronoi "1.1.2"
d3-zoom "1.7.1"
d3@^5.12:
d3@^5.12, d3@^5.7.0:
version "5.12.0"
resolved "https://registry.yarnpkg.com/d3/-/d3-5.12.0.tgz#0ddeac879c28c882317cd439b495290acd59ab61"
integrity sha512-flYVMoVuhPFHd9zVCe2BxIszUWqBcd5fvQGMNRmSiBrgdnh6Vlruh60RJQTouAK9xPbOB0plxMvBm4MoyODXNg==
@ -3512,43 +3520,6 @@ d3@^5.12:
d3-voronoi "1"
d3-zoom "1"
d3@^5.7.0:
version "5.9.2"
resolved "https://registry.yarnpkg.com/d3/-/d3-5.9.2.tgz#64e8a7e9c3d96d9e6e4999d2c8a2c829767e67f5"
integrity sha512-ydrPot6Lm3nTWH+gJ/Cxf3FcwuvesYQ5uk+j/kXEH/xbuYWYWTMAHTJQkyeuG8Y5WM5RSEYB41EctUrXQQytRQ==
dependencies:
d3-array "1"
d3-axis "1"
d3-brush "1"
d3-chord "1"
d3-collection "1"
d3-color "1"
d3-contour "1"
d3-dispatch "1"
d3-drag "1"
d3-dsv "1"
d3-ease "1"
d3-fetch "1"
d3-force "1"
d3-format "1"
d3-geo "1"
d3-hierarchy "1"
d3-interpolate "1"
d3-path "1"
d3-polygon "1"
d3-quadtree "1"
d3-random "1"
d3-scale "2"
d3-scale-chromatic "1"
d3-selection "1"
d3-shape "1"
d3-time "1"
d3-time-format "2"
d3-timer "1"
d3-transition "1"
d3-voronoi "1"
d3-zoom "1"
dagre-d3@dagrejs/dagre-d3:
version "0.6.4-pre"
resolved "https://codeload.github.com/dagrejs/dagre-d3/tar.gz/e1a00e5cb518f5d2304a35647e024f31d178e55b"
@ -5682,11 +5653,6 @@ immediate@~3.0.5:
resolved "https://registry.yarnpkg.com/immediate/-/immediate-3.0.6.tgz#9db1dbd0faf8de6fbe0f5dd5e56bb606280de69b"
integrity sha1-nbHb0Pr43m++D13V5Wu2BigN5ps=
immutable-tuple@^0.4.9:
version "0.4.9"
resolved "https://registry.yarnpkg.com/immutable-tuple/-/immutable-tuple-0.4.9.tgz#473ebdd6c169c461913a454bf87ef8f601a20ff0"
integrity sha512-LWbJPZnidF8eczu7XmcnLBsumuyRBkpwIRPCZxlojouhBo5jEBO4toj6n7hMy6IxHU/c+MqDSWkvaTpPlMQcyA==
import-fresh@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-2.0.0.tgz#d81355c15612d386c61f9ddd3922d4304822a546"
@ -8282,12 +8248,12 @@ opn@^5.5.0:
dependencies:
is-wsl "^1.1.0"
optimism@^0.6.9:
version "0.6.9"
resolved "https://registry.yarnpkg.com/optimism/-/optimism-0.6.9.tgz#19258ff8b3be0cea29ac35f06bff818e026e30bb"
integrity sha512-xoQm2lvXbCA9Kd7SCx6y713Y7sZ6fUc5R6VYpoL5M6svKJbTuvtNopexK8sO8K4s0EOUYHuPN2+yAEsNyRggkQ==
optimism@^0.10.0:
version "0.10.3"
resolved "https://registry.yarnpkg.com/optimism/-/optimism-0.10.3.tgz#163268fdc741dea2fb50f300bedda80356445fd7"
integrity sha512-9A5pqGoQk49H6Vhjb9kPgAeeECfUDF6aIICbMDL23kDLStBn1MWk3YvcZ4xWF9CsSf6XEgvRLkXy4xof/56vVw==
dependencies:
immutable-tuple "^0.4.9"
"@wry/context" "^0.4.0"
optimist@^0.6.1:
version "0.6.1"
@ -11111,13 +11077,6 @@ tryer@^1.0.0:
resolved "https://registry.yarnpkg.com/tryer/-/tryer-1.0.0.tgz#027b69fa823225e551cace3ef03b11f6ab37c1d7"
integrity sha1-Antp+oIyJeVRys4+8DsR9qs3wdc=
ts-invariant@^0.2.1:
version "0.2.1"
resolved "https://registry.yarnpkg.com/ts-invariant/-/ts-invariant-0.2.1.tgz#3d587f9d6e3bded97bf9ec17951dd9814d5a9d3f"
integrity sha512-Z/JSxzVmhTo50I+LKagEISFJW3pvPCqsMWLamCTX8Kr3N5aMrnGOqcflbe5hLUzwjvgPfnLzQtHZv0yWQ+FIHg==
dependencies:
tslib "^1.9.3"
ts-invariant@^0.3.2:
version "0.3.2"
resolved "https://registry.yarnpkg.com/ts-invariant/-/ts-invariant-0.3.2.tgz#89a2ffeb70879b777258df1df1c59383c35209b0"