Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2020-02-14 21:09:08 +00:00
parent 26a50872e9
commit 866ca4e49f
107 changed files with 688 additions and 252 deletions

View File

@ -203,6 +203,8 @@
- name: postgres:9.6 - name: postgres:9.6
command: ["postgres", "-c", "fsync=off", "-c", "synchronous_commit=off", "-c", "full_page_writes=off"] command: ["postgres", "-c", "fsync=off", "-c", "synchronous_commit=off", "-c", "full_page_writes=off"]
- name: redis:alpine - name: redis:alpine
variables:
POSTGRES_HOST_AUTH_METHOD: trust
.use-pg10: .use-pg10:
image: "registry.gitlab.com/gitlab-org/gitlab-build-images:ruby-2.6.5-golang-1.12-git-2.24-lfs-2.9-chrome-73.0-node-12.x-yarn-1.21-postgresql-10-graphicsmagick-1.3.34" image: "registry.gitlab.com/gitlab-org/gitlab-build-images:ruby-2.6.5-golang-1.12-git-2.24-lfs-2.9-chrome-73.0-node-12.x-yarn-1.21-postgresql-10-graphicsmagick-1.3.34"
@ -210,6 +212,8 @@
- name: postgres:10.9 - name: postgres:10.9
command: ["postgres", "-c", "fsync=off", "-c", "synchronous_commit=off", "-c", "full_page_writes=off"] command: ["postgres", "-c", "fsync=off", "-c", "synchronous_commit=off", "-c", "full_page_writes=off"]
- name: redis:alpine - name: redis:alpine
variables:
POSTGRES_HOST_AUTH_METHOD: trust
.use-pg9-ee: .use-pg9-ee:
services: services:
@ -217,6 +221,8 @@
command: ["postgres", "-c", "fsync=off", "-c", "synchronous_commit=off", "-c", "full_page_writes=off"] command: ["postgres", "-c", "fsync=off", "-c", "synchronous_commit=off", "-c", "full_page_writes=off"]
- name: redis:alpine - name: redis:alpine
- name: elasticsearch:6.4.2 - name: elasticsearch:6.4.2
variables:
POSTGRES_HOST_AUTH_METHOD: trust
.use-pg10-ee: .use-pg10-ee:
image: "registry.gitlab.com/gitlab-org/gitlab-build-images:ruby-2.6.5-golang-1.12-git-2.24-lfs-2.9-chrome-73.0-node-12.x-yarn-1.21-postgresql-10-graphicsmagick-1.3.34" image: "registry.gitlab.com/gitlab-org/gitlab-build-images:ruby-2.6.5-golang-1.12-git-2.24-lfs-2.9-chrome-73.0-node-12.x-yarn-1.21-postgresql-10-graphicsmagick-1.3.34"
@ -225,6 +231,8 @@
command: ["postgres", "-c", "fsync=off", "-c", "synchronous_commit=off", "-c", "full_page_writes=off"] command: ["postgres", "-c", "fsync=off", "-c", "synchronous_commit=off", "-c", "full_page_writes=off"]
- name: redis:alpine - name: redis:alpine
- name: elasticsearch:6.4.2 - name: elasticsearch:6.4.2
variables:
POSTGRES_HOST_AUTH_METHOD: trust
.only-ee: .only-ee:
only: only:

View File

