Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2021-07-14 09:09:45 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2021-07-14 09:09:45 +0300
commitb52c116c9929b21ab71703e50d140fe2c52f99be (patch)
tree8e6087e59c8c35340041bb9bcd12ce9b6cf4fc59
parentcd4d8b60a0ab51c6d6075a6b7206f1ddbf6295d3 (diff)
Add latest changes from gitlab-org/gitlab@master
-rw-r--r--.markdownlint.yml1
-rw-r--r--GITLAB_PAGES_VERSION2
-rw-r--r--app/assets/javascripts/activities.js2
-rw-r--r--app/assets/javascripts/commits.js2
-rw-r--r--app/assets/javascripts/lib/utils/datetime/timeago_utility.js15
-rw-r--r--app/assets/javascripts/main.js2
-rw-r--r--app/assets/javascripts/members/components/action_buttons/user_action_buttons.vue1
-rw-r--r--app/assets/javascripts/merge_request_tabs.js7
-rw-r--r--app/assets/javascripts/notes.js4
-rw-r--r--app/assets/javascripts/pages/admin/users/components/delete_user_modal.vue4
-rw-r--r--app/assets/javascripts/pages/projects/merge_requests/creations/new/compare.js2
-rw-r--r--app/assets/javascripts/pages/users/user_tabs.js4
-rw-r--r--app/assets/javascripts/vue_shared/components/oncall_schedules_list.vue10
-rw-r--r--danger/datateam/Dangerfile14
-rw-r--r--doc/.markdownlint/markdownlint-no-trailing-spaces.yml1
-rw-r--r--doc/.vale/gitlab/Acronyms.yml1
-rw-r--r--doc/.vale/gitlab/HeaderGerunds.yml2
-rw-r--r--doc/administration/auth/authentiq.md12
-rw-r--r--doc/administration/gitaly/index.md3
-rw-r--r--doc/administration/gitaly/praefect.md199
-rw-r--r--generator_templates/usage_metric_definition/metric_definition.yml2
-rw-r--r--qa/qa/specs/features/browser_ui/2_plan/issue/create_issue_spec.rb5
-rw-r--r--spec/features/dashboard/issues_filter_spec.rb4
-rw-r--r--spec/features/issues/user_sorts_issues_spec.rb23
-rw-r--r--spec/features/merge_requests/user_sorts_merge_requests_spec.rb2
-rw-r--r--spec/frontend/lib/utils/datetime/timeago_utility_spec.js13
-rw-r--r--spec/frontend/pages/admin/users/components/__snapshots__/delete_user_modal_spec.js.snap1
-rw-r--r--spec/frontend/vue_shared/oncall_schedules_list_spec.js2
-rw-r--r--spec/support/matchers/have_issuable_counts.rb2
29 files changed, 218 insertions, 124 deletions
diff --git a/.markdownlint.yml b/.markdownlint.yml
index ccf2ef02eee..35e8ef119be 100644
--- a/.markdownlint.yml
+++ b/.markdownlint.yml
@@ -1,3 +1,4 @@
+---
# Base Markdownlint configuration
# Extended Markdownlint configuration in doc/.markdownlint/
"default": true
diff --git a/GITLAB_PAGES_VERSION b/GITLAB_PAGES_VERSION
index 32b7211cb61..7d47e599800 100644
--- a/GITLAB_PAGES_VERSION
+++ b/GITLAB_PAGES_VERSION
@@ -1 +1 @@
-1.40.0
+1.41.0
diff --git a/app/assets/javascripts/activities.js b/app/assets/javascripts/activities.js
index b671d038ce8..f45af5fe08e 100644
--- a/app/assets/javascripts/activities.js
+++ b/app/assets/javascripts/activities.js
@@ -42,7 +42,7 @@ export default class Activities {
}
updateTooltips() {
- localTimeAgo($('.js-timeago', '.content_list'));
+ localTimeAgo(document.querySelectorAll('.content_list .js-timeago'));
}
reloadActivities() {
diff --git a/app/assets/javascripts/commits.js b/app/assets/javascripts/commits.js
index da7fc88d8ac..39dc4a4e9e5 100644
--- a/app/assets/javascripts/commits.js
+++ b/app/assets/javascripts/commits.js
@@ -93,7 +93,7 @@ export default class CommitsList {
.text(n__('%d commit', '%d commits', commitsCount));
}
- localTimeAgo($processedData.find('.js-timeago'));
+ localTimeAgo($processedData.find('.js-timeago').get());
return processedData;
}
diff --git a/app/assets/javascripts/lib/utils/datetime/timeago_utility.js b/app/assets/javascripts/lib/utils/datetime/timeago_utility.js
index 0199cf20ace..5c6c5ccd5c1 100644
--- a/app/assets/javascripts/lib/utils/datetime/timeago_utility.js
+++ b/app/assets/javascripts/lib/utils/datetime/timeago_utility.js
@@ -1,4 +1,3 @@
-import $ from 'jquery';
import * as timeago from 'timeago.js';
import { languageCode, s__, createDateTimeFormat } from '../../../locale';
import { formatDate } from './date_format_utility';
@@ -97,21 +96,21 @@ export const getTimeago = () =>
/**
* For the given elements, sets a tooltip with a formatted date.
- * @param {JQuery} $timeagoEls
- * @param {Boolean} setTimeago
+ * @param {Array<Node>|NodeList} elements
+ * @param {Boolean} updateTooltip
*/
-export const localTimeAgo = ($timeagoEls, setTimeago = true) => {
+export const localTimeAgo = (elements, updateTooltip = true) => {
const { format } = getTimeago();
- $timeagoEls.each((i, el) => {
- $(el).text(format($(el).attr('datetime'), timeagoLanguageCode));
+ elements.forEach((el) => {
+ el.innerText = format(el.dateTime, timeagoLanguageCode);
});
- if (!setTimeago) {
+ if (!updateTooltip) {
return;
}
function addTimeAgoTooltip() {
- $timeagoEls.each((i, el) => {
+ elements.forEach((el) => {
// Recreate with custom template
el.setAttribute('title', formatDate(el.dateTime));
});
diff --git a/app/assets/javascripts/main.js b/app/assets/javascripts/main.js
index 63c25136f74..88ddd12594e 100644
--- a/app/assets/javascripts/main.js
+++ b/app/assets/javascripts/main.js
@@ -183,7 +183,7 @@ document.addEventListener('DOMContentLoaded', () => {
return true;
});
- localTimeAgo($('abbr.timeago, .js-timeago'), true);
+ localTimeAgo(document.querySelectorAll('abbr.timeago, .js-timeago'), true);
/**
* This disables form buttons while a form is submitting
diff --git a/app/assets/javascripts/members/components/action_buttons/user_action_buttons.vue b/app/assets/javascripts/members/components/action_buttons/user_action_buttons.vue
index 1e9f79927ea..0c20f935d50 100644
--- a/app/assets/javascripts/members/components/action_buttons/user_action_buttons.vue
+++ b/app/assets/javascripts/members/components/action_buttons/user_action_buttons.vue
@@ -38,6 +38,7 @@ export default {
usersName: user.name,
source: source.fullName,
},
+ false,
);
}
diff --git a/app/assets/javascripts/merge_request_tabs.js b/app/assets/javascripts/merge_request_tabs.js
index c3c3aacae35..1d1c0a23fab 100644
--- a/app/assets/javascripts/merge_request_tabs.js
+++ b/app/assets/javascripts/merge_request_tabs.js
@@ -333,8 +333,9 @@ export default class MergeRequestTabs {
axios
.get(`${source}.json`)
.then(({ data }) => {
- document.querySelector('div#commits').innerHTML = data.html;
- localTimeAgo($('.js-timeago', 'div#commits'));
+ const commitsDiv = document.querySelector('div#commits');
+ commitsDiv.innerHTML = data.html;
+ localTimeAgo(commitsDiv.querySelectorAll('.js-timeago'));
this.commitsLoaded = true;
this.scrollToContainerElement('#commits');
@@ -407,7 +408,7 @@ export default class MergeRequestTabs {
initChangesDropdown(this.stickyTop);
- localTimeAgo($('.js-timeago', 'div#diffs'));
+ localTimeAgo(document.querySelectorAll('#diffs .js-timeago'));
syntaxHighlight($('#diffs .js-syntax-highlight'));
if (this.isDiffAction(this.currentAction)) {
diff --git a/app/assets/javascripts/notes.js b/app/assets/javascripts/notes.js
index cd44e8b4987..ef51587734d 100644
--- a/app/assets/javascripts/notes.js
+++ b/app/assets/javascripts/notes.js
@@ -358,7 +358,7 @@ export default class Notes {
setupNewNote($note) {
// Update datetime format on the recent note
- localTimeAgo($note.find('.js-timeago'), false);
+ localTimeAgo($note.find('.js-timeago').get(), false);
this.collapseLongCommitList();
this.taskList.init();
@@ -511,7 +511,7 @@ export default class Notes {
Notes.animateAppendNote(noteEntity.html, discussionContainer);
}
- localTimeAgo($('.js-timeago'), false);
+ localTimeAgo(document.querySelectorAll('.js-timeago'), false);
Notes.checkMergeRequestStatus();
return this.updateNotesCount(1);
}
diff --git a/app/assets/javascripts/pages/admin/users/components/delete_user_modal.vue b/app/assets/javascripts/pages/admin/users/components/delete_user_modal.vue
index a3b78da6ef5..413163c8536 100644
--- a/app/assets/javascripts/pages/admin/users/components/delete_user_modal.vue
+++ b/app/assets/javascripts/pages/admin/users/components/delete_user_modal.vue
@@ -58,7 +58,7 @@ export default {
},
computed: {
modalTitle() {
- return sprintf(this.title, { username: this.username });
+ return sprintf(this.title, { username: this.username }, false);
},
secondaryButtonLabel() {
return s__('AdminUsers|Block user');
@@ -112,7 +112,7 @@ export default {
</gl-sprintf>
</p>
- <oncall-schedules-list v-if="schedules.length" :schedules="schedules" />
+ <oncall-schedules-list v-if="schedules.length" :schedules="schedules" :user-name="username" />
<p>
<gl-sprintf :message="s__('AdminUsers|To confirm, type %{username}')">
diff --git a/app/assets/javascripts/pages/projects/merge_requests/creations/new/compare.js b/app/assets/javascripts/pages/projects/merge_requests/creations/new/compare.js
index 8d152ec4ba6..d61209f904d 100644
--- a/app/assets/javascripts/pages/projects/merge_requests/creations/new/compare.js
+++ b/app/assets/javascripts/pages/projects/merge_requests/creations/new/compare.js
@@ -15,7 +15,7 @@ const updateCommitList = (url, $loadingIndicator, $commitList, params) => {
.then(({ data }) => {
$loadingIndicator.hide();
$commitList.html(data);
- localTimeAgo($('.js-timeago', $commitList));
+ localTimeAgo($commitList.get(0).querySelectorAll('.js-timeago'));
});
};
diff --git a/app/assets/javascripts/pages/users/user_tabs.js b/app/assets/javascripts/pages/users/user_tabs.js
index f9d70845560..90eafa85886 100644
--- a/app/assets/javascripts/pages/users/user_tabs.js
+++ b/app/assets/javascripts/pages/users/user_tabs.js
@@ -166,7 +166,7 @@ export default class UserTabs {
const tabSelector = `div#${action}`;
this.$parentEl.find(tabSelector).html(data.html);
this.loaded[action] = true;
- localTimeAgo($('.js-timeago', tabSelector));
+ localTimeAgo(document.querySelectorAll(`${tabSelector} .js-timeago`));
this.toggleLoading(false);
})
@@ -209,7 +209,7 @@ export default class UserTabs {
container,
url: $(`${container} .overview-content-list`).data('href'),
...options,
- postRenderCallback: () => localTimeAgo($('.js-timeago', container)),
+ postRenderCallback: () => localTimeAgo(document.querySelectorAll(`${container} .js-timeago`)),
});
}
diff --git a/app/assets/javascripts/vue_shared/components/oncall_schedules_list.vue b/app/assets/javascripts/vue_shared/components/oncall_schedules_list.vue
index ff2847624c5..e37a663ace3 100644
--- a/app/assets/javascripts/vue_shared/components/oncall_schedules_list.vue
+++ b/app/assets/javascripts/vue_shared/components/oncall_schedules_list.vue
@@ -27,9 +27,13 @@ export default {
title() {
return this.isCurrentUser
? s__('OnCallSchedules|You are currently a part of:')
- : sprintf(s__('OnCallSchedules|User %{name} is currently part of:'), {
- name: this.userName,
- });
+ : sprintf(
+ s__('OnCallSchedules|User %{name} is currently part of:'),
+ {
+ name: this.userName,
+ },
+ false,
+ );
},
footer() {
return this.isCurrentUser
diff --git a/danger/datateam/Dangerfile b/danger/datateam/Dangerfile
index 0a33cb6777b..e054cddce06 100644
--- a/danger/datateam/Dangerfile
+++ b/danger/datateam/Dangerfile
@@ -1,14 +1,24 @@
# frozen_string_literal: true
# rubocop:disable Style/SignalException
+DATA_WAREHOUSE_LABELS = [
+ "Data Warehouse::Impact Check",
+ "Data Warehouse::Impacted",
+ "Data Warehouse::Not Impacted"
+].freeze
+
CHANGED_SCHEMA_MESSAGE = <<~MSG
-Mentioning @gitlab-data/engineers to notify the team about changes to the db/structure.sql file.
+Notification to the Data Team about changes to the db/structure.sql file, add label `Data Warehouse::Impact Check`.
+
+/label ~"Data Warehouse::Impact Check"
MSG
db_schema_updated = !git.modified_files.grep(%r{\Adb/structure\.sql}).empty?
-if db_schema_updated
+no_data_warehouse_labels = (gitlab.mr_labels & DATA_WAREHOUSE_LABELS).empty?
+
+if db_schema_updated && no_data_warehouse_labels
markdown(CHANGED_SCHEMA_MESSAGE)
diff --git a/doc/.markdownlint/markdownlint-no-trailing-spaces.yml b/doc/.markdownlint/markdownlint-no-trailing-spaces.yml
index 3d107a3e667..71903ae423d 100644
--- a/doc/.markdownlint/markdownlint-no-trailing-spaces.yml
+++ b/doc/.markdownlint/markdownlint-no-trailing-spaces.yml
@@ -1,3 +1,4 @@
+---
# Extended Markdown configuration to enforce no-trailing-spaces rule
"extends": "../../.markdownlint.yml"
"no-trailing-spaces": true
diff --git a/doc/.vale/gitlab/Acronyms.yml b/doc/.vale/gitlab/Acronyms.yml
index 2077cdf9994..bc8f38fe5e2 100644
--- a/doc/.vale/gitlab/Acronyms.yml
+++ b/doc/.vale/gitlab/Acronyms.yml
@@ -120,6 +120,7 @@ exceptions:
- PUT
- RAID
- RAM
+ - RBAC
- RDP
- REST
- RFC
diff --git a/doc/.vale/gitlab/HeaderGerunds.yml b/doc/.vale/gitlab/HeaderGerunds.yml
index c73ed78da34..9e5fa19f867 100644
--- a/doc/.vale/gitlab/HeaderGerunds.yml
+++ b/doc/.vale/gitlab/HeaderGerunds.yml
@@ -1,5 +1,5 @@
---
-# Error: gitlab.HeaderGerunds
+# Suggestion: gitlab.HeaderGerunds
#
# Checks for headers that start with gerunds (ing words).
# Related to: https://docs.gitlab.com/ee/development/documentation/structure.html
diff --git a/doc/administration/auth/authentiq.md b/doc/administration/auth/authentiq.md
index 2eab4555c85..835293ff500 100644
--- a/doc/administration/auth/authentiq.md
+++ b/doc/administration/auth/authentiq.md
@@ -9,7 +9,7 @@ info: To determine the technical writer assigned to the Stage/Group associated w
To enable the Authentiq OmniAuth provider for passwordless authentication you must register an application with Authentiq.
-Authentiq will generate a Client ID and the accompanying Client Secret for you to use.
+Authentiq generates a Client ID and the accompanying Client Secret for you to use.
1. Get your Client credentials (Client ID and Client Secret) at [Authentiq](https://www.authentiq.com/developers).
@@ -67,15 +67,17 @@ Authentiq will generate a Client ID and the accompanying Client Secret for you t
1. [Reconfigure](../restart_gitlab.md#omnibus-gitlab-reconfigure) or [restart GitLab](../restart_gitlab.md#installations-from-source) for the changes to take effect if you installed GitLab via Omnibus or from source respectively.
-On the sign in page there should now be an Authentiq icon below the regular sign in form. Click the icon to begin the authentication process.
+On the sign in page there should now be an Authentiq icon below the regular sign in form. Click the
+icon to begin the authentication process. If the user:
-- If the user has the Authentiq ID app installed in their iOS or Android device, they can:
+- Has the Authentiq ID app installed in their iOS or Android device, they can:
1. Scan the QR code.
1. Decide what personal details to share.
1. Sign in to your GitLab installation.
-- If not they will be prompted to download the app and then follow the procedure above.
+- Does not have the app installed, they are prompted to download the app and then follow the
+ procedure above.
-If everything goes right, the user will be returned to GitLab and will be signed in.
+If everything works, the user is returned to GitLab and is signed in.
<!-- ## Troubleshooting
diff --git a/doc/administration/gitaly/index.md b/doc/administration/gitaly/index.md
index 63b19b1d82f..0af248e0573 100644
--- a/doc/administration/gitaly/index.md
+++ b/doc/administration/gitaly/index.md
@@ -186,7 +186,8 @@ Gitaly Cluster supports:
- [Strong consistency](praefect.md#strong-consistency) of the secondary replicas.
- [Automatic failover](praefect.md#automatic-failover-and-primary-election-strategies) from the primary to the secondary.
- Reporting of possible data loss if replication queue is non-empty.
-- Marking repositories as [read-only](praefect.md#read-only-mode) if data loss is detected to prevent data inconsistencies.
+- From GitLab 13.0 to GitLab 14.0, marking repositories as [read-only](praefect.md#read-only-mode)
+ if data loss is detected to prevent data inconsistencies.
Follow the [Gitaly Cluster epic](https://gitlab.com/groups/gitlab-org/-/epics/1489)
for improvements including
diff --git a/doc/administration/gitaly/praefect.md b/doc/administration/gitaly/praefect.md
index 1d070d601b9..b0ff67c0fdd 100644
--- a/doc/administration/gitaly/praefect.md
+++ b/doc/administration/gitaly/praefect.md
@@ -1239,24 +1239,30 @@ The `per_repository` election strategy solves this problem by electing a primary
repository. Combined with [configurable replication factors](#configure-replication-factor), you can
horizontally scale storage capacity and distribute write load across Gitaly nodes.
-Primary elections are run when:
+Primary elections are run:
-- Praefect starts up.
-- The cluster's consensus of a Gitaly node's health changes.
+- In GitLab 14.1 and later, lazily. This means that Praefect doesn't immediately elect
+ a new primary node if the current one is unhealthy. A new primary is elected if it is
+ necessary to serve a request while the current primary is unavailable.
+- In GitLab 13.12 to GitLab 14.0 when:
+ - Praefect starts up.
+ - The cluster's consensus of a Gitaly node's health changes.
-A Gitaly node is considered:
+A valid primary node candidate is a Gitaly node that:
-- Healthy if `>=50%` Praefect nodes have successfully health checked the Gitaly node in the
- previous ten seconds.
-- Unhealthy otherwise.
+- Is healthy. A Gitaly node is considered healthy if `>=50%` Praefect nodes have
+ successfully health checked the Gitaly node in the previous ten seconds.
+- Has a fully up to date copy of the repository.
-During an election run, Praefect elects a new primary Gitaly node for each repository that has
-an unhealthy primary Gitaly node. The election is made:
+If there are multiple primary node candidates, Praefect:
-- Randomly from healthy secondary Gitaly nodes that are the most up to date.
-- Only from Gitaly nodes assigned to the host repository.
+- Picks one of them randomly.
+- Prioritizes promoting a Gitaly node that is assigned to host the repository. If
+ there are no assigned Gitaly nodes to elect as the primary, Praefect may temporarily
+ elect an unassigned one. The unassigned primary is demoted in favor of an assigned
+ one when one becomes available.
-If there are no healthy secondary nodes for a repository:
+If there are no valid primary candidates for a repository:
- The unhealthy primary node is demoted and the repository is left without a primary node.
- Operations that require a primary node fail until a primary is successfully elected.
@@ -1351,23 +1357,37 @@ Migrate to [repository-specific primary nodes](#repository-specific-primary-node
Gitaly Cluster recovers from a failing primary Gitaly node by promoting a healthy secondary as the
new primary.
-To minimize data loss, Gitaly Cluster:
+In GitLab 14.1 and later, Gitaly Cluster:
+
+- Elects a healthy secondary with a fully up to date copy of the repository as the new primary.
+- Repository becomes unavailable if there are no fully up to date copies of it on healthy secondaries.
+
+To minimize data loss in GitLab 13.0 to 14.0, Gitaly Cluster:
- Switches repositories that are outdated on the new primary to [read-only mode](#read-only-mode).
-- Elects the secondary with the least unreplicated writes from the primary to be the new primary.
- Because there can still be some unreplicated writes, [data loss can occur](#check-for-data-loss).
+- Elects the secondary with the least unreplicated writes from the primary to be the new
+ primary. Because there can still be some unreplicated writes,
+ [data loss can occur](#check-for-data-loss).
### Read-only mode
> - Introduced in GitLab 13.0 as [generally available](https://about.gitlab.com/handbook/product/gitlab-the-product/#generally-available-ga).
> - Between GitLab 13.0 and GitLab 13.2, read-only mode applied to the whole virtual storage and occurred whenever failover occurred.
> - [In GitLab 13.3 and later](https://gitlab.com/gitlab-org/gitaly/-/issues/2862), read-only mode applies on a per-repository basis and only occurs if a new primary is out of date.
+new primary. If the failed primary contained unreplicated writes, [data loss can occur](#check-for-data-loss).
+> - Removed in GitLab 14.1. Instead, repositories [become unavailable](#unavailable-repositories).
-When Gitaly Cluster switches to a new primary, repositories enter read-only mode if they are out of
-date. This can happen after failing over to an outdated secondary. Read-only mode eases data
-recovery efforts by preventing writes that may conflict with the unreplicated writes on other nodes.
+In GitLab 13.0 to 14.0, when Gitaly Cluster switches to a new primary, repositories enter
+read-only mode if they are out of date. This can happen after failing over to an outdated
+secondary. Read-only mode eases data recovery efforts by preventing writes that may conflict
+with the unreplicated writes on other nodes.
-To enable writes again, an administrator can:
+When Gitaly Cluster switches to a new primary In GitLab 13.0 to 14.0, repositories enter
+read-only mode if they are out of date. This can happen after failing over to an outdated
+secondary. Read-only mode eases data recovery efforts by preventing writes that may conflict
+with the unreplicated writes on other nodes.
+
+To enable writes again in GitLab 13.0 to 14.0, an administrator can:
1. [Check](#check-for-data-loss) for data loss.
1. Attempt to [recover](#data-recovery) missing data.
@@ -1375,21 +1395,38 @@ To enable writes again, an administrator can:
[accept data loss](#enable-writes-or-accept-data-loss) if necessary, depending on the version of
GitLab.
+## Unavailable repositories
+
+> - From GitLab 13.0 through 14.0, repositories became read-only if they were outdated on the primary but fully up to date on a healthy secondary. `dataloss` sub-command displays read-only repositories by default through these versions.
+> - Since GitLab 14.1, Praefect contains more responsive failover logic which immediately fails over to one of the fully up to date secondaries rather than placing the repository in read-only mode. Since GitLab 14.1, the `dataloss` sub-command displays repositories which are unavailable due to having no fully up to date copies on healthy Gitaly nodes.
+
+A repository is unavailable if all of its up to date replicas are unavailable. Unavailable repositories are
+not accessible through Praefect to prevent serving stale data that may break automated tooling.
+
### Check for data loss
-The Praefect `dataloss` sub-command identifies replicas that are likely to be outdated. This can help
-identify potential data loss after a failover. The following parameters are
-available:
+The Praefect `dataloss` subcommand identifies:
+
+- Copies of repositories in GitLab 13.0 to GitLab 14.0 that at are likely to be outdated.
+ This can help identify potential data loss after a failover.
+- Repositories in GitLab 14.1 and later that are unavailable. This helps identify potential
+ data loss and repositories which are no longer accessible because all of their up-to-date
+ replicas copies are unavailable.
+
+The following parameters are available:
-- `-virtual-storage` that specifies which virtual storage to check. The default behavior is to
- display outdated replicas of read-only repositories as they might require administrator action.
-- In GitLab 13.3 and later, `-partially-replicated` that specifies whether to display a list of
- [outdated replicas of writable repositories](#outdated-replicas-of-writable-repositories).
+- `-virtual-storage` that specifies which virtual storage to check. Because they might require
+ an administrator to intervene, the default behavior is to display:
+ - In GitLab 13.0 to 14.0, copies of read-only repositories.
+ - In GitLab 14.1 and later, unavailable repositories.
+- In GitLab 14.1 and later, [`-partially-unavailable`](#unavailable-replicas-of-available-repositories)
+ that specifies whether to include in the output repositories that are available but have
+ some assigned copies that are not available.
NOTE:
`dataloss` is still in beta and the output format is subject to change.
-To check for repositories with outdated primaries, run:
+To check for repositories with outdated primaries or for unavailable repositories, run:
```shell
sudo /opt/gitlab/embedded/bin/praefect -config /var/opt/gitlab/praefect/config.toml dataloss [-virtual-storage <virtual-storage>]
@@ -1401,13 +1438,20 @@ Every configured virtual storage is checked if none is specified:
sudo /opt/gitlab/embedded/bin/praefect -config /var/opt/gitlab/praefect/config.toml dataloss
```
-Repositories which have assigned storage nodes that contain an outdated copy of the repository are listed
-in the output. This information is printed for each repository:
+Repositories are listed in the output that have either:
+
+- An outdated copy of the repository on the primary, in GitLab 13.0 to GitLab 14.0.
+- No healthy and fully up-to-date copies available, in GitLab 14.1 and later.
+
+The following information is printed for each repository:
- A repository's relative path to the storage directory identifies each repository and groups the related
information.
-- The repository's current status is printed in parentheses next to the disk path. If the repository's primary
- is outdated, the repository is in `read-only` mode and can't accept writes. Otherwise, the mode is `writable`.
+- The repository's current status is printed in parentheses next to the disk path:
+ - In GitLab 13.0 to 14.0, either `(read-only)` if the repository's primary node is outdated
+ and can't accept writes. Otherwise, `(writable)`.
+ - In GitLab 14.1 and later, `(unavailable)` is printed next to the disk path if the
+ repository is unavailable.
- The primary field lists the repository's current primary. If the repository has no primary, the field shows
`No Primary`.
- The In-Sync Storages lists replicas which have replicated the latest successful write and all writes
@@ -1417,44 +1461,51 @@ in the output. This information is printed for each repository:
is listed next to replica. It's important to notice that the outdated replicas may be fully up to date or contain
later changes but Praefect can't guarantee it.
-Whether a replica is assigned to host the repository is listed with each replica's status. `assigned host` is printed
-next to replicas which are assigned to store the repository. The text is omitted if the replica contains a copy of
-the repository but is not assigned to store the repository. Such replicas aren't kept in-sync by Praefect, but may
-act as replication sources to bring assigned replicas up to date.
+Additional information includes:
+
+- Whether a node is assigned to host the repository is listed with each node's status.
+ `assigned host` is printed next to nodes that are assigned to store the repository. The
+ text is omitted if the node contains a copy of the repository but is not assigned to store
+ the repository. Such copies aren't kept in sync by Praefect, but may act as replication
+ sources to bring assigned copies up to date.
+- In GitLab 14.1 and later, `unhealthy` is printed next to the copies that are located
+ on unhealthy Gitaly nodes.
Example output:
```shell
Virtual storage: default
Outdated repositories:
- @hashed/3f/db/3fdba35f04dc8c462986c992bcf875546257113072a909c162f7e470e581e278.git (read-only):
+ @hashed/3f/db/3fdba35f04dc8c462986c992bcf875546257113072a909c162f7e470e581e278.git (unavailable):
Primary: gitaly-1
In-Sync Storages:
- gitaly-2, assigned host
+ gitaly-2, assigned host, unhealthy
Outdated Storages:
gitaly-1 is behind by 3 changes or less, assigned host
gitaly-3 is behind by 3 changes or less
```
-A confirmation is printed out when every repository is writable. For example:
+A confirmation is printed out when every repository is available. For example:
```shell
Virtual storage: default
- All repositories are writable!
+ All repositories are available!
```
-#### Outdated replicas of writable repositories
+#### Unavailable replicas of available repositories
-> [Introduced](https://gitlab.com/gitlab-org/gitaly/-/issues/3019) in GitLab 13.3.
+NOTE:
+In GitLab 14.0 and earlier, the flag is `-partially-replicated` and the output shows any repositories with assigned nodes with outdated
+copies.
-To also list information of repositories whose primary is up to date but one or more assigned
-replicas are outdated, use the `-partially-replicated` flag.
+To also list information of repositories which are available but are unavailable from some of the assigned nodes,
+use the `-partially-unavailable` flag.
-A repository is writable if the primary has the latest changes. Secondaries might be temporarily
-outdated while they are waiting to replicate the latest changes.
+A repository is available if there is a healthy, up to date replica available. Some of the assigned secondary
+replicas may be temporarily unavailable for access while they are waiting to replicate the latest changes.
```shell
-sudo /opt/gitlab/embedded/bin/praefect -config /var/opt/gitlab/praefect/config.toml dataloss [-virtual-storage <virtual-storage>] [-partially-replicated]
+sudo /opt/gitlab/embedded/bin/praefect -config /var/opt/gitlab/praefect/config.toml dataloss [-virtual-storage <virtual-storage>] [-partially-unavailable]
```
Example output:
@@ -1462,7 +1513,7 @@ Example output:
```shell
Virtual storage: default
Outdated repositories:
- @hashed/3f/db/3fdba35f04dc8c462986c992bcf875546257113072a909c162f7e470e581e278.git (writable):
+ @hashed/3f/db/3fdba35f04dc8c462986c992bcf875546257113072a909c162f7e470e581e278.git:
Primary: gitaly-1
In-Sync Storages:
gitaly-1, assigned host
@@ -1471,14 +1522,14 @@ Virtual storage: default
gitaly-3 is behind by 3 changes or less
```
-With the `-partially-replicated` flag set, a confirmation is printed out if every assigned replica is fully up to
-date.
+With the `-partially-unavailable` flag set, a confirmation is printed out if every assigned replica is fully up to
+date and healthy.
For example:
```shell
Virtual storage: default
- All repositories are up to date!
+ All repositories are fully available on all assigned storages!
```
### Check repository checksums
@@ -1486,30 +1537,50 @@ Virtual storage: default
To check a project's repository checksums across on all Gitaly nodes, run the
[replicas Rake task](../raketasks/praefect.md#replica-checksums) on the main GitLab node.
+### Accept data loss
+
+WARNING:
+`accept-dataloss` causes permanent data loss by overwriting other versions of the repository. Data
+[recovery efforts](#data-recovery) must be performed before using it.
+
+If it is not possible to bring one of the up to date replicas back online, you may have to accept data
+loss. When accepting data loss, Praefect marks the chosen replica of the repository as the latest version
+and replicates it to the other assigned Gitaly nodes. This process overwrites any other version of the
+repository so care must be taken.
+
+```shell
+sudo /opt/gitlab/embedded/bin/praefect -config /var/opt/gitlab/praefect/config.toml accept-dataloss
+-virtual-storage <virtual-storage> -repository <relative-path> -authoritative-storage <storage-name>
+```
+
### Enable writes or accept data loss
-Praefect provides the following sub-commands to re-enable writes:
+WARNING:
+`accept-dataloss` causes permanent data loss by overwriting other versions of the repository.
+Data [recovery efforts](#data-recovery) must be performed before using it.
-- In GitLab 13.2 and earlier, `enable-writes` to re-enable virtual storage for writes after data
- recovery attempts.
+Praefect provides the following subcommands to re-enable writes or accept data loss:
- ```shell
- sudo /opt/gitlab/embedded/bin/praefect -config /var/opt/gitlab/praefect/config.toml enable-writes -virtual-storage <virtual-storage>
- ```
+- In GitLab 13.2 and earlier, `enable-writes` to re-enable virtual storage for writes after
+ data recovery attempts:
-- [In GitLab 13.3](https://gitlab.com/gitlab-org/gitaly/-/merge_requests/2415) and later,
- `accept-dataloss` to accept data loss and re-enable writes for repositories after data recovery
- attempts have failed. Accepting data loss causes current version of the repository on the
- authoritative storage to be considered latest. Other storages are brought up to date with the
- authoritative storage by scheduling replication jobs.
+ ```shell
+ sudo /opt/gitlab/embedded/bin/praefect -config /var/opt/gitlab/praefect/config.toml enable-writes -virtual-storage <virtual-storage>
+ ```
+
+- In GitLab 13.3 and later, if it is not possible to bring one of the up to date nodes back
+ online, you may have to accept data loss:
```shell
sudo /opt/gitlab/embedded/bin/praefect -config /var/opt/gitlab/praefect/config.toml accept-dataloss -virtual-storage <virtual-storage> -repository <relative-path> -authoritative-storage <storage-name>
```
-WARNING:
-`accept-dataloss` causes permanent data loss by overwriting other versions of the repository. Data
-[recovery efforts](#data-recovery) must be performed before using it.
+ When accepting data loss, Praefect:
+
+ 1. Marks the chosen copy of the repository as the latest version.
+ 1. Replicates the copy to the other assigned Gitaly nodes.
+
+ This process overwrites any other copy of the repository so care must be taken.
## Data recovery
diff --git a/generator_templates/usage_metric_definition/metric_definition.yml b/generator_templates/usage_metric_definition/metric_definition.yml
index 53ff84fc4ab..209ff628eb5 100644
--- a/generator_templates/usage_metric_definition/metric_definition.yml
+++ b/generator_templates/usage_metric_definition/metric_definition.yml
@@ -11,7 +11,7 @@ milestone: "<%= milestone %>"
introduced_by_url:
time_frame: <%= time_frame %>
data_source:
-data_category: Operational
+data_category: Optional
distribution:
<%= distribution %>
tier:
diff --git a/qa/qa/specs/features/browser_ui/2_plan/issue/create_issue_spec.rb b/qa/qa/specs/features/browser_ui/2_plan/issue/create_issue_spec.rb
index b7cda94f289..64645ed16cd 100644
--- a/qa/qa/specs/features/browser_ui/2_plan/issue/create_issue_spec.rb
+++ b/qa/qa/specs/features/browser_ui/2_plan/issue/create_issue_spec.rb
@@ -48,7 +48,10 @@ module QA
Resource::Issue.fabricate_via_api!.visit!
end
- it 'comments on an issue with an attachment', testcase: 'https://gitlab.com/gitlab-org/quality/testcases/-/issues/1742' do
+ # The following example is excluded from running in `review-qa-smoke` job
+ # as it proved to be flaky when running against Review App
+ # See https://gitlab.com/gitlab-com/www-gitlab-com/-/issues/11568#note_621999351
+ it 'comments on an issue with an attachment', testcase: 'https://gitlab.com/gitlab-org/quality/testcases/-/issues/1742', exclude: { job: 'review-qa-smoke' } do
Page::Project::Issue::Show.perform do |show|
show.comment('See attached image for scale', attachment: file_to_attach)
diff --git a/spec/features/dashboard/issues_filter_spec.rb b/spec/features/dashboard/issues_filter_spec.rb
index 4bd00bd0a80..4d59e1ded3d 100644
--- a/spec/features/dashboard/issues_filter_spec.rb
+++ b/spec/features/dashboard/issues_filter_spec.rb
@@ -81,14 +81,14 @@ RSpec.describe 'Dashboard Issues filtering', :js do
sort_by('Created date')
visit_issues(assignee_username: user.username)
- expect(find('.issues-filters')).to have_content('Created date')
+ expect(page).to have_button('Created date')
end
it 'keeps sorting issues after visiting Projects Issues page' do
sort_by('Created date')
visit project_issues_path(project)
- expect(find('.issues-filters')).to have_content('Created date')
+ expect(page).to have_button('Created date')
end
end
diff --git a/spec/features/issues/user_sorts_issues_spec.rb b/spec/features/issues/user_sorts_issues_spec.rb
index c161e1deb83..48297e9049e 100644
--- a/spec/features/issues/user_sorts_issues_spec.rb
+++ b/spec/features/issues/user_sorts_issues_spec.rb
@@ -22,11 +22,11 @@ RSpec.describe "User sorts issues" do
create(:award_emoji, :upvote, awardable: issue2)
sign_in(user)
-
- visit(project_issues_path(project))
end
it 'keeps the sort option' do
+ visit(project_issues_path(project))
+
find('.filter-dropdown-container .dropdown').click
page.within('ul.dropdown-menu.dropdown-menu-right li') do
@@ -47,11 +47,10 @@ RSpec.describe "User sorts issues" do
end
it 'sorts by popularity', :js do
- find('.filter-dropdown-container .dropdown').click
+ visit(project_issues_path(project))
- page.within('ul.dropdown-menu.dropdown-menu-right li') do
- click_link("Popularity")
- end
+ click_button 'Created date'
+ click_on 'Popularity'
page.within(".issues-list") do
page.within("li.issue:nth-child(1)") do
@@ -129,7 +128,7 @@ RSpec.describe "User sorts issues" do
it 'filters by none' do
visit project_issues_path(project, due_date: Issue::NoDueDate.name)
- page.within '.issues-holder' do
+ page.within '.issues-list' do
expect(page).not_to have_content('foo')
expect(page).not_to have_content('bar')
expect(page).to have_content('baz')
@@ -139,7 +138,7 @@ RSpec.describe "User sorts issues" do
it 'filters by any' do
visit project_issues_path(project, due_date: Issue::AnyDueDate.name)
- page.within '.issues-holder' do
+ page.within '.issues-list' do
expect(page).to have_content('foo')
expect(page).to have_content('bar')
expect(page).to have_content('baz')
@@ -153,7 +152,7 @@ RSpec.describe "User sorts issues" do
visit project_issues_path(project, due_date: Issue::DueThisWeek.name)
- page.within '.issues-holder' do
+ page.within '.issues-list' do
expect(page).to have_content('foo')
expect(page).to have_content('bar')
expect(page).not_to have_content('baz')
@@ -167,7 +166,7 @@ RSpec.describe "User sorts issues" do
visit project_issues_path(project, due_date: Issue::DueThisMonth.name)
- page.within '.issues-holder' do
+ page.within '.issues-list' do
expect(page).to have_content('foo')
expect(page).to have_content('bar')
expect(page).not_to have_content('baz')
@@ -181,7 +180,7 @@ RSpec.describe "User sorts issues" do
visit project_issues_path(project, due_date: Issue::Overdue.name)
- page.within '.issues-holder' do
+ page.within '.issues-list' do
expect(page).not_to have_content('foo')
expect(page).not_to have_content('bar')
expect(page).to have_content('baz')
@@ -195,7 +194,7 @@ RSpec.describe "User sorts issues" do
visit project_issues_path(project, due_date: Issue::DueNextMonthAndPreviousTwoWeeks.name)
- page.within '.issues-holder' do
+ page.within '.issues-list' do
expect(page).not_to have_content('foo')
expect(page).not_to have_content('bar')
expect(page).to have_content('baz')
diff --git a/spec/features/merge_requests/user_sorts_merge_requests_spec.rb b/spec/features/merge_requests/user_sorts_merge_requests_spec.rb
index 54c9fbef218..99473f3b1ea 100644
--- a/spec/features/merge_requests/user_sorts_merge_requests_spec.rb
+++ b/spec/features/merge_requests/user_sorts_merge_requests_spec.rb
@@ -60,7 +60,7 @@ RSpec.describe 'User sorts merge requests' do
visit(project_issues_path(project))
- expect(find('.issues-filters a.is-active')).not_to have_content('Milestone')
+ expect(page).not_to have_button('Milestone')
end
context 'when merge requests have awards' do
diff --git a/spec/frontend/lib/utils/datetime/timeago_utility_spec.js b/spec/frontend/lib/utils/datetime/timeago_utility_spec.js
index 5cffe3ef2b0..2314ec678d3 100644
--- a/spec/frontend/lib/utils/datetime/timeago_utility_spec.js
+++ b/spec/frontend/lib/utils/datetime/timeago_utility_spec.js
@@ -1,4 +1,3 @@
-import $ from 'jquery';
import { getTimeago, localTimeAgo, timeFor } from '~/lib/utils/datetime/timeago_utility';
import { s__ } from '~/locale';
import '~/commons/bootstrap';
@@ -81,16 +80,16 @@ describe('TimeAgo utils', () => {
`With User Setting timeDisplayRelative: $timeDisplayRelative`,
({ timeDisplayRelative, text }) => {
it.each`
- timeagoArg | title
- ${false} | ${'some time'}
- ${true} | ${'Feb 18, 2020 10:22pm UTC'}
+ updateTooltip | title
+ ${false} | ${'some time'}
+ ${true} | ${'Feb 18, 2020 10:22pm UTC'}
`(
- `has content: '${text}' and tooltip: '$title' with timeagoArg = $timeagoArg`,
- ({ timeagoArg, title }) => {
+ `has content: '${text}' and tooltip: '$title' with updateTooltip = $updateTooltip`,
+ ({ updateTooltip, title }) => {
window.gon = { time_display_relative: timeDisplayRelative };
const element = document.querySelector('time');
- localTimeAgo($(element), timeagoArg);
+ localTimeAgo([element], updateTooltip);
jest.runAllTimers();
diff --git a/spec/frontend/pages/admin/users/components/__snapshots__/delete_user_modal_spec.js.snap b/spec/frontend/pages/admin/users/components/__snapshots__/delete_user_modal_spec.js.snap
index 4c644a0d05f..5e367891337 100644
--- a/spec/frontend/pages/admin/users/components/__snapshots__/delete_user_modal_spec.js.snap
+++ b/spec/frontend/pages/admin/users/components/__snapshots__/delete_user_modal_spec.js.snap
@@ -10,6 +10,7 @@ exports[`User Operation confirmation modal renders modal with form included 1`]
<oncall-schedules-list-stub
schedules="schedule1,schedule2"
+ username="username"
/>
<p>
diff --git a/spec/frontend/vue_shared/oncall_schedules_list_spec.js b/spec/frontend/vue_shared/oncall_schedules_list_spec.js
index 5c30809c09b..f83a5187b8b 100644
--- a/spec/frontend/vue_shared/oncall_schedules_list_spec.js
+++ b/spec/frontend/vue_shared/oncall_schedules_list_spec.js
@@ -18,7 +18,7 @@ const mockSchedules = [
},
];
-const userName = 'User 1';
+const userName = "O'User";
describe('On-call schedules list', () => {
let wrapper;
diff --git a/spec/support/matchers/have_issuable_counts.rb b/spec/support/matchers/have_issuable_counts.rb
index 049cfc022fb..586ba0651dc 100644
--- a/spec/support/matchers/have_issuable_counts.rb
+++ b/spec/support/matchers/have_issuable_counts.rb
@@ -6,7 +6,7 @@ RSpec::Matchers.define :have_issuable_counts do |opts|
end
match do |actual|
- actual.within '.issues-state-filters' do
+ actual.within '.top-area' do
expected_counts.each do |expected_count|
expect(actual).to have_content(expected_count)
end