diff options
29 files changed, 324 insertions, 184 deletions
diff --git a/.rubocop.yml b/.rubocop.yml index de04e0cbcfe..4b3931a7cab 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -410,13 +410,10 @@ RSpec/RepeatedExample: - 'spec/models/ability_spec.rb' - 'spec/models/ci/build_spec.rb' - 'spec/models/concerns/issuable_spec.rb' - - 'spec/models/member_spec.rb' - 'spec/models/project_services/chat_message/pipeline_message_spec.rb' - - 'spec/models/wiki_page_spec.rb' - 'spec/routing/admin_routing_spec.rb' - 'spec/rubocop/cop/migration/update_large_table_spec.rb' - 'spec/services/notification_service_spec.rb' - 'spec/services/web_hook_service_spec.rb' - - 'ee/spec/models/group_spec.rb' - 'ee/spec/services/boards/lists/update_service_spec.rb' - 'ee/spec/services/geo/repository_verification_primary_service_spec.rb' diff --git a/app/assets/javascripts/monitoring/components/dashboard.vue b/app/assets/javascripts/monitoring/components/dashboard.vue index 531d23bb6e5..0ceea21fda3 100644 --- a/app/assets/javascripts/monitoring/components/dashboard.vue +++ b/app/assets/javascripts/monitoring/components/dashboard.vue @@ -250,7 +250,7 @@ export default { }, }, created() { - this.setEndpoints({ + this.setInitialState({ metricsEndpoint: this.metricsEndpoint, deploymentsEndpoint: this.deploymentsEndpoint, dashboardEndpoint: this.dashboardEndpoint, @@ -258,6 +258,7 @@ export default { currentDashboard: this.currentDashboard, projectPath: this.projectPath, logsPath: this.logsPath, + currentEnvironmentName: this.currentEnvironmentName, }); }, mounted() { @@ -273,7 +274,7 @@ export default { 'setTimeRange', 'fetchData', 'setGettingStartedEmptyState', - 'setEndpoints', + 'setInitialState', 'setPanelGroupMetrics', 'filterEnvironments', ]), diff --git a/app/assets/javascripts/monitoring/components/embeds/metric_embed.vue b/app/assets/javascripts/monitoring/components/embeds/metric_embed.vue index 8a44e6bd737..3f8b0f76997 100644 --- a/app/assets/javascripts/monitoring/components/embeds/metric_embed.vue +++ b/app/assets/javascripts/monitoring/components/embeds/metric_embed.vue @@ -64,7 +64,10 @@ export default { }, }, mounted() { - this.setInitialState(); + this.setInitialState({ + dashboardEndpoint: removeTimeRangeParams(this.dashboardUrl), + }); + this.setShowErrorBanner(false); this.setTimeRange(this.timeRange); this.fetchDashboard(); @@ -90,11 +93,8 @@ export default { fetchDashboard(dispatch, payload) { return dispatch(`${this.namespace}/fetchDashboard`, payload); }, - setEndpoints(dispatch, payload) { - return dispatch(`${this.namespace}/setEndpoints`, payload); - }, - setFeatureFlags(dispatch, payload) { - return dispatch(`${this.namespace}/setFeatureFlags`, payload); + setInitialState(dispatch, payload) { + return dispatch(`${this.namespace}/setInitialState`, payload); }, setShowErrorBanner(dispatch, payload) { return dispatch(`${this.namespace}/setShowErrorBanner`, payload); @@ -108,12 +108,6 @@ export default { this.elWidth = this.$el.clientWidth; }, sidebarAnimationDuration); }, - setInitialState() { - this.setEndpoints({ - dashboardEndpoint: removeTimeRangeParams(this.dashboardUrl), - }); - this.setShowErrorBanner(false); - }, }, }; </script> diff --git a/app/assets/javascripts/monitoring/constants.js b/app/assets/javascripts/monitoring/constants.js index f9a911ddf03..3990a8d1f61 100644 --- a/app/assets/javascripts/monitoring/constants.js +++ b/app/assets/javascripts/monitoring/constants.js @@ -79,3 +79,28 @@ export const dateFormats = { timeOfDay: 'h:MM TT', default: 'dd mmm yyyy, h:MMTT', }; + +/** + * These Vuex store properties are allowed to be + * replaced dynamically after component has been created + * and initial state has been set. + * + * Currently used in `receiveMetricsDashboardSuccess` action. + */ +export const endpointKeys = [ + 'metricsEndpoint', + 'deploymentsEndpoint', + 'dashboardEndpoint', + 'dashboardsEndpoint', + 'currentDashboard', + 'projectPath', + 'logsPath', +]; + +/** + * These Vuex store properties are set as soon as the + * dashboard component has been created. The values are + * passed as data-* attributes and received by dashboard + * as Vue props. + */ +export const initialStateKeys = [...endpointKeys, 'currentEnvironmentName']; diff --git a/app/assets/javascripts/monitoring/stores/actions.js b/app/assets/javascripts/monitoring/stores/actions.js index 7ea43d57039..86f416240c8 100644 --- a/app/assets/javascripts/monitoring/stores/actions.js +++ b/app/assets/javascripts/monitoring/stores/actions.js @@ -30,8 +30,8 @@ export const setGettingStartedEmptyState = ({ commit }) => { commit(types.SET_GETTING_STARTED_EMPTY_STATE); }; -export const setEndpoints = ({ commit }, endpoints) => { - commit(types.SET_ENDPOINTS, endpoints); +export const setInitialState = ({ commit }, initialState) => { + commit(types.SET_INITIAL_STATE, initialState); }; export const setTimeRange = ({ commit }, timeRange) => { diff --git a/app/assets/javascripts/monitoring/stores/mutation_types.js b/app/assets/javascripts/monitoring/stores/mutation_types.js index 8873142accc..09eb7dc1673 100644 --- a/app/assets/javascripts/monitoring/stores/mutation_types.js +++ b/app/assets/javascripts/monitoring/stores/mutation_types.js @@ -17,6 +17,7 @@ export const RECEIVE_METRIC_RESULT_FAILURE = 'RECEIVE_METRIC_RESULT_FAILURE'; export const SET_TIME_RANGE = 'SET_TIME_RANGE'; export const SET_ALL_DASHBOARDS = 'SET_ALL_DASHBOARDS'; export const SET_ENDPOINTS = 'SET_ENDPOINTS'; +export const SET_INITIAL_STATE = 'SET_INITIAL_STATE'; export const SET_GETTING_STARTED_EMPTY_STATE = 'SET_GETTING_STARTED_EMPTY_STATE'; export const SET_NO_DATA_EMPTY_STATE = 'SET_NO_DATA_EMPTY_STATE'; export const SET_SHOW_ERROR_BANNER = 'SET_SHOW_ERROR_BANNER'; diff --git a/app/assets/javascripts/monitoring/stores/mutations.js b/app/assets/javascripts/monitoring/stores/mutations.js index 7aac98821c9..2e10d189087 100644 --- a/app/assets/javascripts/monitoring/stores/mutations.js +++ b/app/assets/javascripts/monitoring/stores/mutations.js @@ -3,7 +3,7 @@ import pick from 'lodash/pick'; import * as types from './mutation_types'; import { mapToDashboardViewModel, normalizeQueryResult } from './utils'; import { BACKOFF_TIMEOUT } from '../../lib/utils/common_utils'; -import { metricStates } from '../constants'; +import { endpointKeys, initialStateKeys, metricStates } from '../constants'; import httpStatusCodes from '~/lib/utils/http_status'; /** @@ -150,19 +150,11 @@ export default { state: emptyStateFromError(error), }); }, + [types.SET_INITIAL_STATE](state, initialState = {}) { + Object.assign(state, pick(initialState, initialStateKeys)); + }, [types.SET_ENDPOINTS](state, endpoints = {}) { - const endpointKeys = [ - 'metricsEndpoint', - 'deploymentsEndpoint', - 'dashboardEndpoint', - 'dashboardsEndpoint', - 'currentDashboard', - 'projectPath', - 'logsPath', - ]; - Object.entries(pick(endpoints, endpointKeys)).forEach(([key, value]) => { - state[key] = value; - }); + Object.assign(state, pick(endpoints, endpointKeys)); }, [types.SET_TIME_RANGE](state, timeRange) { state.timeRange = timeRange; diff --git a/app/assets/javascripts/releases/components/app_index.vue b/app/assets/javascripts/releases/components/app_index.vue index 511b3cda9c8..215a376fc76 100644 --- a/app/assets/javascripts/releases/components/app_index.vue +++ b/app/assets/javascripts/releases/components/app_index.vue @@ -103,7 +103,7 @@ export default { <div v-else-if="shouldRenderSuccessState" class="js-success-state"> <release-block v-for="(release, index) in releases" - :key="release.tagName" + :key="index" :release="release" :class="{ 'linked-card': releases.length > 1 && index !== releases.length - 1 }" /> diff --git a/app/assets/javascripts/releases/components/release_block.vue b/app/assets/javascripts/releases/components/release_block.vue index 515aa629476..58045b57d80 100644 --- a/app/assets/javascripts/releases/components/release_block.vue +++ b/app/assets/javascripts/releases/components/release_block.vue @@ -37,7 +37,11 @@ export default { }; }, computed: { - id() { + htmlId() { + if (!this.release.tagName) { + return null; + } + return slugify(this.release.tagName); }, assets() { @@ -72,7 +76,7 @@ export default { this.renderGFM(); const hash = getLocationHash(); - if (hash && slugify(hash) === this.id) { + if (hash && slugify(hash) === this.htmlId) { this.isHighlighted = true; setTimeout(() => { this.isHighlighted = false; @@ -89,7 +93,7 @@ export default { }; </script> <template> - <div :id="id" :class="{ 'bg-line-target-blue': isHighlighted }" class="card release-block"> + <div :id="htmlId" :class="{ 'bg-line-target-blue': isHighlighted }" class="card release-block"> <release-block-header :release="release" /> <div class="card-body"> <div v-if="shouldRenderMilestoneInfo"> diff --git a/app/workers/reactive_caching_worker.rb b/app/workers/reactive_caching_worker.rb index 1921ac6619b..513033281e5 100644 --- a/app/workers/reactive_caching_worker.rb +++ b/app/workers/reactive_caching_worker.rb @@ -15,7 +15,7 @@ class ReactiveCachingWorker # rubocop:disable Scalability/IdempotentWorker def self.context_for_arguments(arguments) class_name, *_other_args = arguments - Gitlab::ApplicationContext.new(related_class: class_name) + Gitlab::ApplicationContext.new(related_class: class_name.to_s) end def perform(class_name, id, *args) diff --git a/changelogs/unreleased/nfriend-fix-guest-user-releases.yml b/changelogs/unreleased/nfriend-fix-guest-user-releases.yml new file mode 100644 index 00000000000..784fd421fc0 --- /dev/null +++ b/changelogs/unreleased/nfriend-fix-guest-user-releases.yml @@ -0,0 +1,5 @@ +--- +title: Fix Releases page for Guest users of private projects +merge_request: 28447 +author: +type: fixed diff --git a/changelogs/unreleased/refactor-member-spec.yml b/changelogs/unreleased/refactor-member-spec.yml new file mode 100644 index 00000000000..21288aa9ad9 --- /dev/null +++ b/changelogs/unreleased/refactor-member-spec.yml @@ -0,0 +1,5 @@ +--- +title: Refactor duplicate member specs +merge_request: 28574 +author: Rajendra Kadam +type: added diff --git a/changelogs/unreleased/refator-wiki-page.yml b/changelogs/unreleased/refator-wiki-page.yml new file mode 100644 index 00000000000..91fc65354d9 --- /dev/null +++ b/changelogs/unreleased/refator-wiki-page.yml @@ -0,0 +1,5 @@ +--- +title: Refactor duplicate specs in wiki page specs +merge_request: 28551 +author: Rajendra Kadam +type: added diff --git a/doc/administration/high_availability/README.md b/doc/administration/high_availability/README.md index 2bc2f28e4c5..b5258a66e59 100644 --- a/doc/administration/high_availability/README.md +++ b/doc/administration/high_availability/README.md @@ -161,20 +161,20 @@ On different cloud vendors a best effort like for like can be used. - **Test RPS rates:** API: 40 RPS, Web: 4 RPS, Git: 4 RPS - **Known issues:** [List of known performance issues](https://gitlab.com/gitlab-org/gitlab/issues?label_name%5B%5D=Quality%3Aperformance-issues) -| Service | Nodes | Configuration[^8] | GCP type | -| ----------------------------|-------|-----------------------|---------------| -| GitLab Rails[^1] | 3 | 8 vCPU, 7.2GB Memory | n1-highcpu-8 | -| PostgreSQL | 3 | 2 vCPU, 7.5GB Memory | n1-standard-2 | -| PgBouncer | 3 | 2 vCPU, 1.8GB Memory | n1-highcpu-2 | -| Gitaly[^2] [^5] [^7] | X | 4 vCPU, 15GB Memory | n1-standard-4 | -| Redis[^3] | 3 | 2 vCPU, 7.5GB Memory | n1-standard-2 | -| Consul + Sentinel[^3] | 3 | 2 vCPU, 1.8GB Memory | n1-highcpu-2 | -| Sidekiq | 4 | 2 vCPU, 7.5GB Memory | n1-standard-2 | -| Cloud Object Storage[^4] | - | - | - | -| NFS Server[^5] [^7] | 1 | 4 vCPU, 3.6GB Memory | n1-highcpu-4 | -| Monitoring node | 1 | 2 vCPU, 1.8GB Memory | n1-highcpu-2 | -| External load balancing node[^6] | 1 | 2 vCPU, 1.8GB Memory | n1-highcpu-2 | -| Internal load balancing node[^6] | 1 | 2 vCPU, 1.8GB Memory | n1-highcpu-2 | +| Service | Nodes | Configuration[^8] | GCP type | AWS type[^9] | +| ----------------------------|-------|-----------------------|---------------|--------------| +| GitLab Rails[^1] | 3 | 8 vCPU, 7.2GB Memory | n1-highcpu-8 | c5.2xlarge | +| PostgreSQL | 3 | 2 vCPU, 7.5GB Memory | n1-standard-2 | m5.large | +| PgBouncer | 3 | 2 vCPU, 1.8GB Memory | n1-highcpu-2 | c5.large | +| Gitaly[^2] [^5] [^7] | X | 4 vCPU, 15GB Memory | n1-standard-4 | m5.xlarge | +| Redis[^3] | 3 | 2 vCPU, 7.5GB Memory | n1-standard-2 | m5.large | +| Consul + Sentinel[^3] | 3 | 2 vCPU, 1.8GB Memory | n1-highcpu-2 | c5.large | +| Sidekiq | 4 | 2 vCPU, 7.5GB Memory | n1-standard-2 | m5.large | +| Cloud Object Storage[^4] | - | - | - | - | +| NFS Server[^5] [^7] | 1 | 4 vCPU, 3.6GB Memory | n1-highcpu-4 | c5.xlarge | +| Monitoring node | 1 | 2 vCPU, 1.8GB Memory | n1-highcpu-2 | c5.large | +| External load balancing node[^6] | 1 | 2 vCPU, 1.8GB Memory | n1-highcpu-2 | c5.large | +| Internal load balancing node[^6] | 1 | 2 vCPU, 1.8GB Memory | n1-highcpu-2 | c5.large | ### 5,000 user configuration @@ -182,20 +182,20 @@ On different cloud vendors a best effort like for like can be used. - **Test RPS rates:** API: 100 RPS, Web: 10 RPS, Git: 10 RPS - **Known issues:** [List of known performance issues](https://gitlab.com/gitlab-org/gitlab/issues?label_name%5B%5D=Quality%3Aperformance-issues) -| Service | Nodes | Configuration[^8] | GCP type | -| ----------------------------|-------|-----------------------|---------------| -| GitLab Rails[^1] | 3 | 16 vCPU, 14.4GB Memory | n1-highcpu-16 | -| PostgreSQL | 3 | 2 vCPU, 7.5GB Memory | n1-standard-2 | -| PgBouncer | 3 | 2 vCPU, 1.8GB Memory | n1-highcpu-2 | -| Gitaly[^2] [^5] [^7] | X | 8 vCPU, 30GB Memory | n1-standard-8 | -| Redis[^3] | 3 | 2 vCPU, 7.5GB Memory | n1-standard-2 | -| Consul + Sentinel[^3] | 3 | 2 vCPU, 1.8GB Memory | n1-highcpu-2 | -| Sidekiq | 4 | 2 vCPU, 7.5GB Memory | n1-standard-2 | -| Cloud Object Storage[^4] | - | - | - | -| NFS Server[^5] [^7] | 1 | 4 vCPU, 3.6GB Memory | n1-highcpu-4 | -| Monitoring node | 1 | 2 vCPU, 1.8GB Memory | n1-highcpu-2 | -| External load balancing node[^6] | 1 | 2 vCPU, 1.8GB Memory | n1-highcpu-2 | -| Internal load balancing node[^6] | 1 | 2 vCPU, 1.8GB Memory | n1-highcpu-2 | +| Service | Nodes | Configuration[^8] | GCP type | AWS type[^9] | +| ----------------------------|-------|------------------------|---------------|--------------| +| GitLab Rails[^1] | 3 | 16 vCPU, 14.4GB Memory | n1-highcpu-16 | c5.4xlarge | +| PostgreSQL | 3 | 2 vCPU, 7.5GB Memory | n1-standard-2 | m5.large | +| PgBouncer | 3 | 2 vCPU, 1.8GB Memory | n1-highcpu-2 | c5.large | +| Gitaly[^2] [^5] [^7] | X | 8 vCPU, 30GB Memory | n1-standard-8 | m5.2xlarge | +| Redis[^3] | 3 | 2 vCPU, 7.5GB Memory | n1-standard-2 | m5.large | +| Consul + Sentinel[^3] | 3 | 2 vCPU, 1.8GB Memory | n1-highcpu-2 | c5.large | +| Sidekiq | 4 | 2 vCPU, 7.5GB Memory | n1-standard-2 | m5.large | +| Cloud Object Storage[^4] | - | - | - | - | +| NFS Server[^5] [^7] | 1 | 4 vCPU, 3.6GB Memory | n1-highcpu-4 | c5.xlarge | +| Monitoring node | 1 | 2 vCPU, 1.8GB Memory | n1-highcpu-2 | c5.large | +| External load balancing node[^6] | 1 | 2 vCPU, 1.8GB Memory | n1-highcpu-2 | c5.large | +| Internal load balancing node[^6] | 1 | 2 vCPU, 1.8GB Memory | n1-highcpu-2 | c5.large | ### 10,000 user configuration @@ -203,23 +203,23 @@ On different cloud vendors a best effort like for like can be used. - **Test RPS rates:** API: 200 RPS, Web: 20 RPS, Git: 20 RPS - **Known issues:** [List of known performance issues](https://gitlab.com/gitlab-org/gitlab/issues?label_name%5B%5D=Quality%3Aperformance-issues) -| Service | Nodes | Configuration[^8] | GCP type | -| ----------------------------|-------|-----------------------|---------------| -| GitLab Rails[^1] | 3 | 32 vCPU, 28.8GB Memory | n1-highcpu-32 | -| PostgreSQL | 3 | 4 vCPU, 15GB Memory | n1-standard-4 | -| PgBouncer | 3 | 2 vCPU, 1.8GB Memory | n1-highcpu-2 | -| Gitaly[^2] [^5] [^7] | X | 16 vCPU, 60GB Memory | n1-standard-16 | -| Redis[^3] - Cache | 3 | 4 vCPU, 15GB Memory | n1-standard-4 | -| Redis[^3] - Queues / Shared State | 3 | 4 vCPU, 15GB Memory | n1-standard-4 | -| Redis Sentinel[^3] - Cache | 3 | 1 vCPU, 1.7GB Memory | g1-small | -| Redis Sentinel[^3] - Queues / Shared State | 3 | 1 vCPU, 1.7GB Memory | g1-small | -| Consul | 3 | 2 vCPU, 1.8GB Memory | n1-highcpu-2 | -| Sidekiq | 4 | 4 vCPU, 15GB Memory | n1-standard-4 | -| Cloud Object Storage[^4] | - | - | - | -| NFS Server[^5] [^7] | 1 | 4 vCPU, 3.6GB Memory | n1-highcpu-4 | -| Monitoring node | 1 | 4 vCPU, 3.6GB Memory | n1-highcpu-4 | -| External load balancing node[^6] | 1 | 2 vCPU, 1.8GB Memory | n1-highcpu-2 | -| Internal load balancing node[^6] | 1 | 2 vCPU, 1.8GB Memory | n1-highcpu-2 | +| Service | Nodes | GCP Configuration[^8] | GCP type | AWS type[^9] | +| ----------------------------|-------|------------------------|----------------|--------------| +| GitLab Rails[^1] | 3 | 32 vCPU, 28.8GB Memory | n1-highcpu-32 | c5.9xlarge | +| PostgreSQL | 3 | 4 vCPU, 15GB Memory | n1-standard-4 | m5.xlarge | +| PgBouncer | 3 | 2 vCPU, 1.8GB Memory | n1-highcpu-2 | c5.large | +| Gitaly[^2] [^5] [^7] | X | 16 vCPU, 60GB Memory | n1-standard-16 | m5.4xlarge | +| Redis[^3] - Cache | 3 | 4 vCPU, 15GB Memory | n1-standard-4 | m5.xlarge | +| Redis[^3] - Queues / Shared State | 3 | 4 vCPU, 15GB Memory | n1-standard-4 | m5.xlarge | +| Redis Sentinel[^3] - Cache | 3 | 1 vCPU, 1.7GB Memory | g1-small | t2.small | +| Redis Sentinel[^3] - Queues / Shared State | 3 | 1 vCPU, 1.7GB Memory | g1-small | t2.small | +| Consul | 3 | 2 vCPU, 1.8GB Memory | n1-highcpu-2 | c5.large | +| Sidekiq | 4 | 4 vCPU, 15GB Memory | n1-standard-4 | m5.xlarge | +| Cloud Object Storage[^4] | - | - | - | - | +| NFS Server[^5] [^7] | 1 | 4 vCPU, 3.6GB Memory | n1-highcpu-4 | c5.xlarge | +| Monitoring node | 1 | 4 vCPU, 3.6GB Memory | n1-highcpu-4 | c5.xlarge | +| External load balancing node[^6] | 1 | 2 vCPU, 1.8GB Memory | n1-highcpu-2 | c5.large | +| Internal load balancing node[^6] | 1 | 2 vCPU, 1.8GB Memory | n1-highcpu-2 | c5.large | ### 25,000 user configuration @@ -227,23 +227,23 @@ On different cloud vendors a best effort like for like can be used. - **Test RPS rates:** API: 500 RPS, Web: 50 RPS, Git: 50 RPS - **Known issues:** [List of known performance issues](https://gitlab.com/gitlab-org/gitlab/issues?label_name%5B%5D=Quality%3Aperformance-issues) -| Service | Nodes | Configuration[^8] | GCP type | -| ----------------------------|-------|-----------------------|---------------| -| GitLab Rails[^1] | 5 | 32 vCPU, 28.8GB Memory | n1-highcpu-32 | -| PostgreSQL | 3 | 8 vCPU, 30GB Memory | n1-standard-8 | -| PgBouncer | 3 | 2 vCPU, 1.8GB Memory | n1-highcpu-2 | -| Gitaly[^2] [^5] [^7] | X | 32 vCPU, 120GB Memory | n1-standard-32 | -| Redis[^3] - Cache | 3 | 4 vCPU, 15GB Memory | n1-standard-4 | -| Redis[^3] - Queues / Shared State | 3 | 4 vCPU, 15GB Memory | n1-standard-4 | -| Redis Sentinel[^3] - Cache | 3 | 1 vCPU, 1.7GB Memory | g1-small | -| Redis Sentinel[^3] - Queues / Shared State | 3 | 1 vCPU, 1.7GB Memory | g1-small | -| Consul | 3 | 2 vCPU, 1.8GB Memory | n1-highcpu-2 | -| Sidekiq | 4 | 4 vCPU, 15GB Memory | n1-standard-4 | -| Cloud Object Storage[^4] | - | - | - | -| NFS Server[^5] [^7] | 1 | 4 vCPU, 3.6GB Memory | n1-highcpu-4 | -| Monitoring node | 1 | 4 vCPU, 3.6GB Memory | n1-highcpu-4 | -| External load balancing node[^6] | 1 | 2 vCPU, 1.8GB Memory | n1-highcpu-2 | -| Internal load balancing node[^6] | 1 | 4 vCPU, 3.6GB Memory | n1-highcpu-4 | +| Service | Nodes | Configuration[^8] | GCP type | AWS type[^9] | +| ----------------------------|-------|------------------------|----------------|--------------| +| GitLab Rails[^1] | 5 | 32 vCPU, 28.8GB Memory | n1-highcpu-32 | c5.9xlarge | +| PostgreSQL | 3 | 8 vCPU, 30GB Memory | n1-standard-8 | m5.2xlarge | +| PgBouncer | 3 | 2 vCPU, 1.8GB Memory | n1-highcpu-2 | c5.large | +| Gitaly[^2] [^5] [^7] | X | 32 vCPU, 120GB Memory | n1-standard-32 | m5.8xlarge | +| Redis[^3] - Cache | 3 | 4 vCPU, 15GB Memory | n1-standard-4 | m5.xlarge | +| Redis[^3] - Queues / Shared State | 3 | 4 vCPU, 15GB Memory | n1-standard-4 | m5.xlarge | +| Redis Sentinel[^3] - Cache | 3 | 1 vCPU, 1.7GB Memory | g1-small | t2.small | +| Redis Sentinel[^3] - Queues / Shared State | 3 | 1 vCPU, 1.7GB Memory | g1-small | t2.small | +| Consul | 3 | 2 vCPU, 1.8GB Memory | n1-highcpu-2 | c5.large | +| Sidekiq | 4 | 4 vCPU, 15GB Memory | n1-standard-4 | m5.xlarge | +| Cloud Object Storage[^4] | - | - | - | - | +| NFS Server[^5] [^7] | 1 | 4 vCPU, 3.6GB Memory | n1-highcpu-4 | c5.xlarge | +| Monitoring node | 1 | 4 vCPU, 3.6GB Memory | n1-highcpu-4 | c5.xlarge | +| External load balancing node[^6] | 1 | 2 vCPU, 1.8GB Memory | n1-highcpu-2 | c5.large | +| Internal load balancing node[^6] | 1 | 4 vCPU, 3.6GB Memory | n1-highcpu-4 | c5.xlarge | ### 50,000 user configuration @@ -251,23 +251,23 @@ On different cloud vendors a best effort like for like can be used. - **Test RPS rates:** API: 1000 RPS, Web: 100 RPS, Git: 100 RPS - **Known issues:** [List of known performance issues](https://gitlab.com/gitlab-org/gitlab/issues?label_name%5B%5D=Quality%3Aperformance-issues) -| Service | Nodes | Configuration[^8] | GCP type | -| ----------------------------|-------|-----------------------|---------------| -| GitLab Rails[^1] | 12 | 32 vCPU, 28.8GB Memory | n1-highcpu-32 | -| PostgreSQL | 3 | 16 vCPU, 60GB Memory | n1-standard-16 | -| PgBouncer | 3 | 2 vCPU, 1.8GB Memory | n1-highcpu-2 | -| Gitaly[^2] [^5] [^7] | X | 64 vCPU, 240GB Memory | n1-standard-64 | -| Redis[^3] - Cache | 3 | 4 vCPU, 15GB Memory | n1-standard-4 | -| Redis[^3] - Queues / Shared State | 3 | 4 vCPU, 15GB Memory | n1-standard-4 | -| Redis Sentinel[^3] - Cache | 3 | 1 vCPU, 1.7GB Memory | g1-small | -| Redis Sentinel[^3] - Queues / Shared State | 3 | 1 vCPU, 1.7GB Memory | g1-small | -| Consul | 3 | 2 vCPU, 1.8GB Memory | n1-highcpu-2 | -| Sidekiq | 4 | 4 vCPU, 15GB Memory | n1-standard-4 | -| NFS Server[^5] [^7] | 1 | 4 vCPU, 3.6GB Memory | n1-highcpu-4 | -| Cloud Object Storage[^4] | - | - | - | -| Monitoring node | 1 | 4 vCPU, 3.6GB Memory | n1-highcpu-4 | -| External load balancing node[^6] | 1 | 2 vCPU, 1.8GB Memory | n1-highcpu-2 | -| Internal load balancing node[^6] | 1 | 8 vCPU, 7.2GB Memory | n1-highcpu-8 | +| Service | Nodes | Configuration[^8] | GCP type | AWS type[^9] | +| ----------------------------|-------|------------------------|----------------|--------------| +| GitLab Rails[^1] | 12 | 32 vCPU, 28.8GB Memory | n1-highcpu-32 | c5.9xlarge | +| PostgreSQL | 3 | 16 vCPU, 60GB Memory | n1-standard-16 | m5.4xlarge | +| PgBouncer | 3 | 2 vCPU, 1.8GB Memory | n1-highcpu-2 | c5.large | +| Gitaly[^2] [^5] [^7] | X | 64 vCPU, 240GB Memory | n1-standard-64 | m5.16xlarge | +| Redis[^3] - Cache | 3 | 4 vCPU, 15GB Memory | n1-standard-4 | m5.xlarge | +| Redis[^3] - Queues / Shared State | 3 | 4 vCPU, 15GB Memory | n1-standard-4 | m5.xlarge | +| Redis Sentinel[^3] - Cache | 3 | 1 vCPU, 1.7GB Memory | g1-small | t2.small | +| Redis Sentinel[^3] - Queues / Shared State | 3 | 1 vCPU, 1.7GB Memory | g1-small | t2.small | +| Consul | 3 | 2 vCPU, 1.8GB Memory | n1-highcpu-2 | c5.large | +| Sidekiq | 4 | 4 vCPU, 15GB Memory | n1-standard-4 | m5.xlarge | +| NFS Server[^5] [^7] | 1 | 4 vCPU, 3.6GB Memory | n1-highcpu-4 | c5.xlarge | +| Cloud Object Storage[^4] | - | - | - | - | +| Monitoring node | 1 | 4 vCPU, 3.6GB Memory | n1-highcpu-4 | c5.xlarge | +| External load balancing node[^6] | 1 | 2 vCPU, 1.8GB Memory | n1-highcpu-2 | c5.large | +| Internal load balancing node[^6] | 1 | 8 vCPU, 7.2GB Memory | n1-highcpu-8 | c5.2xlarge | [^1]: In our architectures we run each GitLab Rails node using the Puma webserver and have its number of workers set to 90% of available CPUs along with 4 threads. @@ -311,3 +311,6 @@ On different cloud vendors a best effort like for like can be used. or higher, are required for your CPU or Node counts accordingly. For more info a [Sysbench](https://github.com/akopytov/sysbench) benchmark of the CPU can be found [here](https://gitlab.com/gitlab-org/quality/performance/-/wikis/Reference-Architectures/GCP-CPU-Benchmarks). + +[^9]: AWS-equivalent configurations are rough suggestions and may change in the + future. They have not yet been tested and validated. diff --git a/doc/development/documentation/styleguide.md b/doc/development/documentation/styleguide.md index 940c660dc35..c3f134b569d 100644 --- a/doc/development/documentation/styleguide.md +++ b/doc/development/documentation/styleguide.md @@ -1460,6 +1460,15 @@ Example response: ``` ```` +### Fake user information + +You may need to demonstrate an API call or a cURL command that includes the name +and email address of a user. Don't use real user information in API calls: + +- **Email addresses**: Use an email address ending in `example.com`. +- **Names**: Use strings like `Example Username`. Alternatively, use diverse or non-gendered names with + common surnames, such as `Sidney Jones`, `Zhang Wei`. or `Maria Garcia`. + ### Fake tokens There may be times where a token is needed to demonstrate an API call using diff --git a/doc/user/application_security/container_scanning/index.md b/doc/user/application_security/container_scanning/index.md index 8d0cb8507e6..a368fa4ae02 100644 --- a/doc/user/application_security/container_scanning/index.md +++ b/doc/user/application_security/container_scanning/index.md @@ -170,6 +170,7 @@ using environment variables. | Environment Variable | Description | Default | | ------ | ------ | ------ | | `KLAR_TRACE` | Set to true to enable more verbose output from klar. | `"false"` | +| `CLAIR_TRACE` | Set to true to enable more verbose output from the clair server process. | `"false"` | | `DOCKER_USER` | Username for accessing a Docker registry requiring authentication. | `$CI_REGISTRY_USER` | | `DOCKER_PASSWORD` | Password for accessing a Docker registry requiring authentication. | `$CI_REGISTRY_PASSWORD` | | `CLAIR_OUTPUT` | Severity level threshold. Vulnerabilities with severity level higher than or equal to this threshold will be outputted. Supported levels are `Unknown`, `Negligible`, `Low`, `Medium`, `High`, `Critical` and `Defcon1`. | `Unknown` | diff --git a/doc/user/project/issues/img/issue_health_status_v12_10.png b/doc/user/project/issues/img/issue_health_status_v12_10.png Binary files differnew file mode 100644 index 00000000000..bcd6af144fb --- /dev/null +++ b/doc/user/project/issues/img/issue_health_status_v12_10.png diff --git a/doc/user/project/issues/index.md b/doc/user/project/issues/index.md index e213f92c297..af19c7f2b4a 100644 --- a/doc/user/project/issues/index.md +++ b/doc/user/project/issues/index.md @@ -168,15 +168,15 @@ requires [GraphQL](../../../api/graphql/index.md) to be enabled. ### Status **(ULTIMATE)** -> [Introduced](https://gitlab.com/gitlab-org/gitlab/issues/36427) in [GitLab Ultimate](https://about.gitlab.com/pricing/) 12.9. +> [Introduced](https://gitlab.com/gitlab-org/gitlab/issues/36427) in [GitLab Ultimate](https://about.gitlab.com/pricing/) 12.10. To help you track the status of your issues, you can assign a status to each issue to flag work that's progressing as planned or needs attention to keep on schedule: -- `On track` (green) -- `Needs attention` (amber) -- `At risk` (red) +- **On track** (green) +- **Needs attention** (amber) +- **At risk** (red) -!["On track" health status on an issue](img/issue_health_status_v12_9.png) +!["On track" health status on an issue](img/issue_health_status_v12_10.png) --- diff --git a/locale/gitlab.pot b/locale/gitlab.pot index b2d55f35a62..75d4542e2e3 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -24701,6 +24701,9 @@ msgstr "" msgid "remove due date" msgstr "" +msgid "remove status" +msgstr "" + msgid "remove weight" msgstr "" diff --git a/qa/qa/runtime/browser.rb b/qa/qa/runtime/browser.rb index 7777d06b6f5..adb496e9ef0 100644 --- a/qa/qa/runtime/browser.rb +++ b/qa/qa/runtime/browser.rb @@ -51,9 +51,7 @@ module QA metadata[:type] = :feature end - config.around(:each) do |example| - example.run - + config.append_after(:each) do |example| if example.metadata[:screenshot] screenshot = example.metadata[:screenshot][:image] || example.metadata[:screenshot][:html] example.metadata[:stdout] = %{[[ATTACHMENT|#{screenshot}]]} diff --git a/spec/features/projects/releases/user_views_releases_spec.rb b/spec/features/projects/releases/user_views_releases_spec.rb index a4ba81ffeb9..e21d8ec16e1 100644 --- a/spec/features/projects/releases/user_views_releases_spec.rb +++ b/spec/features/projects/releases/user_views_releases_spec.rb @@ -3,41 +3,33 @@ require 'spec_helper' describe 'User views releases', :js do - let!(:project) { create(:project, :repository) } - let!(:release) { create(:release, project: project ) } - let!(:user) { create(:user) } + let_it_be(:project) { create(:project, :repository, :private) } + let_it_be(:release) { create(:release, project: project, name: 'The first release' ) } + let_it_be(:maintainer) { create(:user) } + let_it_be(:guest) { create(:user) } before do - project.add_maintainer(user) - - gitlab_sign_in(user) + project.add_maintainer(maintainer) + project.add_guest(guest) end - it 'sees the release' do - visit project_releases_path(project) - - expect(page).to have_content(release.name) - expect(page).to have_content(release.tag) - expect(page).not_to have_content('Upcoming Release') - end - - context 'when there is a link as an asset' do - let!(:release_link) { create(:release_link, release: release, url: url ) } - let(:url) { "#{project.web_url}/-/jobs/1/artifacts/download" } - let(:direct_asset_link) { Gitlab::Routing.url_helpers.project_release_url(project, release) << release_link.filepath } + context('when the user is a maintainer') do + before do + gitlab_sign_in(maintainer) + end - it 'sees the link' do + it 'sees the release' do visit project_releases_path(project) - page.within('.js-assets-list') do - expect(page).to have_link release_link.name, href: direct_asset_link - expect(page).not_to have_content('(external source)') - end + expect(page).to have_content(release.name) + expect(page).to have_content(release.tag) + expect(page).not_to have_content('Upcoming Release') end - context 'when there is a link redirect' do - let!(:release_link) { create(:release_link, release: release, name: 'linux-amd64 binaries', filepath: '/binaries/linux-amd64', url: url) } + context 'when there is a link as an asset' do + let!(:release_link) { create(:release_link, release: release, url: url ) } let(:url) { "#{project.web_url}/-/jobs/1/artifacts/download" } + let(:direct_asset_link) { Gitlab::Routing.url_helpers.project_release_url(project, release) << release_link.filepath } it 'sees the link' do visit project_releases_path(project) @@ -47,39 +39,73 @@ describe 'User views releases', :js do expect(page).not_to have_content('(external source)') end end - end - context 'when url points to external resource' do - let(:url) { 'http://google.com/download' } + context 'when there is a link redirect' do + let!(:release_link) { create(:release_link, release: release, name: 'linux-amd64 binaries', filepath: '/binaries/linux-amd64', url: url) } + let(:url) { "#{project.web_url}/-/jobs/1/artifacts/download" } - it 'sees that the link is external resource' do - visit project_releases_path(project) + it 'sees the link' do + visit project_releases_path(project) - page.within('.js-assets-list') do - expect(page).to have_content('(external source)') + page.within('.js-assets-list') do + expect(page).to have_link release_link.name, href: direct_asset_link + expect(page).not_to have_content('(external source)') + end + end + end + + context 'when url points to external resource' do + let(:url) { 'http://google.com/download' } + + it 'sees that the link is external resource' do + visit project_releases_path(project) + + page.within('.js-assets-list') do + expect(page).to have_content('(external source)') + end end end end - end - context 'with an upcoming release' do - let(:tomorrow) { Time.zone.now + 1.day } - let!(:release) { create(:release, project: project, released_at: tomorrow ) } + context 'with an upcoming release' do + let(:tomorrow) { Time.zone.now + 1.day } + let!(:release) { create(:release, project: project, released_at: tomorrow ) } - it 'sees the upcoming tag' do - visit project_releases_path(project) + it 'sees the upcoming tag' do + visit project_releases_path(project) + + expect(page).to have_content('Upcoming Release') + end + end + + context 'with a tag containing a slash' do + it 'sees the release' do + release = create :release, :with_evidence, project: project, tag: 'debian/2.4.0-1' + visit project_releases_path(project) - expect(page).to have_content('Upcoming Release') + expect(page).to have_content(release.name) + expect(page).to have_content(release.tag) + end end end - context 'with a tag containing a slash' do - it 'sees the release' do - release = create :release, :with_evidence, project: project, tag: 'debian/2.4.0-1' + context('when the user is a guest') do + before do + gitlab_sign_in(guest) + end + + it 'renders release info except for Git-related data' do visit project_releases_path(project) - expect(page).to have_content(release.name) - expect(page).to have_content(release.tag) + within('.release-block') do + expect(page).to have_content(release.description) + + # The following properties (sometimes) include Git info, + # so they are not rendered for Guest users + expect(page).not_to have_content(release.name) + expect(page).not_to have_content(release.tag) + expect(page).not_to have_content(release.commit.short_id) + end end end end diff --git a/spec/frontend/monitoring/components/dashboard_spec.js b/spec/frontend/monitoring/components/dashboard_spec.js index b9d838085a1..ec25c9e169a 100644 --- a/spec/frontend/monitoring/components/dashboard_spec.js +++ b/spec/frontend/monitoring/components/dashboard_spec.js @@ -88,11 +88,17 @@ describe('Dashboard', () => { expect(findEnvironmentsDropdown().exists()).toBe(true); }); - it('sets endpoints: logs path', () => { - expect(store.dispatch).toHaveBeenCalledWith( - 'monitoringDashboard/setEndpoints', - expect.objectContaining({ logsPath: propsData.logsPath }), - ); + it('sets initial state', () => { + expect(store.dispatch).toHaveBeenCalledWith('monitoringDashboard/setInitialState', { + currentDashboard: '', + currentEnvironmentName: 'production', + dashboardEndpoint: 'https://invalid', + dashboardsEndpoint: 'https://invalid', + deploymentsEndpoint: null, + logsPath: '/path/to/logs', + metricsEndpoint: 'http://test.host/monitoring/mock', + projectPath: '/path/to/project', + }); }); }); diff --git a/spec/frontend/monitoring/components/embeds/metric_embed_spec.js b/spec/frontend/monitoring/components/embeds/metric_embed_spec.js index d0fe22cefec..b829cd53479 100644 --- a/spec/frontend/monitoring/components/embeds/metric_embed_spec.js +++ b/spec/frontend/monitoring/components/embeds/metric_embed_spec.js @@ -26,9 +26,8 @@ describe('MetricEmbed', () => { beforeEach(() => { actions = { - setFeatureFlags: jest.fn(), + setInitialState: jest.fn(), setShowErrorBanner: jest.fn(), - setEndpoints: jest.fn(), setTimeRange: jest.fn(), fetchDashboard: jest.fn(), }; diff --git a/spec/frontend/monitoring/store/actions_spec.js b/spec/frontend/monitoring/store/actions_spec.js index 203bc6f4e0e..e9f9aa0ba18 100644 --- a/spec/frontend/monitoring/store/actions_spec.js +++ b/spec/frontend/monitoring/store/actions_spec.js @@ -16,7 +16,7 @@ import { fetchEnvironmentsData, fetchPrometheusMetrics, fetchPrometheusMetric, - setEndpoints, + setInitialState, filterEnvironments, setGettingStartedEmptyState, duplicateSystemDashboard, @@ -208,14 +208,14 @@ describe('Monitoring store actions', () => { }); }); - describe('Set endpoints', () => { + describe('Set initial state', () => { let mockedState; beforeEach(() => { mockedState = storeState(); }); - it('should commit SET_ENDPOINTS mutation', done => { + it('should commit SET_INITIAL_STATE mutation', done => { testAction( - setEndpoints, + setInitialState, { metricsEndpoint: 'additional_metrics.json', deploymentsEndpoint: 'deployments.json', @@ -223,7 +223,7 @@ describe('Monitoring store actions', () => { mockedState, [ { - type: types.SET_ENDPOINTS, + type: types.SET_INITIAL_STATE, payload: { metricsEndpoint: 'additional_metrics.json', deploymentsEndpoint: 'deployments.json', diff --git a/spec/frontend/monitoring/store/mutations_spec.js b/spec/frontend/monitoring/store/mutations_spec.js index 5a79b8ef49c..0310c7e9510 100644 --- a/spec/frontend/monitoring/store/mutations_spec.js +++ b/spec/frontend/monitoring/store/mutations_spec.js @@ -86,6 +86,58 @@ describe('Monitoring mutations', () => { expect(typeof stateCopy.deploymentData[0]).toEqual('object'); }); }); + + describe('SET_INITIAL_STATE', () => { + it('should set all the endpoints', () => { + mutations[types.SET_INITIAL_STATE](stateCopy, { + metricsEndpoint: 'additional_metrics.json', + deploymentsEndpoint: 'deployments.json', + dashboardEndpoint: 'dashboard.json', + projectPath: '/gitlab-org/gitlab-foss', + currentEnvironmentName: 'production', + }); + expect(stateCopy.metricsEndpoint).toEqual('additional_metrics.json'); + expect(stateCopy.deploymentsEndpoint).toEqual('deployments.json'); + expect(stateCopy.dashboardEndpoint).toEqual('dashboard.json'); + expect(stateCopy.projectPath).toEqual('/gitlab-org/gitlab-foss'); + expect(stateCopy.currentEnvironmentName).toEqual('production'); + }); + + it('should not remove previously set properties', () => { + const defaultLogsPath = stateCopy.logsPath; + + mutations[types.SET_INITIAL_STATE](stateCopy, { + logsPath: defaultLogsPath, + }); + mutations[types.SET_INITIAL_STATE](stateCopy, { + dashboardEndpoint: 'dashboard.json', + }); + mutations[types.SET_INITIAL_STATE](stateCopy, { + projectPath: '/gitlab-org/gitlab-foss', + }); + mutations[types.SET_INITIAL_STATE](stateCopy, { + currentEnvironmentName: 'canary', + }); + + expect(stateCopy).toMatchObject({ + logsPath: defaultLogsPath, + dashboardEndpoint: 'dashboard.json', + projectPath: '/gitlab-org/gitlab-foss', + currentEnvironmentName: 'canary', + }); + }); + + it('should not update unknown properties', () => { + mutations[types.SET_INITIAL_STATE](stateCopy, { + dashboardEndpoint: 'dashboard.json', + someOtherProperty: 'some invalid value', // someOtherProperty is not allowed + }); + + expect(stateCopy.dashboardEndpoint).toBe('dashboard.json'); + expect(stateCopy.someOtherProperty).toBeUndefined(); + }); + }); + describe('SET_ENDPOINTS', () => { it('should set all the endpoints', () => { mutations[types.SET_ENDPOINTS](stateCopy, { diff --git a/spec/frontend/releases/components/release_block_spec.js b/spec/frontend/releases/components/release_block_spec.js index 7ea2379ea35..9846fcb65eb 100644 --- a/spec/frontend/releases/components/release_block_spec.js +++ b/spec/frontend/releases/components/release_block_spec.js @@ -165,6 +165,14 @@ describe('Release block', () => { }); }); + it('does not set the ID if tagName is missing', () => { + release.tagName = undefined; + + return factory(release).then(() => { + expect(wrapper.attributes().id).toBeUndefined(); + }); + }); + describe('evidence block', () => { it('renders the evidence block when the evidence is available and the feature flag is true', () => factory(release, { releaseEvidenceCollection: true }).then(() => diff --git a/spec/models/member_spec.rb b/spec/models/member_spec.rb index cd9d7c16f88..e922542a984 100644 --- a/spec/models/member_spec.rb +++ b/spec/models/member_spec.rb @@ -38,10 +38,6 @@ describe Member do expect(member).not_to be_valid end - - it "is valid otherwise" do - expect(member).to be_valid - end end context "when an invite email is not provided" do diff --git a/spec/models/wiki_page_spec.rb b/spec/models/wiki_page_spec.rb index e8e80a8c7f4..0a0611bdeb8 100644 --- a/spec/models/wiki_page_spec.rb +++ b/spec/models/wiki_page_spec.rb @@ -577,6 +577,8 @@ describe WikiPage do end it 'returns false when version is nil' do + expect(latest_page).to receive(:version) { nil } + expect(latest_page.historical?).to be_falsy end diff --git a/spec/workers/reactive_caching_worker_spec.rb b/spec/workers/reactive_caching_worker_spec.rb index c39a97b4eee..603ce6160ce 100644 --- a/spec/workers/reactive_caching_worker_spec.rb +++ b/spec/workers/reactive_caching_worker_spec.rb @@ -37,5 +37,13 @@ describe ReactiveCachingWorker do expect(scheduled_job).to include('meta.related_class' => 'Environment') end + + it 'sets the related class on the job when it was passed as a class' do + described_class.perform_async(Project, 1, 'other', 'argument') + + scheduled_job = described_class.jobs.first + + expect(scheduled_job).to include('meta.related_class' => 'Project') + end end end |