@ -6,7 +6,7 @@ import { gqClient, parseEnvironmentsResponse, removeLeadingSlash } from './utils
import trackDashboardLoad from '../monitoring_tracking_helper'; import trackDashboardLoad from '../monitoring_tracking_helper';
import getEnvironments from '../queries/getEnvironments.query.graphql'; import getEnvironments from '../queries/getEnvironments.query.graphql';
import statusCodes from '../../lib/utils/http_status'; import statusCodes from '../../lib/utils/http_status';
import { backOff } from '../../lib/utils/common_utils'; import { backOff, convertObjectPropsToCamelCase } from '../../lib/utils/common_utils';
import { s__, sprintf } from '../../locale'; import { s__, sprintf } from '../../locale';
import { PROMETHEUS_TIMEOUT } from '../constants'; import { PROMETHEUS_TIMEOUT } from '../constants';
@ -52,6 +52,8 @@ export const requestMetricsDashboard = ({ commit }) => {
export const receiveMetricsDashboardSuccess = ({ commit, dispatch }, { response, params }) => { export const receiveMetricsDashboardSuccess = ({ commit, dispatch }, { response, params }) => {
commit(types.SET_ALL_DASHBOARDS, response.all_dashboards); commit(types.SET_ALL_DASHBOARDS, response.all_dashboards);
commit(types.RECEIVE_METRICS_DATA_SUCCESS, response.dashboard); commit(types.RECEIVE_METRICS_DATA_SUCCESS, response.dashboard);
commit(types.SET_ENDPOINTS, convertObjectPropsToCamelCase(response.metrics_data));
return dispatch('fetchPrometheusMetrics', params); return dispatch('fetchPrometheusMetrics', params);
}; };
export const receiveMetricsDashboardFailure = ({ commit }, error) => { export const receiveMetricsDashboardFailure = ({ commit }, error) => {

View File

@ -1,4 +1,5 @@
import Vue from 'vue'; import Vue from 'vue';
import pick from 'lodash/pick';
import { slugify } from '~/lib/utils/text_utility'; import { slugify } from '~/lib/utils/text_utility';
import * as types from './mutation_types'; import * as types from './mutation_types';
import { normalizeMetric, normalizeQueryResult } from './utils'; import { normalizeMetric, normalizeQueryResult } from './utils';
@ -174,15 +175,19 @@ export default {
state: emptyStateFromError(error), state: emptyStateFromError(error),
}); });
}, },
[types.SET_ENDPOINTS](state, endpoints = {}) {
[types.SET_ENDPOINTS](state, endpoints) { const endpointKeys = [
state.metricsEndpoint = endpoints.metricsEndpoint; 'metricsEndpoint',
state.deploymentsEndpoint = endpoints.deploymentsEndpoint; 'deploymentsEndpoint',
state.dashboardEndpoint = endpoints.dashboardEndpoint; 'dashboardEndpoint',
state.dashboardsEndpoint = endpoints.dashboardsEndpoint; 'dashboardsEndpoint',
state.currentDashboard = endpoints.currentDashboard; 'currentDashboard',
state.projectPath = endpoints.projectPath; 'projectPath',
state.logsPath = endpoints.logsPath || state.logsPath; 'logsPath',
];
Object.entries(pick(endpoints, endpointKeys)).forEach(([key, value]) => {
state[key] = value;
});
}, },
[types.SET_TIME_RANGE](state, timeRange) { [types.SET_TIME_RANGE](state, timeRange) {
state.timeRange = timeRange; state.timeRange = timeRange;

View File

@ -1,5 +1,5 @@
import ZenMode from '~/zen_mode'; import ZenMode from '~/zen_mode';
import initEditRelease from '~/releases/detail'; import initEditRelease from '~/releases/mount_edit';
document.addEventListener('DOMContentLoaded', () => { document.addEventListener('DOMContentLoaded', () => {
new ZenMode(); // eslint-disable-line no-new new ZenMode(); // eslint-disable-line no-new

View File

@ -1,3 +1,3 @@
import initReleases from '~/releases/list'; import initReleases from '~/releases/mount_index';
document.addEventListener('DOMContentLoaded', initReleases); document.addEventListener('DOMContentLoaded', initReleases);

View File

@ -7,7 +7,7 @@ import MarkdownField from '~/vue_shared/components/markdown/field.vue';
import autofocusonshow from '~/vue_shared/directives/autofocusonshow'; import autofocusonshow from '~/vue_shared/directives/autofocusonshow';
export default { export default {
name: 'ReleaseDetailApp', name: 'ReleaseEditApp',
components: { components: {
GlFormInput, GlFormInput,
GlFormGroup, GlFormGroup,
@ -18,7 +18,7 @@ export default {
autofocusonshow, autofocusonshow,
}, },
computed: { computed: {
...mapState([ ...mapState('detail', [
'isFetchingRelease', 'isFetchingRelease',
'fetchError', 'fetchError',
'markdownDocsPath', 'markdownDocsPath',
@ -42,7 +42,7 @@ export default {
); );
}, },
tagName() { tagName() {
return this.$store.state.release.tagName; return this.$store.state.detail.release.tagName;
}, },
tagNameHintText() { tagNameHintText() {
return sprintf( return sprintf(
@ -60,7 +60,7 @@ export default {
}, },
releaseTitle: { releaseTitle: {
get() { get() {
return this.$store.state.release.name; return this.$store.state.detail.release.name;
}, },
set(title) { set(title) {
this.updateReleaseTitle(title); this.updateReleaseTitle(title);
@ -68,7 +68,7 @@ export default {
}, },
releaseNotes: { releaseNotes: {
get() { get() {
return this.$store.state.release.description; return this.$store.state.detail.release.description;
}, },
set(notes) { set(notes) {
this.updateReleaseNotes(notes); this.updateReleaseNotes(notes);
@ -79,7 +79,7 @@ export default {
this.fetchRelease(); this.fetchRelease();
}, },
methods: { methods: {
...mapActions([ ...mapActions('detail', [
'fetchRelease', 'fetchRelease',
'updateRelease', 'updateRelease',
'updateReleaseTitle', 'updateReleaseTitle',

View File

@ -32,7 +32,7 @@ export default {
}, },
}, },
computed: { computed: {
...mapState(['isLoading', 'releases', 'hasError', 'pageInfo']), ...mapState('list', ['isLoading', 'releases', 'hasError', 'pageInfo']),
shouldRenderEmptyState() { shouldRenderEmptyState() {
return !this.releases.length && !this.hasError && !this.isLoading; return !this.releases.length && !this.hasError && !this.isLoading;
}, },
@ -47,7 +47,7 @@ export default {
}); });
}, },
methods: { methods: {
...mapActions(['fetchReleases']), ...mapActions('list', ['fetchReleases']),
onChangePage(page) { onChangePage(page) {
historyPushState(buildUrlWithCurrentLocation(`?page=${page}`)); historyPushState(buildUrlWithCurrentLocation(`?page=${page}`));
this.fetchReleases({ page, projectId: this.projectId }); this.fetchReleases({ page, projectId: this.projectId });

View File

@ -1,19 +0,0 @@
import Vue from 'vue';
import ReleaseDetailApp from './components/app.vue';
import createStore from './store';
export default () => {
const el = document.getElementById('js-edit-release-page');
const store = createStore();
store.dispatch('setInitialState', el.dataset);
return new Vue({
el,
store,
components: { ReleaseDetailApp },
render(createElement) {
return createElement('release-detail-app');
},
});
};

View File

@ -1,14 +0,0 @@
import Vue from 'vue';
import Vuex from 'vuex';
import * as actions from './actions';
import mutations from './mutations';
import state from './state';
Vue.use(Vuex);
export default () =>
new Vuex.Store({
actions,
mutations,
state,
});

View File

@ -1,24 +0,0 @@
import Vue from 'vue';
import App from './components/app.vue';
import createStore from './store';
export default () => {
const element = document.getElementById('js-releases-page');
return new Vue({
el: element,
store: createStore(),
components: {
App,
},
render(createElement) {
return createElement('app', {
props: {
projectId: element.dataset.projectId,
documentationLink: element.dataset.documentationPath,
illustrationPath: element.dataset.illustrationPath,
},
});
},
});
};

View File

@ -1,14 +0,0 @@
import Vue from 'vue';
import Vuex from 'vuex';
import state from './state';
import * as actions from './actions';
import mutations from './mutations';
Vue.use(Vuex);
export default () =>
new Vuex.Store({
actions,
mutations,
state: state(),
});

View File

@ -0,0 +1,17 @@
import Vue from 'vue';
import ReleaseEditApp from './components/app_edit.vue';
import createStore from './stores';
import detailModule from './stores/modules/detail';
export default () => {
const el = document.getElementById('js-edit-release-page');
const store = createStore({ detail: detailModule });
store.dispatch('setInitialState', el.dataset);
return new Vue({
el,
store,
render: h => h(ReleaseEditApp),
});
};

View File

@ -0,0 +1,21 @@
import Vue from 'vue';
import ReleaseListApp from './components/app_index.vue';
import createStore from './stores';
import listModule from './stores/modules/list';
export default () => {
const el = document.getElementById('js-releases-page');
return new Vue({
el,
store: createStore({ list: listModule }),
render: h =>
h(ReleaseListApp, {
props: {
projectId: el.dataset.projectId,
documentationLink: el.dataset.documentationPath,
illustrationPath: el.dataset.illustrationPath,
},
}),
});
};

View File

@ -0,0 +1,6 @@
import Vue from 'vue';
import Vuex from 'vuex';
Vue.use(Vuex);
export default modules => new Vuex.Store({ modules });

View File

@ -0,0 +1,10 @@
import * as actions from './actions';
import mutations from './mutations';
import state from './state';
export default {
namespaced: true,
actions,
mutations,
state,
};

View File

@ -0,0 +1,10 @@
import state from './state';
import * as actions from './actions';
import mutations from './mutations';
export default {
namespaced: true,
actions,
mutations,
state,
};

View File

@ -56,7 +56,7 @@ class Admin::ApplicationSettingsController < Admin::ApplicationController
end end
def clear_repository_check_states def clear_repository_check_states
RepositoryCheck::ClearWorker.perform_async RepositoryCheck::ClearWorker.perform_async # rubocop:disable CodeReuse/Worker
redirect_to( redirect_to(
general_admin_application_settings_path, general_admin_application_settings_path,
@ -73,7 +73,7 @@ class Admin::ApplicationSettingsController < Admin::ApplicationController
# Specs are in spec/requests/self_monitoring_project_spec.rb # Specs are in spec/requests/self_monitoring_project_spec.rb
def create_self_monitoring_project def create_self_monitoring_project
job_id = SelfMonitoringProjectCreateWorker.perform_async job_id = SelfMonitoringProjectCreateWorker.perform_async # rubocop:disable CodeReuse/Worker
render status: :accepted, json: { render status: :accepted, json: {
job_id: job_id, job_id: job_id,
@ -92,7 +92,7 @@ class Admin::ApplicationSettingsController < Admin::ApplicationController
} }
end end
if SelfMonitoringProjectCreateWorker.in_progress?(job_id) if SelfMonitoringProjectCreateWorker.in_progress?(job_id) # rubocop:disable CodeReuse/Worker
::Gitlab::PollingInterval.set_header(response, interval: 3_000) ::Gitlab::PollingInterval.set_header(response, interval: 3_000)
return render status: :accepted, json: { return render status: :accepted, json: {
@ -112,7 +112,7 @@ class Admin::ApplicationSettingsController < Admin::ApplicationController
# Specs are in spec/requests/self_monitoring_project_spec.rb # Specs are in spec/requests/self_monitoring_project_spec.rb
def delete_self_monitoring_project def delete_self_monitoring_project
job_id = SelfMonitoringProjectDeleteWorker.perform_async job_id = SelfMonitoringProjectDeleteWorker.perform_async # rubocop:disable CodeReuse/Worker
render status: :accepted, json: { render status: :accepted, json: {
job_id: job_id, job_id: job_id,
@ -131,7 +131,7 @@ class Admin::ApplicationSettingsController < Admin::ApplicationController
} }
end end
if SelfMonitoringProjectDeleteWorker.in_progress?(job_id) if SelfMonitoringProjectDeleteWorker.in_progress?(job_id) # rubocop:disable CodeReuse/Worker
::Gitlab::PollingInterval.set_header(response, interval: 3_000) ::Gitlab::PollingInterval.set_header(response, interval: 3_000)
return render status: :accepted, json: { return render status: :accepted, json: {

View File

@ -55,7 +55,7 @@ class Admin::ProjectsController < Admin::ApplicationController
# rubocop: enable CodeReuse/ActiveRecord # rubocop: enable CodeReuse/ActiveRecord
def repository_check def repository_check
RepositoryCheck::SingleRepositoryWorker.perform_async(@project.id) RepositoryCheck::SingleRepositoryWorker.perform_async(@project.id) # rubocop:disable CodeReuse/Worker
redirect_to( redirect_to(
admin_project_path(@project), admin_project_path(@project),

View File

@ -19,7 +19,7 @@ class Admin::ServicesController < Admin::ApplicationController
def update def update
if service.update(service_params[:service]) if service.update(service_params[:service])
PropagateServiceTemplateWorker.perform_async(service.id) if service.active? PropagateServiceTemplateWorker.perform_async(service.id) if service.active? # rubocop:disable CodeReuse/Worker
redirect_to admin_application_settings_services_path, redirect_to admin_application_settings_services_path,
notice: 'Application settings saved successfully' notice: 'Application settings saved successfully'

View File

@ -188,7 +188,7 @@ class Projects::IssuesController < Projects::ApplicationController
def import_csv def import_csv
if uploader = UploadService.new(project, params[:file]).execute if uploader = UploadService.new(project, params[:file]).execute
ImportIssuesCsvWorker.perform_async(current_user.id, project.id, uploader.upload.id) ImportIssuesCsvWorker.perform_async(current_user.id, project.id, uploader.upload.id) # rubocop:disable CodeReuse/Worker
flash[:notice] = _("Your issues are being imported. Once finished, you'll get a confirmation email.") flash[:notice] = _("Your issues are being imported. Once finished, you'll get a confirmation email.")
else else

View File

@ -47,7 +47,7 @@ class Projects::PipelineSchedulesController < Projects::ApplicationController
end end
def play def play
job_id = RunPipelineScheduleWorker.perform_async(schedule.id, current_user.id) job_id = RunPipelineScheduleWorker.perform_async(schedule.id, current_user.id) # rubocop:disable CodeReuse/Worker
if job_id if job_id
pipelines_link_start = "<a href=\"#{project_pipelines_path(@project)}\">" pipelines_link_start = "<a href=\"#{project_pipelines_path(@project)}\">"

View File

@ -32,7 +32,7 @@ module Projects
end end
def destroy def destroy
DeleteContainerRepositoryWorker.perform_async(current_user.id, image.id) DeleteContainerRepositoryWorker.perform_async(current_user.id, image.id) # rubocop:disable CodeReuse/Worker
track_event(:delete_repository) track_event(:delete_repository)
respond_to do |format| respond_to do |format|

View File

@ -69,7 +69,9 @@ module Projects
return return
end end
# rubocop:disable CodeReuse/Worker
CreatePipelineWorker.perform_async(project.id, current_user.id, project.default_branch, :web, ignore_skip_ci: true, save_on_errors: false) CreatePipelineWorker.perform_async(project.id, current_user.id, project.default_branch, :web, ignore_skip_ci: true, save_on_errors: false)
# rubocop:enable CodeReuse/Worker
pipelines_link_start = '<a href="%{url}">'.html_safe % { url: project_pipelines_path(@project) } pipelines_link_start = '<a href="%{url}">'.html_safe % { url: project_pipelines_path(@project) }
flash[:toast] = _("A new Auto DevOps pipeline has been created, go to %{pipelines_link_start}Pipelines page%{pipelines_link_end} for details") % { pipelines_link_start: pipelines_link_start, pipelines_link_end: "</a>".html_safe } flash[:toast] = _("A new Auto DevOps pipeline has been created, go to %{pipelines_link_start}Pipelines page%{pipelines_link_end} for details") % { pipelines_link_start: pipelines_link_start, pipelines_link_end: "</a>".html_safe }

View File

@ -25,7 +25,7 @@ module Projects
result = Projects::UpdateService.new(project, current_user, cleanup_params).execute result = Projects::UpdateService.new(project, current_user, cleanup_params).execute
if result[:status] == :success if result[:status] == :success
RepositoryCleanupWorker.perform_async(project.id, current_user.id) RepositoryCleanupWorker.perform_async(project.id, current_user.id) # rubocop:disable CodeReuse/Worker
flash[:notice] = _('Repository cleanup has started. You will receive an email once the cleanup operation is complete.') flash[:notice] = _('Repository cleanup has started. You will receive an email once the cleanup operation is complete.')
else else
flash[:alert] = _('Failed to upload object map file') flash[:alert] = _('Failed to upload object map file')

View File

@ -80,7 +80,7 @@ module Repositories
return unless repo_type.project? return unless repo_type.project?
return unless project&.daily_statistics_enabled? return unless project&.daily_statistics_enabled?
ProjectDailyStatisticsWorker.perform_async(project.id) ProjectDailyStatisticsWorker.perform_async(project.id) # rubocop:disable CodeReuse/Worker
end end
def access def access

View File

@ -31,7 +31,7 @@ module AnalyticsNavbarHelper
end end
def cycle_analytics_navbar_link(project, current_user) def cycle_analytics_navbar_link(project, current_user)
return unless Feature.enabled?(:analytics_pages_under_project_analytics_sidebar, project) return unless Feature.enabled?(:analytics_pages_under_project_analytics_sidebar, project, default_enabled: true)
return unless project_nav_tab?(:cycle_analytics) return unless project_nav_tab?(:cycle_analytics)
navbar_sub_item( navbar_sub_item(
@ -43,7 +43,7 @@ module AnalyticsNavbarHelper
end end
def repository_analytics_navbar_link(project, current_user) def repository_analytics_navbar_link(project, current_user)
return if Feature.disabled?(:analytics_pages_under_project_analytics_sidebar, project) return if Feature.disabled?(:analytics_pages_under_project_analytics_sidebar, project, default_enabled: true)
return if project.empty_repo? return if project.empty_repo?
navbar_sub_item( navbar_sub_item(
@ -55,7 +55,7 @@ module AnalyticsNavbarHelper
end end
def ci_cd_analytics_navbar_link(project, current_user) def ci_cd_analytics_navbar_link(project, current_user)
return unless Feature.enabled?(:analytics_pages_under_project_analytics_sidebar, project) return unless Feature.enabled?(:analytics_pages_under_project_analytics_sidebar, project, default_enabled: true)
return unless project_nav_tab?(:pipelines) return unless project_nav_tab?(:pipelines)
return unless project.feature_available?(:builds, current_user) || !project.empty_repo? return unless project.feature_available?(:builds, current_user) || !project.empty_repo?

View File

@ -3,7 +3,7 @@
module Ci module Ci
class ProcessBuildService < BaseService class ProcessBuildService < BaseService
def execute(build, current_status) def execute(build, current_status)
if valid_statuses_for_when(build.when).include?(current_status) if valid_statuses_for_build(build).include?(current_status)
if build.schedulable? if build.schedulable?
build.schedule build.schedule
elsif build.action? elsif build.action?
@ -25,10 +25,10 @@ module Ci
build.enqueue build.enqueue
end end
def valid_statuses_for_when(value) def valid_statuses_for_build(build)
case value case build.when
when 'on_success' when 'on_success'
%w[success skipped] build.scheduling_type_dag? ? %w[success] : %w[success skipped]
when 'on_failure' when 'on_failure'
%w[failed] %w[failed]
when 'always' when 'always'

View File

@ -6,10 +6,10 @@
= link_to navbar_links.first.link do = link_to navbar_links.first.link do
.nav-icon-container .nav-icon-container
= sprite_icon('chart') = sprite_icon('chart')
%span.nav-item-name %span.nav-item-name{ data: { qa_selector: 'analytics_link' } }
= _('Analytics') = _('Analytics')
%ul.sidebar-sub-level-items %ul.sidebar-sub-level-items{ data: { qa_selector: 'analytics_sidebar_submenu' } }
- navbar_links.each do |menu_item| - navbar_links.each do |menu_item|
= nav_link(path: menu_item.path) do = nav_link(path: menu_item.path) do
= link_to(menu_item.link, menu_item.link_to_options) do = link_to(menu_item.link, menu_item.link_to_options) do

View File

@ -1,4 +1,4 @@
- should_display_analytics_pages_in_sidebar = Feature.enabled?(:analytics_pages_under_group_analytics_sidebar, @group) - should_display_analytics_pages_in_sidebar = Feature.enabled?(:analytics_pages_under_group_analytics_sidebar, @group, default_enabled: true)
- issues_count = group_issues_count(state: 'opened') - issues_count = group_issues_count(state: 'opened')
- merge_requests_count = group_merge_requests_count(state: 'opened') - merge_requests_count = group_merge_requests_count(state: 'opened')

View File

@ -1,4 +1,4 @@
- should_display_analytics_pages_in_sidebar = Feature.enabled?(:analytics_pages_under_project_analytics_sidebar, @project) - should_display_analytics_pages_in_sidebar = Feature.enabled?(:analytics_pages_under_project_analytics_sidebar, @project, default_enabled: true)
.nav-sidebar{ class: ("sidebar-collapsed-desktop" if collapsed_sidebar?) } .nav-sidebar{ class: ("sidebar-collapsed-desktop" if collapsed_sidebar?) }
.nav-sidebar-inner-scroll .nav-sidebar-inner-scroll
@ -9,7 +9,7 @@
= project_icon(@project, alt: @project.name, class: 'avatar s40 avatar-tile', width: 40, height: 40) = project_icon(@project, alt: @project.name, class: 'avatar s40 avatar-tile', width: 40, height: 40)
.sidebar-context-title .sidebar-context-title
= @project.name = @project.name
%ul.sidebar-top-level-items %ul.sidebar-top-level-items.qa-project-sidebar
- paths = sidebar_projects_paths - paths = sidebar_projects_paths
- paths << 'cycle_analytics#show' unless should_display_analytics_pages_in_sidebar - paths << 'cycle_analytics#show' unless should_display_analytics_pages_in_sidebar
= nav_link(path: paths, html_options: { class: 'home' }) do = nav_link(path: paths, html_options: { class: 'home' }) do

View File

@ -0,0 +1,5 @@
---
title: Prevent DAG builds to run after skipped need build
merge_request: 23405
author:
type: fixed

View File

@ -0,0 +1,5 @@
---
title: Backfill LfsObjectsProject records of forks
merge_request: 24767
author:
type: other

View File

@ -0,0 +1,6 @@
---
title: Fix Group Import existing objects lookup when description attribute is an empty
string
merge_request: 25187
author:
type: fixed

View File

@ -0,0 +1,5 @@
---
title: Update cluster-applications to v0.8.0
merge_request: 25138
author:
type: changed

View File

@ -0,0 +1,5 @@
---
title: Move analytics pages under the sidebar for projects and groups
merge_request: 24470
author:
type: changed

View File

@ -0,0 +1,38 @@
# frozen_string_literal: true
class ScheduleLinkLfsObjects < ActiveRecord::Migration[6.0]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
MIGRATION = 'LinkLfsObjects'
BATCH_SIZE = 1_000
disable_ddl_transaction!
class Project < ActiveRecord::Base
include EachBatch
self.table_name = 'projects'
end
def up
fork_network_members =
Gitlab::BackgroundMigration::LinkLfsObjects::ForkNetworkMember
.select(1)
.with_non_existing_lfs_objects
.where('fork_network_members.project_id = projects.id')
forks = Project.where('EXISTS (?)', fork_network_members)
queue_background_migration_jobs_by_range_at_intervals(
forks,
MIGRATION,
BackgroundMigrationWorker.minimum_interval,
batch_size: BATCH_SIZE
)
end
def down
# no-op
end
end

View File

@ -16,7 +16,7 @@ group:
- Merge requests - Merge requests
- Push events - Push events
To view the Contribution Analytics, go to your group's **Overview > Contribution Analytics** To view the Contribution Analytics, go to your group's **Analytics > Contribution Analytics**
page. page.
## Use cases ## Use cases

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.6 KiB

View File

@ -14,10 +14,10 @@ requests to be merged and much more.
## View your group's Insights ## View your group's Insights
You can access your group's Insights by clicking the **Overview > Insights** You can access your group's Insights by clicking the **Analytics > Insights**
link in the left sidebar: link in the left sidebar:
![Insights sidebar link](img/insights_sidebar_link.png) ![Insights sidebar link](img/insights_sidebar_link_v12_8.png)
## Configure your Insights ## Configure your Insights

Binary file not shown.

Before

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 65 KiB

View File

@ -10,7 +10,7 @@ Issues Analytics is a bar graph which illustrates the number of issues created e
The default timespan is 13 months, which includes the current month, and the 12 months The default timespan is 13 months, which includes the current month, and the 12 months
prior. prior.
To access the chart, navigate to a group's sidebar and select **Issues > Analytics**. To access the chart, navigate to a group's sidebar and select **Analytics > Issues Analytics**.
Hover over each bar to see the total number of issues. Hover over each bar to see the total number of issues.
@ -28,7 +28,7 @@ You can change the total number of months displayed by setting a URL parameter.
For example, `https://gitlab.com/groups/gitlab-org/-/issues_analytics?months_back=15` For example, `https://gitlab.com/groups/gitlab-org/-/issues_analytics?months_back=15`
shows a total of 15 months for the chart in the GitLab.org group. shows a total of 15 months for the chart in the GitLab.org group.
![Issues created per month](img/issues_created_per_month.png) ![Issues created per month](img/issues_created_per_month_v12_8.png)
<!-- ## Troubleshooting <!-- ## Troubleshooting

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

View File

@ -13,10 +13,10 @@ This feature is [also available at the group level](../../group/insights/index.m
## View your project's Insights ## View your project's Insights
You can access your project's Insights by clicking the **Project > Insights** You can access your project's Insights by clicking the **Analytics > Insights**
link in the left sidebar: link in the left sidebar:
![Insights sidebar link](img/insights_sidebar_link.png) ![Insights sidebar link](img/insights_sidebar_link_v12_8.png)
## Configure your Insights ## Configure your Insights

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 52 KiB

View File

@ -285,7 +285,9 @@ Note the following properties:
| type | string | no | Type of panel to be rendered. Optional for area panel types | | type | string | no | Type of panel to be rendered. Optional for area panel types |
| query_range | string | required | For area panel types, you must use a [range query](https://prometheus.io/docs/prometheus/latest/querying/api/#range-queries) | | query_range | string | required | For area panel types, you must use a [range query](https://prometheus.io/docs/prometheus/latest/querying/api/#range-queries) |
![area panel type](img/prometheus_dashboard_area_panel_type.png) ![area panel chart](img/prometheus_dashboard_area_panel_type_v12_8.png)
Starting in [version 12.8](https://gitlab.com/gitlab-org/gitlab/issues/202696), the y-axis values will automatically scale according to the data. Previously, it always started from 0.
##### Anomaly chart ##### Anomaly chart
@ -329,7 +331,7 @@ Note the following properties:
![anomaly panel type](img/prometheus_dashboard_anomaly_panel_type.png) ![anomaly panel type](img/prometheus_dashboard_anomaly_panel_type.png)
#### Column ##### Column chart
To add a column panel type to a dashboard, look at the following sample dashboard file: To add a column panel type to a dashboard, look at the following sample dashboard file:

View File

@ -52,7 +52,7 @@ relatively quickly to work, and they will take you to another page in the projec
| <kbd>t</kbd> | Go to the project file search page. (**Repository > Files**, click **Find Files**). | | <kbd>t</kbd> | Go to the project file search page. (**Repository > Files**, click **Find Files**). |
| <kbd>g</kbd> + <kbd>c</kbd> | Go to the project commits list (**Repository > Commits**). | | <kbd>g</kbd> + <kbd>c</kbd> | Go to the project commits list (**Repository > Commits**). |
| <kbd>g</kbd> + <kbd>n</kbd> | Go to the [repository graph](#repository-graph) page (**Repository > Graph**). | | <kbd>g</kbd> + <kbd>n</kbd> | Go to the [repository graph](#repository-graph) page (**Repository > Graph**). |
| <kbd>g</kbd> + <kbd>d</kbd> | Go to repository charts (**Repository > Charts**). | | <kbd>g</kbd> + <kbd>d</kbd> | Go to repository charts (**Analytics > Repository Analytics**). |
| <kbd>g</kbd> + <kbd>i</kbd> | Go to the project issues list (**Issues > List**). | | <kbd>g</kbd> + <kbd>i</kbd> | Go to the project issues list (**Issues > List**). |
| <kbd>i</kbd> | Go to the New Issue page (**Issues**, click **New Issue** ). | | <kbd>i</kbd> | Go to the New Issue page (**Issues**, click **New Issue** ). |
| <kbd>g</kbd> + <kbd>b</kbd> | Go to the project issue boards list (**Issues > Boards**). | | <kbd>g</kbd> + <kbd>b</kbd> | Go to the project issue boards list (**Issues > Boards**). |

View File

@ -27,7 +27,7 @@ module API
detail 'This feature was introduced in GitLab 12.5.' detail 'This feature was introduced in GitLab 12.5.'
end end
post ':id/export' do post ':id/export' do
GroupExportWorker.perform_async(current_user.id, user_group.id, params) GroupExportWorker.perform_async(current_user.id, user_group.id, params) # rubocop:disable CodeReuse/Worker
accepted! accepted!
end end

View File

@ -76,7 +76,7 @@ module API
group = ::Groups::CreateService.new(current_user, group_params).execute group = ::Groups::CreateService.new(current_user, group_params).execute
if group.persisted? if group.persisted?
GroupImportWorker.perform_async(current_user.id, group.id) GroupImportWorker.perform_async(current_user.id, group.id) # rubocop:disable CodeReuse/Worker
accepted! accepted!
else else

View File

@ -120,7 +120,7 @@ module API
post ':id/pipeline_schedules/:pipeline_schedule_id/play' do post ':id/pipeline_schedules/:pipeline_schedule_id/play' do
authorize! :play_pipeline_schedule, pipeline_schedule authorize! :play_pipeline_schedule, pipeline_schedule
job_id = RunPipelineScheduleWorker job_id = RunPipelineScheduleWorker # rubocop:disable CodeReuse/Worker
.perform_async(pipeline_schedule.id, current_user.id) .perform_async(pipeline_schedule.id, current_user.id)
if job_id if job_id

View File

@ -41,7 +41,7 @@ module API
delete ':id/registry/repositories/:repository_id', requirements: REPOSITORY_ENDPOINT_REQUIREMENTS do delete ':id/registry/repositories/:repository_id', requirements: REPOSITORY_ENDPOINT_REQUIREMENTS do
authorize_admin_container_image! authorize_admin_container_image!
DeleteContainerRepositoryWorker.perform_async(current_user.id, repository.id) DeleteContainerRepositoryWorker.perform_async(current_user.id, repository.id) # rubocop:disable CodeReuse/Worker
track_event('delete_repository') track_event('delete_repository')
status :accepted status :accepted
@ -79,8 +79,10 @@ module API
message = 'This request has already been made. You can run this at most once an hour for a given container repository' message = 'This request has already been made. You can run this at most once an hour for a given container repository'
render_api_error!(message, 400) unless obtain_new_cleanup_container_lease render_api_error!(message, 400) unless obtain_new_cleanup_container_lease
# rubocop:disable CodeReuse/Worker
CleanupContainerRepositoryWorker.perform_async(current_user.id, repository.id, CleanupContainerRepositoryWorker.perform_async(current_user.id, repository.id,
declared_params.except(:repository_id).merge(container_expiration_policy: false)) declared_params.except(:repository_id).merge(container_expiration_policy: false))
# rubocop:enable CodeReuse/Worker
track_event('delete_tag_bulk') track_event('delete_tag_bulk')

View File

@ -170,9 +170,9 @@ module API
return if release.historical_release? return if release.historical_release?
if release.upcoming_release? if release.upcoming_release?
CreateEvidenceWorker.perform_at(release.released_at, release.id) CreateEvidenceWorker.perform_at(release.released_at, release.id) # rubocop:disable CodeReuse/Worker
else else
CreateEvidenceWorker.perform_async(release.id) CreateEvidenceWorker.perform_async(release.id) # rubocop:disable CodeReuse/Worker
end end
end end
end end

View File

@ -0,0 +1,48 @@
# frozen_string_literal: true
module Gitlab
module BackgroundMigration
# Create missing LfsObjectsProject records for forks
class LinkLfsObjects
# Model definition used for migration
class ForkNetworkMember < ActiveRecord::Base
self.table_name = 'fork_network_members'
def self.with_non_existing_lfs_objects
joins('JOIN lfs_objects_projects lop ON fork_network_members.forked_from_project_id = lop.project_id')
.where(
<<~SQL
NOT EXISTS (
SELECT 1
FROM lfs_objects_projects
WHERE lfs_objects_projects.project_id = fork_network_members.project_id
AND lfs_objects_projects.lfs_object_id = lop.lfs_object_id
)
SQL
)
end
end
def perform(start_id, end_id)
select_query =
ForkNetworkMember
.select('lop.lfs_object_id, fork_network_members.project_id')
.with_non_existing_lfs_objects
.where(project_id: start_id..end_id)
return if select_query.empty?
execute <<-SQL
INSERT INTO lfs_objects_projects (lfs_object_id, project_id)
#{select_query.to_sql}
SQL
end
private
def execute(sql)
::ActiveRecord::Base.connection.execute(sql)
end
end
end
end

View File

@ -1,6 +1,6 @@
apply: apply:
stage: deploy stage: deploy
image: "registry.gitlab.com/gitlab-org/cluster-integration/cluster-applications:v0.7.0" image: "registry.gitlab.com/gitlab-org/cluster-integration/cluster-applications:v0.8.0"
environment: environment:
name: production name: production
variables: variables:
@ -12,6 +12,8 @@ apply:
GITLAB_RUNNER_VALUES_FILE: $CI_PROJECT_DIR/.gitlab/managed-apps/gitlab-runner/values.yaml GITLAB_RUNNER_VALUES_FILE: $CI_PROJECT_DIR/.gitlab/managed-apps/gitlab-runner/values.yaml
CILIUM_VALUES_FILE: $CI_PROJECT_DIR/.gitlab/managed-apps/cilium/values.yaml CILIUM_VALUES_FILE: $CI_PROJECT_DIR/.gitlab/managed-apps/cilium/values.yaml
JUPYTERHUB_VALUES_FILE: $CI_PROJECT_DIR/.gitlab/managed-apps/jupyterhub/values.yaml JUPYTERHUB_VALUES_FILE: $CI_PROJECT_DIR/.gitlab/managed-apps/jupyterhub/values.yaml
PROMETHEUS_VALUES_FILE: $CI_PROJECT_DIR/.gitlab/managed-apps/prometheus/values.yaml
ELASTIC_STACK_VALUES_FILE: $CI_PROJECT_DIR/.gitlab/managed-apps/elastic-stack/values.yaml
script: script:
- gitlab-managed-apps /usr/local/share/gitlab-managed-apps/helmfile.yaml - gitlab-managed-apps /usr/local/share/gitlab-managed-apps/helmfile.yaml
only: only:

View File

@ -18,12 +18,21 @@ module Gitlab
super super
@group = @attributes['group'] @group = @attributes['group']
update_description
end end
private private
attr_reader :group attr_reader :group
# Convert description empty string to nil
# due to existing object being saved with description: nil
# Which makes object lookup to fail since nil != ''
def update_description
attributes['description'] = nil if attributes['description'] == ''
end
def where_clauses def where_clauses
[ [
where_clause_base, where_clause_base,

View File

@ -159,6 +159,10 @@ module QA
autoload :Validator, 'qa/page/validator' autoload :Validator, 'qa/page/validator'
autoload :Validatable, 'qa/page/validatable' autoload :Validatable, 'qa/page/validatable'
module SubMenus
autoload :Common, 'qa/page/sub_menus/common'
end
module Main module Main
autoload :Login, 'qa/page/main/login' autoload :Login, 'qa/page/main/login'
autoload :Menu, 'qa/page/main/menu' autoload :Menu, 'qa/page/main/menu'

View File

@ -13,15 +13,22 @@ module QA
element :contribution_analytics_link element :contribution_analytics_link
end end
view 'app/views/layouts/nav/sidebar/_analytics_links.html.haml' do
element :analytics_link
element :analytics_sidebar_submenu
end
def click_group_members_item def click_group_members_item
within_sidebar do within_sidebar do
click_element(:group_members_item) click_element(:group_members_item)
end end
end end
def click_group_analytics_item def click_contribution_analytics_item
within_sidebar do hover_element(:analytics_link) do
click_element(:contribution_analytics_link) within_submenu(:analytics_sidebar_submenu) do
click_element(:contribution_analytics_link)
end
end end
end end

View File

@ -5,6 +5,8 @@ module QA
module Group module Group
module SubMenus module SubMenus
module Common module Common
include QA::Page::SubMenus::Common
def self.included(base) def self.included(base)
base.class_eval do base.class_eval do
view 'app/views/layouts/nav/sidebar/_group.html.haml' do view 'app/views/layouts/nav/sidebar/_group.html.haml' do
@ -13,23 +15,10 @@ module QA
end end
end end
def hover_element(element) private
within_sidebar do
find_element(element).hover
yield
end
end
def within_sidebar def sidebar_element
within_element(:group_sidebar) do :group_sidebar
yield
end
end
def within_submenu(element)
within_element(element) do
yield
end
end end
end end
end end

View File

@ -5,20 +5,12 @@ module QA
module Project module Project
module SubMenus module SubMenus
module Common module Common
def within_sidebar include QA::Page::SubMenus::Common
within('.sidebar-top-level-items') do
yield
end
end
def within_submenu private
if has_css?('.fly-out-list')
within('.fly-out-list') do def sidebar_element
yield :project_sidebar
end
else
yield
end
end end
end end
end end

View File

@ -0,0 +1,50 @@
# frozen_string_literal: true
module QA
module Page
module SubMenus
module Common
def hover_element(element)
within_sidebar do
find_element(element).hover
yield
end
end
def within_sidebar
within_element(sidebar_element) do
yield
end
end
def within_submenu(element = nil)
if element
within_element(element) do
yield
end
else
within_submenu_without_element do
yield
end
end
end
private
def within_submenu_without_element
if has_css?('.fly-out-list')
within('.fly-out-list') do
yield
end
else
yield
end
end
def sidebar_element
raise NotImplementedError
end
end
end
end
end

View File

@ -55,6 +55,7 @@ require_relative 'cop/code_reuse/service_class'
require_relative 'cop/code_reuse/presenter' require_relative 'cop/code_reuse/presenter'
require_relative 'cop/code_reuse/serializer' require_relative 'cop/code_reuse/serializer'
require_relative 'cop/code_reuse/active_record' require_relative 'cop/code_reuse/active_record'
require_relative 'cop/code_reuse/worker'
require_relative 'cop/group_public_or_visible_to_user' require_relative 'cop/group_public_or_visible_to_user'
require_relative 'cop/inject_enterprise_edition_module' require_relative 'cop/inject_enterprise_edition_module'
require_relative 'cop/graphql/authorize_types' require_relative 'cop/graphql/authorize_types'

View File

@ -36,7 +36,7 @@ describe 'Internal Group access' do
it { is_expected.to be_denied_for(:visitor) } it { is_expected.to be_denied_for(:visitor) }
end end
describe 'GET /groups/:path/issues' do describe 'GET /groups/:path/-/issues' do
subject { issues_group_path(group) } subject { issues_group_path(group) }
it { is_expected.to be_allowed_for(:admin) } it { is_expected.to be_allowed_for(:admin) }
@ -51,7 +51,7 @@ describe 'Internal Group access' do
it { is_expected.to be_denied_for(:visitor) } it { is_expected.to be_denied_for(:visitor) }
end end
describe 'GET /groups/:path/merge_requests' do describe 'GET /groups/:path/-/merge_requests' do
let(:project) { create(:project, :internal, :repository, group: group) } let(:project) { create(:project, :internal, :repository, group: group) }
subject { merge_requests_group_path(group) } subject { merge_requests_group_path(group) }
@ -68,7 +68,7 @@ describe 'Internal Group access' do
it { is_expected.to be_denied_for(:visitor) } it { is_expected.to be_denied_for(:visitor) }
end end
describe 'GET /groups/:path/group_members' do describe 'GET /groups/:path/-/group_members' do
subject { group_group_members_path(group) } subject { group_group_members_path(group) }
it { is_expected.to be_allowed_for(:admin) } it { is_expected.to be_allowed_for(:admin) }
@ -83,7 +83,7 @@ describe 'Internal Group access' do
it { is_expected.to be_denied_for(:visitor) } it { is_expected.to be_denied_for(:visitor) }
end end
describe 'GET /groups/:path/edit' do describe 'GET /groups/:path/-/edit' do
subject { edit_group_path(group) } subject { edit_group_path(group) }
it { is_expected.to be_allowed_for(:admin) } it { is_expected.to be_allowed_for(:admin) }

View File

@ -36,7 +36,7 @@ describe 'Private Group access' do
it { is_expected.to be_denied_for(:visitor) } it { is_expected.to be_denied_for(:visitor) }
end end
describe 'GET /groups/:path/issues' do describe 'GET /groups/:path/-/issues' do
subject { issues_group_path(group) } subject { issues_group_path(group) }
it { is_expected.to be_allowed_for(:admin) } it { is_expected.to be_allowed_for(:admin) }
@ -51,7 +51,7 @@ describe 'Private Group access' do
it { is_expected.to be_denied_for(:visitor) } it { is_expected.to be_denied_for(:visitor) }
end end
describe 'GET /groups/:path/merge_requests' do describe 'GET /groups/:path/-/merge_requests' do
let(:project) { create(:project, :private, :repository, group: group) } let(:project) { create(:project, :private, :repository, group: group) }
subject { merge_requests_group_path(group) } subject { merge_requests_group_path(group) }
@ -68,7 +68,7 @@ describe 'Private Group access' do
it { is_expected.to be_denied_for(:visitor) } it { is_expected.to be_denied_for(:visitor) }
end end
describe 'GET /groups/:path/group_members' do describe 'GET /groups/:path/-/group_members' do
subject { group_group_members_path(group) } subject { group_group_members_path(group) }
it { is_expected.to be_allowed_for(:admin) } it { is_expected.to be_allowed_for(:admin) }
@ -83,7 +83,7 @@ describe 'Private Group access' do
it { is_expected.to be_denied_for(:visitor) } it { is_expected.to be_denied_for(:visitor) }
end end
describe 'GET /groups/:path/edit' do describe 'GET /groups/:path/-/edit' do
subject { edit_group_path(group) } subject { edit_group_path(group) }
it { is_expected.to be_allowed_for(:admin) } it { is_expected.to be_allowed_for(:admin) }

View File

@ -36,7 +36,7 @@ describe 'Public Group access' do
it { is_expected.to be_allowed_for(:visitor) } it { is_expected.to be_allowed_for(:visitor) }
end end
describe 'GET /groups/:path/issues' do describe 'GET /groups/:path/-/issues' do
subject { issues_group_path(group) } subject { issues_group_path(group) }
it { is_expected.to be_allowed_for(:admin) } it { is_expected.to be_allowed_for(:admin) }
@ -51,7 +51,7 @@ describe 'Public Group access' do
it { is_expected.to be_allowed_for(:visitor) } it { is_expected.to be_allowed_for(:visitor) }
end end
describe 'GET /groups/:path/merge_requests' do describe 'GET /groups/:path/-/merge_requests' do
let(:project) { create(:project, :public, :repository, group: group) } let(:project) { create(:project, :public, :repository, group: group) }
subject { merge_requests_group_path(group) } subject { merge_requests_group_path(group) }
@ -68,7 +68,7 @@ describe 'Public Group access' do
it { is_expected.to be_allowed_for(:visitor) } it { is_expected.to be_allowed_for(:visitor) }
end end
describe 'GET /groups/:path/group_members' do describe 'GET /groups/:path/-/group_members' do
subject { group_group_members_path(group) } subject { group_group_members_path(group) }
it { is_expected.to be_allowed_for(:admin) } it { is_expected.to be_allowed_for(:admin) }
@ -83,7 +83,7 @@ describe 'Public Group access' do
it { is_expected.to be_allowed_for(:visitor) } it { is_expected.to be_allowed_for(:visitor) }
end end
describe 'GET /groups/:path/edit' do describe 'GET /groups/:path/-/edit' do
subject { edit_group_path(group) } subject { edit_group_path(group) }
it { is_expected.to be_allowed_for(:admin) } it { is_expected.to be_allowed_for(:admin) }

View File

@ -29,7 +29,7 @@ describe "Internal Project Access" do
it { is_expected.to be_denied_for(:visitor) } it { is_expected.to be_denied_for(:visitor) }
end end
describe "GET /:project_path/tree/master" do describe "GET /:project_path/-/tree/master" do
subject { project_tree_path(project, project.repository.root_ref) } subject { project_tree_path(project, project.repository.root_ref) }
it { is_expected.to be_allowed_for(:admin) } it { is_expected.to be_allowed_for(:admin) }
@ -43,7 +43,7 @@ describe "Internal Project Access" do
it { is_expected.to be_denied_for(:visitor) } it { is_expected.to be_denied_for(:visitor) }
end end
describe "GET /:project_path/commits/master" do describe "GET /:project_path/-/commits/master" do
subject { project_commits_path(project, project.repository.root_ref, limit: 1) } subject { project_commits_path(project, project.repository.root_ref, limit: 1) }
it { is_expected.to be_allowed_for(:admin) } it { is_expected.to be_allowed_for(:admin) }
@ -57,7 +57,7 @@ describe "Internal Project Access" do
it { is_expected.to be_denied_for(:visitor) } it { is_expected.to be_denied_for(:visitor) }
end end
describe "GET /:project_path/commit/:sha" do describe "GET /:project_path/-/commit/:sha" do
subject { project_commit_path(project, project.repository.commit) } subject { project_commit_path(project, project.repository.commit) }
it { is_expected.to be_allowed_for(:admin) } it { is_expected.to be_allowed_for(:admin) }
@ -71,7 +71,7 @@ describe "Internal Project Access" do
it { is_expected.to be_denied_for(:visitor) } it { is_expected.to be_denied_for(:visitor) }
end end
describe "GET /:project_path/compare" do describe "GET /:project_path/-/compare" do
subject { project_compare_index_path(project) } subject { project_compare_index_path(project) }
it { is_expected.to be_allowed_for(:admin) } it { is_expected.to be_allowed_for(:admin) }
@ -127,7 +127,7 @@ describe "Internal Project Access" do
it { is_expected.to be_denied_for(:external) } it { is_expected.to be_denied_for(:external) }
end end
describe "GET /:project_path/blob" do describe "GET /:project_path/-/blob" do
let(:commit) { project.repository.commit } let(:commit) { project.repository.commit }
subject { project_blob_path(project, File.join(commit.id, '.gitignore')) } subject { project_blob_path(project, File.join(commit.id, '.gitignore')) }
@ -229,7 +229,7 @@ describe "Internal Project Access" do
it { is_expected.to be_denied_for(:visitor) } it { is_expected.to be_denied_for(:visitor) }
end end
describe "GET /:project_path/merge_requests" do describe "GET /:project_path/-/merge_requests" do
subject { project_merge_requests_path(project) } subject { project_merge_requests_path(project) }
it { is_expected.to be_allowed_for(:admin) } it { is_expected.to be_allowed_for(:admin) }
@ -243,7 +243,7 @@ describe "Internal Project Access" do
it { is_expected.to be_denied_for(:visitor) } it { is_expected.to be_denied_for(:visitor) }
end end
describe "GET /:project_path/merge_requests/new" do describe "GET /:project_path/-/merge_requests/new" do
subject { project_new_merge_request_path(project) } subject { project_new_merge_request_path(project) }
it { is_expected.to be_allowed_for(:admin) } it { is_expected.to be_allowed_for(:admin) }
@ -257,7 +257,7 @@ describe "Internal Project Access" do
it { is_expected.to be_denied_for(:visitor) } it { is_expected.to be_denied_for(:visitor) }
end end
describe "GET /:project_path/branches" do describe "GET /:project_path/-/branches" do
subject { project_branches_path(project) } subject { project_branches_path(project) }
before do before do
@ -278,7 +278,7 @@ describe "Internal Project Access" do
it { is_expected.to be_denied_for(:visitor) } it { is_expected.to be_denied_for(:visitor) }
end end
describe "GET /:project_path/tags" do describe "GET /:project_path/-/tags" do
subject { project_tags_path(project) } subject { project_tags_path(project) }
before do before do

View File

@ -29,7 +29,7 @@ describe "Private Project Access" do
it { is_expected.to be_denied_for(:visitor) } it { is_expected.to be_denied_for(:visitor) }
end end
describe "GET /:project_path/tree/master" do describe "GET /:project_path/-/tree/master" do
subject { project_tree_path(project, project.repository.root_ref) } subject { project_tree_path(project, project.repository.root_ref) }
it { is_expected.to be_allowed_for(:admin) } it { is_expected.to be_allowed_for(:admin) }
@ -43,7 +43,7 @@ describe "Private Project Access" do
it { is_expected.to be_denied_for(:visitor) } it { is_expected.to be_denied_for(:visitor) }
end end
describe "GET /:project_path/commits/master" do describe "GET /:project_path/-/commits/master" do
subject { project_commits_path(project, project.repository.root_ref, limit: 1) } subject { project_commits_path(project, project.repository.root_ref, limit: 1) }
it { is_expected.to be_allowed_for(:admin) } it { is_expected.to be_allowed_for(:admin) }
@ -57,7 +57,7 @@ describe "Private Project Access" do
it { is_expected.to be_denied_for(:visitor) } it { is_expected.to be_denied_for(:visitor) }
end end
describe "GET /:project_path/commit/:sha" do describe "GET /:project_path/-/commit/:sha" do
subject { project_commit_path(project, project.repository.commit) } subject { project_commit_path(project, project.repository.commit) }
it { is_expected.to be_allowed_for(:admin) } it { is_expected.to be_allowed_for(:admin) }
@ -71,7 +71,7 @@ describe "Private Project Access" do
it { is_expected.to be_denied_for(:visitor) } it { is_expected.to be_denied_for(:visitor) }
end end
describe "GET /:project_path/compare" do describe "GET /:project_path/-/compare" do
subject { project_compare_index_path(project) } subject { project_compare_index_path(project) }
it { is_expected.to be_allowed_for(:admin) } it { is_expected.to be_allowed_for(:admin) }
@ -127,7 +127,7 @@ describe "Private Project Access" do
it { is_expected.to be_denied_for(:visitor) } it { is_expected.to be_denied_for(:visitor) }
end end
describe "GET /:project_path/blob" do describe "GET /:project_path/-/blob" do
let(:commit) { project.repository.commit } let(:commit) { project.repository.commit }
subject { project_blob_path(project, File.join(commit.id, '.gitignore')) } subject { project_blob_path(project, File.join(commit.id, '.gitignore')) }
@ -215,7 +215,7 @@ describe "Private Project Access" do
it { is_expected.to be_denied_for(:visitor) } it { is_expected.to be_denied_for(:visitor) }
end end
describe "GET /:project_path/merge_requests" do describe "GET /:project_path/-/merge_requests" do
subject { project_merge_requests_path(project) } subject { project_merge_requests_path(project) }
it { is_expected.to be_allowed_for(:admin) } it { is_expected.to be_allowed_for(:admin) }
@ -229,7 +229,7 @@ describe "Private Project Access" do
it { is_expected.to be_denied_for(:visitor) } it { is_expected.to be_denied_for(:visitor) }
end end
describe "GET /:project_path/branches" do describe "GET /:project_path/-/branches" do
subject { project_branches_path(project) } subject { project_branches_path(project) }
before do before do
@ -250,7 +250,7 @@ describe "Private Project Access" do
it { is_expected.to be_denied_for(:visitor) } it { is_expected.to be_denied_for(:visitor) }
end end
describe "GET /:project_path/tags" do describe "GET /:project_path/-/tags" do
subject { project_tags_path(project) } subject { project_tags_path(project) }
before do before do

View File

@ -29,7 +29,7 @@ describe "Public Project Access" do
it { is_expected.to be_allowed_for(:visitor) } it { is_expected.to be_allowed_for(:visitor) }
end end
describe "GET /:project_path/tree/master" do describe "GET /:project_path/-/tree/master" do
subject { project_tree_path(project, project.repository.root_ref) } subject { project_tree_path(project, project.repository.root_ref) }
it { is_expected.to be_allowed_for(:admin) } it { is_expected.to be_allowed_for(:admin) }
@ -43,7 +43,7 @@ describe "Public Project Access" do
it { is_expected.to be_allowed_for(:visitor) } it { is_expected.to be_allowed_for(:visitor) }
end end
describe "GET /:project_path/commits/master" do describe "GET /:project_path/-/commits/master" do
subject { project_commits_path(project, project.repository.root_ref, limit: 1) } subject { project_commits_path(project, project.repository.root_ref, limit: 1) }
it { is_expected.to be_allowed_for(:admin) } it { is_expected.to be_allowed_for(:admin) }
@ -57,7 +57,7 @@ describe "Public Project Access" do
it { is_expected.to be_allowed_for(:visitor) } it { is_expected.to be_allowed_for(:visitor) }
end end
describe "GET /:project_path/commit/:sha" do describe "GET /:project_path/-/commit/:sha" do
subject { project_commit_path(project, project.repository.commit) } subject { project_commit_path(project, project.repository.commit) }
it { is_expected.to be_allowed_for(:admin) } it { is_expected.to be_allowed_for(:admin) }
@ -71,7 +71,7 @@ describe "Public Project Access" do
it { is_expected.to be_allowed_for(:visitor) } it { is_expected.to be_allowed_for(:visitor) }
end end
describe "GET /:project_path/compare" do describe "GET /:project_path/-/compare" do
subject { project_compare_index_path(project) } subject { project_compare_index_path(project) }
it { is_expected.to be_allowed_for(:admin) } it { is_expected.to be_allowed_for(:admin) }
@ -345,7 +345,7 @@ describe "Public Project Access" do
it { is_expected.to be_denied_for(:visitor) } it { is_expected.to be_denied_for(:visitor) }
end end
describe "GET /:project_path/blob" do describe "GET /:project_path/-/blob" do
let(:commit) { project.repository.commit } let(:commit) { project.repository.commit }
subject { project_blob_path(project, File.join(commit.id, '.gitignore')) } subject { project_blob_path(project, File.join(commit.id, '.gitignore')) }
@ -446,7 +446,7 @@ describe "Public Project Access" do
it { is_expected.to be_denied_for(:visitor) } it { is_expected.to be_denied_for(:visitor) }
end end
describe "GET /:project_path/merge_requests" do describe "GET /:project_path/-/merge_requests" do
subject { project_merge_requests_path(project) } subject { project_merge_requests_path(project) }
it { is_expected.to be_allowed_for(:admin) } it { is_expected.to be_allowed_for(:admin) }
@ -460,7 +460,7 @@ describe "Public Project Access" do
it { is_expected.to be_allowed_for(:visitor) } it { is_expected.to be_allowed_for(:visitor) }
end end
describe "GET /:project_path/merge_requests/new" do describe "GET /:project_path/-/merge_requests/new" do
subject { project_new_merge_request_path(project) } subject { project_new_merge_request_path(project) }
it { is_expected.to be_allowed_for(:admin) } it { is_expected.to be_allowed_for(:admin) }
@ -474,7 +474,7 @@ describe "Public Project Access" do
it { is_expected.to be_denied_for(:visitor) } it { is_expected.to be_denied_for(:visitor) }
end end
describe "GET /:project_path/branches" do describe "GET /:project_path/-/branches" do
subject { project_branches_path(project) } subject { project_branches_path(project) }
before do before do
@ -495,7 +495,7 @@ describe "Public Project Access" do
it { is_expected.to be_allowed_for(:visitor) } it { is_expected.to be_allowed_for(:visitor) }
end end
describe "GET /:project_path/tags" do describe "GET /:project_path/-/tags" do
subject { project_tags_path(project) } subject { project_tags_path(project) }
before do before do

View File

@ -91,16 +91,37 @@ describe('Monitoring mutations', () => {
expect(stateCopy.projectPath).toEqual('/gitlab-org/gitlab-foss'); expect(stateCopy.projectPath).toEqual('/gitlab-org/gitlab-foss');
}); });
it('should not remove default value of logsPath', () => { it('should not remove previously set properties', () => {
const defaultLogsPath = stateCopy.logsPath; const defaultLogsPath = stateCopy.logsPath;
mutations[types.SET_ENDPOINTS](stateCopy, {
logsPath: defaultLogsPath,
});
mutations[types.SET_ENDPOINTS](stateCopy, { mutations[types.SET_ENDPOINTS](stateCopy, {
dashboardEndpoint: 'dashboard.json', dashboardEndpoint: 'dashboard.json',
}); });
mutations[types.SET_ENDPOINTS](stateCopy, {
projectPath: '/gitlab-org/gitlab-foss',
});
expect(stateCopy.logsPath).toBe(defaultLogsPath); expect(stateCopy).toMatchObject({
logsPath: defaultLogsPath,
dashboardEndpoint: 'dashboard.json',
projectPath: '/gitlab-org/gitlab-foss',
});
});
it('should not update unknown properties', () => {
mutations[types.SET_ENDPOINTS](stateCopy, {
dashboardEndpoint: 'dashboard.json',
someOtherProperty: 'some invalid value', // someOtherProperty is not allowed
});
expect(stateCopy.dashboardEndpoint).toBe('dashboard.json');
expect(stateCopy.someOtherProperty).toBeUndefined();
}); });
}); });
describe('Individual panel/metric results', () => { describe('Individual panel/metric results', () => {
const metricId = '12_system_metrics_kubernetes_container_memory_total'; const metricId = '12_system_metrics_kubernetes_container_memory_total';
const result = [ const result = [

View File

@ -1,10 +1,10 @@
import Vuex from 'vuex'; import Vuex from 'vuex';
import { mount } from '@vue/test-utils'; import { mount } from '@vue/test-utils';
import ReleaseDetailApp from '~/releases/detail/components/app.vue'; import ReleaseEditApp from '~/releases/components/app_edit.vue';
import { release } from '../../mock_data'; import { release } from '../mock_data';
import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils'; import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils';
describe('Release detail component', () => { describe('Release edit component', () => {
let wrapper; let wrapper;
let releaseClone; let releaseClone;
let actions; let actions;
@ -27,9 +27,17 @@ describe('Release detail component', () => {
navigateToReleasesPage: jest.fn(), navigateToReleasesPage: jest.fn(),
}; };
const store = new Vuex.Store({ actions, state }); const store = new Vuex.Store({
modules: {
detail: {
namespaced: true,
actions,
state,
},
},
});
wrapper = mount(ReleaseDetailApp, { wrapper = mount(ReleaseEditApp, {
store, store,
}); });

View File

@ -2,8 +2,8 @@ import { mount } from '@vue/test-utils';
import { GlLink } from '@gitlab/ui'; import { GlLink } from '@gitlab/ui';
import { truncateSha } from '~/lib/utils/text_utility'; import { truncateSha } from '~/lib/utils/text_utility';
import Icon from '~/vue_shared/components/icon.vue'; import Icon from '~/vue_shared/components/icon.vue';
import { release } from '../../mock_data'; import { release } from '../mock_data';
import EvidenceBlock from '~/releases/list/components/evidence_block.vue'; import EvidenceBlock from '~/releases/components/evidence_block.vue';
import ClipboardButton from '~/vue_shared/components/clipboard_button.vue'; import ClipboardButton from '~/vue_shared/components/clipboard_button.vue';
describe('Evidence Block', () => { describe('Evidence Block', () => {

View File

@ -1,9 +1,9 @@
import { mount } from '@vue/test-utils'; import { mount } from '@vue/test-utils';
import { GlLink } from '@gitlab/ui'; import { GlLink } from '@gitlab/ui';
import { trimText } from 'helpers/text_helper'; import { trimText } from 'helpers/text_helper';
import ReleaseBlockFooter from '~/releases/list/components/release_block_footer.vue'; import ReleaseBlockFooter from '~/releases/components/release_block_footer.vue';
import Icon from '~/vue_shared/components/icon.vue'; import Icon from '~/vue_shared/components/icon.vue';
import { release } from '../../mock_data'; import { release } from '../mock_data';
import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils'; import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils';
jest.mock('~/vue_shared/mixins/timeago', () => ({ jest.mock('~/vue_shared/mixins/timeago', () => ({

View File

@ -1,9 +1,9 @@
import { shallowMount } from '@vue/test-utils'; import { shallowMount } from '@vue/test-utils';
import { cloneDeep, merge } from 'lodash'; import { cloneDeep, merge } from 'lodash';
import { GlLink } from '@gitlab/ui'; import { GlLink } from '@gitlab/ui';
import ReleaseBlockHeader from '~/releases/list/components/release_block_header.vue'; import ReleaseBlockHeader from '~/releases/components/release_block_header.vue';
import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils'; import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils';
import { release as originalRelease } from '../../mock_data'; import { release as originalRelease } from '../mock_data';
describe('Release block header', () => { describe('Release block header', () => {
let wrapper; let wrapper;

View File

@ -1,9 +1,9 @@
import { mount } from '@vue/test-utils'; import { mount } from '@vue/test-utils';
import { GlProgressBar, GlLink, GlBadge, GlButton } from '@gitlab/ui'; import { GlProgressBar, GlLink, GlBadge, GlButton } from '@gitlab/ui';
import { trimText } from 'helpers/text_helper'; import { trimText } from 'helpers/text_helper';
import ReleaseBlockMilestoneInfo from '~/releases/list/components/release_block_milestone_info.vue'; import ReleaseBlockMilestoneInfo from '~/releases/components/release_block_milestone_info.vue';
import { milestones } from '../../mock_data'; import { milestones } from '../mock_data';
import { MAX_MILESTONES_TO_DISPLAY } from '~/releases/list/constants'; import { MAX_MILESTONES_TO_DISPLAY } from '~/releases/constants';
describe('Release block milestone info', () => { describe('Release block milestone info', () => {
let wrapper; let wrapper;

View File

@ -1,11 +1,11 @@
import $ from 'jquery'; import $ from 'jquery';
import { mount } from '@vue/test-utils'; import { mount } from '@vue/test-utils';
import { first } from 'underscore'; import { first } from 'underscore';
import EvidenceBlock from '~/releases/list/components/evidence_block.vue'; import EvidenceBlock from '~/releases/components/evidence_block.vue';
import ReleaseBlock from '~/releases/list/components/release_block.vue'; import ReleaseBlock from '~/releases/components/release_block.vue';
import ReleaseBlockFooter from '~/releases/list/components/release_block_footer.vue'; import ReleaseBlockFooter from '~/releases/components/release_block_footer.vue';
import timeagoMixin from '~/vue_shared/mixins/timeago'; import timeagoMixin from '~/vue_shared/mixins/timeago';
import { release } from '../../mock_data'; import { release } from '../mock_data';
import Icon from '~/vue_shared/components/icon.vue'; import Icon from '~/vue_shared/components/icon.vue';
import { scrollToElement } from '~/lib/utils/common_utils'; import { scrollToElement } from '~/lib/utils/common_utils';

View File

@ -1,10 +1,10 @@
import axios from 'axios'; import axios from 'axios';
import MockAdapter from 'axios-mock-adapter'; import MockAdapter from 'axios-mock-adapter';
import testAction from 'helpers/vuex_action_helper'; import testAction from 'helpers/vuex_action_helper';
import * as actions from '~/releases/detail/store/actions'; import * as actions from '~/releases/stores/modules/detail/actions';
import * as types from '~/releases/detail/store/mutation_types'; import * as types from '~/releases/stores/modules/detail/mutation_types';
import { release } from '../../mock_data'; import { release } from '../../../mock_data';
import state from '~/releases/detail/store/state'; import state from '~/releases/stores/modules/detail/state';
import createFlash from '~/flash'; import createFlash from '~/flash';
import { redirectTo } from '~/lib/utils/url_utility'; import { redirectTo } from '~/lib/utils/url_utility';
import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils'; import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils';

View File

@ -5,10 +5,10 @@
* is resolved * is resolved
*/ */
import state from '~/releases/detail/store/state'; import state from '~/releases/stores/modules/detail/state';
import mutations from '~/releases/detail/store/mutations'; import mutations from '~/releases/stores/modules/detail/mutations';
import * as types from '~/releases/detail/store/mutation_types'; import * as types from '~/releases/stores/modules/detail/mutation_types';
import { release } from '../../mock_data'; import { release } from '../../../mock_data';
describe('Release detail mutations', () => { describe('Release detail mutations', () => {
let stateClone; let stateClone;

View File

@ -1,16 +1,17 @@
import _ from 'underscore'; import _ from 'underscore';
import Vue from 'vue'; import Vue from 'vue';
import { mountComponentWithStore } from 'spec/helpers/vue_mount_component_helper'; import { mountComponentWithStore } from 'spec/helpers/vue_mount_component_helper';
import app from '~/releases/list/components/app.vue'; import app from '~/releases/components/app_index.vue';
import createStore from '~/releases/list/store'; import createStore from '~/releases/stores';
import listModule from '~/releases/stores/modules/list';
import api from '~/api'; import api from '~/api';
import { resetStore } from '../store/helpers'; import { resetStore } from '../stores/modules/list/helpers';
import { import {
pageInfoHeadersWithoutPagination, pageInfoHeadersWithoutPagination,
pageInfoHeadersWithPagination, pageInfoHeadersWithPagination,
release, release,
releases, releases,
} from '../../mock_data'; } from '../mock_data';
describe('Releases App ', () => { describe('Releases App ', () => {
const Component = Vue.extend(app); const Component = Vue.extend(app);
@ -25,7 +26,7 @@ describe('Releases App ', () => {
}; };
beforeEach(() => { beforeEach(() => {
store = createStore(); store = createStore({ list: listModule });
releasesPagination = _.range(21).map(index => ({ ...release, tag_name: `${index}.00` })); releasesPagination = _.range(21).map(index => ({ ...release, tag_name: `${index}.00` }));
}); });

View File

@ -4,12 +4,12 @@ import {
fetchReleases, fetchReleases,
receiveReleasesSuccess, receiveReleasesSuccess,
receiveReleasesError, receiveReleasesError,
} from '~/releases/list/store/actions'; } from '~/releases/stores/modules/list/actions';
import state from '~/releases/list/store/state'; import state from '~/releases/stores/modules/list/state';
import * as types from '~/releases/list/store/mutation_types'; import * as types from '~/releases/stores/modules/list/mutation_types';
import api from '~/api'; import api from '~/api';
import { parseIntPagination } from '~/lib/utils/common_utils'; import { parseIntPagination } from '~/lib/utils/common_utils';
import { pageInfoHeadersWithoutPagination, releases } from '../../mock_data'; import { pageInfoHeadersWithoutPagination, releases } from '../../../mock_data';
describe('Releases State actions', () => { describe('Releases State actions', () => {
let mockedState; let mockedState;

View File

@ -1,4 +1,4 @@
import state from '~/releases/list/store/state'; import state from '~/releases/stores/modules/list/state';
// eslint-disable-next-line import/prefer-default-export // eslint-disable-next-line import/prefer-default-export
export const resetStore = store => { export const resetStore = store => {

Some files were not shown because too many files have changed in this diff Show More