summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2020-01-24 10:12:46 +0000
committerGitLab Bot <gitlab-bot@gitlab.com>2020-01-24 10:12:46 +0000
commit85e95876ecf827253256c841df80a53843b84f7f (patch)
tree7759343984204444409dcfb5ac8b72c493c5d7b5
parent680a5284470c6e5c430cd077b797504acd1f26d7 (diff)
downloadgitlab-ce-85e95876ecf827253256c841df80a53843b84f7f.tar.gz
Add latest changes from gitlab-org/gitlab@12-7-stable-ee
-rw-r--r--CHANGELOG.md1
-rw-r--r--VERSION2
-rw-r--r--app/assets/javascripts/diffs/components/app.vue2
-rw-r--r--app/assets/javascripts/diffs/components/compare_versions.vue12
-rw-r--r--app/assets/javascripts/diffs/components/diff_file_header.vue16
-rw-r--r--app/assets/javascripts/diffs/components/diff_stats.vue23
-rw-r--r--app/assets/javascripts/diffs/components/tree_list.vue9
-rw-r--r--app/assets/javascripts/vue_shared/components/changed_file_icon.vue11
-rw-r--r--app/assets/javascripts/vue_shared/components/file_row.vue11
-rw-r--r--app/assets/stylesheets/pages/diff.scss15
-rw-r--r--app/assets/stylesheets/pages/merge_requests.scss4
-rw-r--r--app/models/user.rb5
-rw-r--r--app/policies/project_policy.rb1
-rw-r--r--app/services/error_tracking/base_service.rb8
-rw-r--r--app/services/error_tracking/issue_details_service.rb2
-rw-r--r--app/services/error_tracking/issue_latest_event_service.rb2
-rw-r--r--app/services/error_tracking/issue_update_service.rb58
-rw-r--r--app/services/error_tracking/list_issues_service.rb2
-rw-r--r--app/services/error_tracking/list_projects_service.rb2
-rw-r--r--app/services/pages_domains/create_acme_order_service.rb5
-rw-r--r--app/services/system_note_service.rb6
-rw-r--r--app/services/users/build_service.rb2
-rw-r--r--changelogs/unreleased/197925-setting-minimum-password-length-breaks-sign-up-with-saml.yml5
-rw-r--r--changelogs/unreleased/198030-fix-wrong-data.yml5
-rw-r--r--changelogs/unreleased/198289-unable-to-sign-out-from-secondary-geo-node.yml5
-rw-r--r--changelogs/unreleased/39825-close-issue-after-error-resolve.yml5
-rw-r--r--changelogs/unreleased/jprovazn-fix-group-preloader.yml5
-rw-r--r--changelogs/unreleased/revert-22364.yml6
-rw-r--r--changelogs/unreleased/sh-add-missing-backtrace-define.yml5
-rw-r--r--db/post_migrate/20200123155929_remove_invalid_jira_data.rb25
-rw-r--r--db/schema.rb2
-rw-r--r--doc/administration/logs.md39
-rw-r--r--doc/api/keys.md10
-rw-r--r--doc/api/merge_request_approvals.md110
-rw-r--r--doc/api/protected_branches.md7
-rw-r--r--doc/user/analytics/code_review_analytics.md42
-rw-r--r--doc/user/analytics/cycle_analytics.md9
-rw-r--r--doc/user/analytics/index.md6
-rw-r--r--doc/user/application_security/dependency_scanning/index.md2
-rw-r--r--doc/user/clusters/applications.md59
-rw-r--r--doc/user/img/markdown_copy_from_spreadsheet_v12_7.pngbin0 -> 371532 bytes
-rw-r--r--doc/user/img/markdown_paste_table_v12_7.pngbin0 -> 153855 bytes
-rw-r--r--doc/user/instance_statistics/convdev.md5
-rw-r--r--doc/user/instance_statistics/dev_ops_score.md1
-rw-r--r--doc/user/markdown.md16
-rw-r--r--doc/user/packages/conan_repository/index.md2
-rw-r--r--doc/user/project/integrations/prometheus.md19
-rw-r--r--doc/user/project/issues/design_management.md4
-rw-r--r--doc/user/project/operations/error_tracking.md9
-rw-r--r--doc/user/project/repository/git_blame.md8
-rw-r--r--doc/user/project/service_desk.md2
-rw-r--r--lib/gitlab/auth/o_auth/auth_hash.rb2
-rw-r--r--lib/gitlab/bitbucket_server_import/importer.rb1
-rw-r--r--lib/gitlab/middleware/read_only/controller.rb13
-rw-r--r--locale/gitlab.pot32
-rw-r--r--spec/controllers/projects/error_tracking_controller_spec.rb2
-rw-r--r--spec/features/merge_request/user_sees_versions_spec.rb26
-rw-r--r--spec/features/users/logout_spec.rb12
-rw-r--r--spec/fixtures/api/schemas/error_tracking/update_issue.json8
-rw-r--r--spec/frontend/diffs/components/compare_versions_spec.js3
-rw-r--r--spec/frontend/diffs/components/diff_stats_spec.js18
-rw-r--r--spec/frontend/vue_shared/components/changed_file_icon_spec.js6
-rw-r--r--spec/javascripts/ide/components/repo_tab_spec.js4
-rw-r--r--spec/lib/gitlab/auth/ldap/user_spec.rb12
-rw-r--r--spec/lib/gitlab/auth/o_auth/user_spec.rb14
-rw-r--r--spec/lib/gitlab/auth/saml/user_spec.rb12
-rw-r--r--spec/lib/gitlab/bitbucket_server_import/importer_spec.rb8
-rw-r--r--spec/migrations/20200123155929_remove_invalid_jira_data_spec.rb70
-rw-r--r--spec/models/user_spec.rb14
-rw-r--r--spec/services/error_tracking/issue_details_service_spec.rb19
-rw-r--r--spec/services/error_tracking/issue_latest_event_service_spec.rb19
-rw-r--r--spec/services/error_tracking/issue_update_service_spec.rb106
-rw-r--r--spec/services/error_tracking/list_issues_service_spec.rb18
-rw-r--r--spec/services/pages_domains/create_acme_order_service_spec.rb26
-rw-r--r--spec/support/shared_contexts/sentry_error_tracking_shared_context.rb22
75 files changed, 831 insertions, 248 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 02d6b8c8038..a70dc4b79a1 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -4,7 +4,6 @@ entry.
## 12.7.0
-- No changes.
### Security (6 changes, 2 of them are from the community)
- Ensure content matches extension on image uploads. !20697
diff --git a/VERSION b/VERSION
index e12d94fbf3a..13a10acf71c 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-12.7.0
+12.7.0-ee
diff --git a/app/assets/javascripts/diffs/components/app.vue b/app/assets/javascripts/diffs/components/app.vue
index 878b54f7d53..463d1427805 100644
--- a/app/assets/javascripts/diffs/components/app.vue
+++ b/app/assets/javascripts/diffs/components/app.vue
@@ -374,7 +374,7 @@ export default {
<div
:data-can-create-note="getNoteableData.current_user.can_create_note"
- class="files d-flex"
+ class="files d-flex prepend-top-default"
>
<div
v-show="showTreeList"
diff --git a/app/assets/javascripts/diffs/components/compare_versions.vue b/app/assets/javascripts/diffs/components/compare_versions.vue
index 63ce43a193d..24542126b07 100644
--- a/app/assets/javascripts/diffs/components/compare_versions.vue
+++ b/app/assets/javascripts/diffs/components/compare_versions.vue
@@ -1,4 +1,5 @@
<script>
+/* eslint-disable @gitlab/vue-i18n/no-bare-strings */
import { mapActions, mapGetters, mapState } from 'vuex';
import { GlTooltipDirective, GlLink, GlButton } from '@gitlab/ui';
import { __ } from '~/locale';
@@ -62,6 +63,9 @@ export default {
showDropdowns() {
return !this.commit && this.mergeRequestDiffs.length;
},
+ fileTreeIcon() {
+ return this.showTreeList ? 'collapse-left' : 'expand-left';
+ },
toggleFileBrowserTitle() {
return this.showTreeList ? __('Hide file browser') : __('Show file browser');
},
@@ -87,7 +91,7 @@ export default {
</script>
<template>
- <div class="mr-version-controls border-top">
+ <div class="mr-version-controls border-top border-bottom">
<div
class="mr-version-menus-container content-block"
:class="{
@@ -104,17 +108,17 @@ export default {
:title="toggleFileBrowserTitle"
@click="toggleShowTreeList"
>
- <icon name="file-tree" />
+ <icon :name="fileTreeIcon" />
</button>
<div v-if="showDropdowns" class="d-flex align-items-center compare-versions-container">
- {{ __('Compare') }}
+ Changes between
<compare-versions-dropdown
:other-versions="mergeRequestDiffs"
:merge-request-version="mergeRequestDiff"
:show-commit-count="true"
class="mr-version-dropdown"
/>
- {{ __('and') }}
+ and
<compare-versions-dropdown
:other-versions="comparableDiffs"
:base-version-path="baseVersionPath"
diff --git a/app/assets/javascripts/diffs/components/diff_file_header.vue b/app/assets/javascripts/diffs/components/diff_file_header.vue
index e78bea789c3..5d27c6eb865 100644
--- a/app/assets/javascripts/diffs/components/diff_file_header.vue
+++ b/app/assets/javascripts/diffs/components/diff_file_header.vue
@@ -123,20 +123,6 @@ export default {
}
return s__('MRDiff|Show full file');
},
- changedFile() {
- const {
- new_path: changed,
- deleted_file: deleted,
- new_file: tempFile,
- ...diffFile
- } = this.diffFile;
- return {
- ...diffFile,
- changed: Boolean(changed),
- deleted,
- tempFile,
- };
- },
},
mounted() {
polyfillSticky(this.$refs.header);
@@ -235,7 +221,7 @@ export default {
<div
v-if="!diffFile.submodule && addMergeRequestButtons"
- class="file-actions d-none d-sm-flex align-items-center"
+ class="file-actions d-none d-sm-block"
>
<diff-stats :added-lines="diffFile.added_lines" :removed-lines="diffFile.removed_lines" />
<div class="btn-group" role="group">
diff --git a/app/assets/javascripts/diffs/components/diff_stats.vue b/app/assets/javascripts/diffs/components/diff_stats.vue
index 1fa1fda7bd7..2e5855380af 100644
--- a/app/assets/javascripts/diffs/components/diff_stats.vue
+++ b/app/assets/javascripts/diffs/components/diff_stats.vue
@@ -1,7 +1,9 @@
<script>
+import Icon from '~/vue_shared/components/icon.vue';
import { n__ } from '~/locale';
export default {
+ components: { Icon },
props: {
addedLines: {
type: Number,
@@ -19,7 +21,7 @@ export default {
},
computed: {
filesText() {
- return n__('file', 'files', this.diffFilesLength);
+ return n__('File', 'Files', this.diffFilesLength);
},
isCompareVersionsHeader() {
return Boolean(this.diffFilesLength);
@@ -37,21 +39,14 @@ export default {
}"
>
<div v-if="diffFilesLength !== null" class="diff-stats-group">
- <span class="text-secondary bold">{{ diffFilesLength }} {{ filesText }}</span>
+ <icon name="doc-code" class="diff-stats-icon text-secondary" />
+ <strong>{{ diffFilesLength }} {{ filesText }}</strong>
</div>
- <div
- class="diff-stats-group cgreen d-flex align-items-center"
- :class="{ bold: isCompareVersionsHeader }"
- >
- <span>+</span>
- <span class="js-file-addition-line">{{ addedLines }}</span>
+ <div class="diff-stats-group cgreen">
+ <icon name="file-addition" class="diff-stats-icon" /> <strong>{{ addedLines }}</strong>
</div>
- <div
- class="diff-stats-group cred d-flex align-items-center"
- :class="{ bold: isCompareVersionsHeader }"
- >
- <span>-</span>
- <span class="js-file-deletion-line">{{ removedLines }}</span>
+ <div class="diff-stats-group cred">
+ <icon name="file-deletion" class="diff-stats-icon" /> <strong>{{ removedLines }}</strong>
</div>
</div>
</template>
diff --git a/app/assets/javascripts/diffs/components/tree_list.vue b/app/assets/javascripts/diffs/components/tree_list.vue
index 7956d05b4f1..30be2e68e76 100644
--- a/app/assets/javascripts/diffs/components/tree_list.vue
+++ b/app/assets/javascripts/diffs/components/tree_list.vue
@@ -4,6 +4,7 @@ import { GlTooltipDirective } from '@gitlab/ui';
import { s__, sprintf } from '~/locale';
import Icon from '~/vue_shared/components/icon.vue';
import FileRow from '~/vue_shared/components/file_row.vue';
+import FileRowStats from './file_row_stats.vue';
export default {
directives: {
@@ -47,6 +48,9 @@ export default {
return acc;
}, []);
},
+ fileRowExtraComponent() {
+ return this.hideFileStats ? null : FileRowStats;
+ },
},
methods: {
...mapActions('diffs', ['toggleTreeOpen', 'scrollToFile']),
@@ -54,8 +58,8 @@ export default {
this.search = '';
},
},
- searchPlaceholder: sprintf(s__('MergeRequest|Search files (%{modifier_key}P)'), {
- modifier_key: /Mac/i.test(navigator.userAgent) ? '⌘' : 'Ctrl+',
+ searchPlaceholder: sprintf(s__('MergeRequest|Filter files or search with %{modifier_key}+p'), {
+ modifier_key: /Mac/i.test(navigator.userAgent) ? 'cmd' : 'ctrl',
}),
};
</script>
@@ -93,6 +97,7 @@ export default {
:file="file"
:level="0"
:hide-extra-on-tree="true"
+ :extra-component="fileRowExtraComponent"
:show-changed-icon="true"
@toggleTreeOpen="toggleTreeOpen"
@clickFile="scrollToFile"
diff --git a/app/assets/javascripts/vue_shared/components/changed_file_icon.vue b/app/assets/javascripts/vue_shared/components/changed_file_icon.vue
index 09cffc57688..75c3c544c77 100644
--- a/app/assets/javascripts/vue_shared/components/changed_file_icon.vue
+++ b/app/assets/javascripts/vue_shared/components/changed_file_icon.vue
@@ -36,17 +36,12 @@ export default {
required: false,
default: true,
},
- showChangedStatus: {
- type: Boolean,
- required: false,
- default: false,
- },
},
computed: {
changedIcon() {
// False positive i18n lint: https://gitlab.com/gitlab-org/frontend/eslint-plugin-i18n/issues/26
// eslint-disable-next-line @gitlab/i18n/no-non-i18n-strings
- const suffix = this.showStagedIcon ? '-solid' : '';
+ const suffix = !this.file.changed && this.file.staged && this.showStagedIcon ? '-solid' : '';
return `${getCommitIconMap(this.file).icon}${suffix}`;
},
@@ -91,8 +86,8 @@ export default {
<span
v-gl-tooltip.right
:title="tooltipTitle"
- :class="[{ 'ml-auto': isCentered }, changedIconClass]"
- class="file-changed-icon d-flex align-items-center "
+ :class="{ 'ml-auto': isCentered }"
+ class="file-changed-icon d-inline-block"
>
<icon v-if="showIcon" :name="changedIcon" :size="size" :class="changedIconClass" />
</span>
diff --git a/app/assets/javascripts/vue_shared/components/file_row.vue b/app/assets/javascripts/vue_shared/components/file_row.vue
index 0c9f6ea94d5..611001df32f 100644
--- a/app/assets/javascripts/vue_shared/components/file_row.vue
+++ b/app/assets/javascripts/vue_shared/components/file_row.vue
@@ -1,4 +1,5 @@
<script>
+import Icon from '~/vue_shared/components/icon.vue';
import FileHeader from '~/vue_shared/components/file_row_header.vue';
import FileIcon from '~/vue_shared/components/file_icon.vue';
import ChangedFileIcon from '~/vue_shared/components/changed_file_icon.vue';
@@ -8,6 +9,7 @@ export default {
components: {
FileHeader,
FileIcon,
+ Icon,
ChangedFileIcon,
},
props: {
@@ -24,7 +26,6 @@ export default {
required: false,
default: null,
},
-
hideExtraOnTree: {
type: Boolean,
required: false,
@@ -142,17 +143,17 @@ export default {
@mouseleave="toggleDropdown(false)"
>
<div class="file-row-name-container">
- <span ref="textOutput" :style="levelIndentation" class="file-row-name str-truncated d-flex">
+ <span ref="textOutput" :style="levelIndentation" class="file-row-name str-truncated">
<file-icon
v-if="!showChangedIcon || file.type === 'tree'"
- class="file-row-icon text-secondary mr-1"
+ class="file-row-icon"
:file-name="file.name"
:loading="file.loading"
:folder="isTree"
:opened="file.opened"
:size="16"
/>
- <file-icon v-else :file-name="file.name" :size="16" css-classes="top mr-1" />
+ <changed-file-icon v-else :file="file" :size="16" class="append-right-5" />
{{ file.name }}
</span>
<component
@@ -162,7 +163,6 @@ export default {
:dropdown-open="dropdownOpen"
@toggle="toggleDropdown($event)"
/>
- <changed-file-icon :file="file" :size="16" class="append-right-5" />
</div>
</div>
<template v-if="file.opened || file.isHeader">
@@ -172,6 +172,7 @@ export default {
:file="childFile"
:level="childFilesLevel"
:hide-extra-on-tree="hideExtraOnTree"
+ :extra-component="extraComponent"
:show-changed-icon="showChangedIcon"
@toggleTreeOpen="toggleTreeOpen"
@clickFile="clickedFile"
diff --git a/app/assets/stylesheets/pages/diff.scss b/app/assets/stylesheets/pages/diff.scss
index d1053570093..f394e4ab58a 100644
--- a/app/assets/stylesheets/pages/diff.scss
+++ b/app/assets/stylesheets/pages/diff.scss
@@ -14,9 +14,9 @@
cursor: pointer;
@media (min-width: map-get($grid-breakpoints, md)) {
- // The `+11` is to ensure the file header border shows when scrolled -
+ // The `-1` below is to prevent two borders from clashing up against eachother -
// the bottom of the compare-versions header and the top of the file header
- $mr-file-header-top: $mr-version-controls-height + $header-height + $mr-tabs-height + 11;
+ $mr-file-header-top: $mr-version-controls-height + $header-height + $mr-tabs-height - 1;
position: -webkit-sticky;
position: sticky;
@@ -552,7 +552,7 @@ table.code {
.diff-stats {
align-items: center;
- padding: 0 1rem;
+ padding: 0 0.25rem;
.diff-stats-group {
padding: 0 0.25rem;
@@ -564,7 +564,7 @@ table.code {
&.is-compare-versions-header {
.diff-stats-group {
- padding: 0 0.25rem;
+ padding: 0 0.5rem;
}
}
}
@@ -1059,8 +1059,8 @@ table.code {
.diff-tree-list {
position: -webkit-sticky;
position: sticky;
- $top-pos: $header-height + $mr-tabs-height + $mr-version-controls-height + 11px;
- top: $header-height + $mr-tabs-height + $mr-version-controls-height + 11px;
+ $top-pos: $header-height + $mr-tabs-height + $mr-version-controls-height + 10px;
+ top: $header-height + $mr-tabs-height + $mr-version-controls-height + 10px;
max-height: calc(100vh - #{$top-pos});
z-index: 202;
@@ -1097,7 +1097,10 @@ table.code {
.tree-list-scroll {
max-height: 100%;
+ padding-top: $grid-size;
padding-bottom: $grid-size;
+ border-top: 1px solid $border-color;
+ border-bottom: 1px solid $border-color;
overflow-y: scroll;
overflow-x: auto;
}
diff --git a/app/assets/stylesheets/pages/merge_requests.scss b/app/assets/stylesheets/pages/merge_requests.scss
index 84daec4fb43..c023c9e5cbd 100644
--- a/app/assets/stylesheets/pages/merge_requests.scss
+++ b/app/assets/stylesheets/pages/merge_requests.scss
@@ -708,7 +708,7 @@
.mr-version-controls {
position: relative;
z-index: 203;
- background: $white-light;
+ background: $gray-light;
color: $gl-text-color;
margin-top: -1px;
@@ -732,7 +732,7 @@
}
.content-block {
- padding: $gl-padding;
+ padding: $gl-padding-top $gl-padding;
border-bottom: 0;
}
diff --git a/app/models/user.rb b/app/models/user.rb
index df54f358ffa..df6c28f5076 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -394,6 +394,11 @@ class User < ApplicationRecord
Gitlab::CurrentSettings.minimum_password_length..Devise.password_length.max
end
+ # Generate a random password that conforms to the current password length settings
+ def random_password
+ Devise.friendly_token(password_length.max)
+ end
+
# Devise method overridden to allow sign in with email or username
def find_for_database_authentication(warden_conditions)
conditions = warden_conditions.dup
diff --git a/app/policies/project_policy.rb b/app/policies/project_policy.rb
index e38eef527be..2789152e175 100644
--- a/app/policies/project_policy.rb
+++ b/app/policies/project_policy.rb
@@ -222,6 +222,7 @@ class ProjectPolicy < BasePolicy
enable :read_deployment
enable :read_merge_request
enable :read_sentry_issue
+ enable :update_sentry_issue
enable :read_prometheus
end
diff --git a/app/services/error_tracking/base_service.rb b/app/services/error_tracking/base_service.rb
index 430d9952332..4fe01716704 100644
--- a/app/services/error_tracking/base_service.rb
+++ b/app/services/error_tracking/base_service.rb
@@ -7,7 +7,7 @@ module ErrorTracking
return unauthorized if unauthorized
begin
- response = fetch
+ response = perform
rescue Sentry::Client::Error => e
return error(e.message, :bad_request)
rescue Sentry::Client::MissingKeysError => e
@@ -22,7 +22,7 @@ module ErrorTracking
private
- def fetch
+ def perform
raise NotImplementedError,
"#{self.class} does not implement #{__method__}"
end
@@ -62,5 +62,9 @@ module ErrorTracking
def can_read?
can?(current_user, :read_sentry_issue, project)
end
+
+ def can_update?
+ can?(current_user, :update_sentry_issue, project)
+ end
end
end
diff --git a/app/services/error_tracking/issue_details_service.rb b/app/services/error_tracking/issue_details_service.rb
index 368cd4517fc..31fb6a9618c 100644
--- a/app/services/error_tracking/issue_details_service.rb
+++ b/app/services/error_tracking/issue_details_service.rb
@@ -4,7 +4,7 @@ module ErrorTracking
class IssueDetailsService < ErrorTracking::BaseService
private
- def fetch
+ def perform
project_error_tracking_setting.issue_details(issue_id: params[:issue_id])
end
diff --git a/app/services/error_tracking/issue_latest_event_service.rb b/app/services/error_tracking/issue_latest_event_service.rb
index b6ad8f8028b..dd6b7f8285f 100644
--- a/app/services/error_tracking/issue_latest_event_service.rb
+++ b/app/services/error_tracking/issue_latest_event_service.rb
@@ -4,7 +4,7 @@ module ErrorTracking
class IssueLatestEventService < ErrorTracking::BaseService
private
- def fetch
+ def perform
project_error_tracking_setting.issue_latest_event(issue_id: params[:issue_id])
end
diff --git a/app/services/error_tracking/issue_update_service.rb b/app/services/error_tracking/issue_update_service.rb
index e433b4a11f2..db754d54fef 100644
--- a/app/services/error_tracking/issue_update_service.rb
+++ b/app/services/error_tracking/issue_update_service.rb
@@ -4,6 +4,16 @@ module ErrorTracking
class IssueUpdateService < ErrorTracking::BaseService
private
+ def perform
+ response = fetch
+
+ unless parse_errors(response).present?
+ response[:closed_issue_iid] = update_related_issue&.iid
+ end
+
+ response
+ end
+
def fetch
project_error_tracking_setting.update_issue(
issue_id: params[:issue_id],
@@ -11,12 +21,58 @@ module ErrorTracking
)
end
+ def update_related_issue
+ issue = related_issue
+ return unless issue
+
+ close_and_create_note(issue)
+ end
+
+ def close_and_create_note(issue)
+ return unless resolving? && issue.opened?
+
+ processed_issue = close_issue(issue)
+ return unless processed_issue.reset.closed?
+
+ create_system_note(processed_issue)
+ processed_issue
+ end
+
+ def close_issue(issue)
+ Issues::CloseService
+ .new(project, current_user)
+ .execute(issue, system_note: false)
+ end
+
+ def create_system_note(issue)
+ SystemNoteService.close_after_error_tracking_resolve(issue, project, current_user)
+ end
+
+ def related_issue
+ SentryIssueFinder
+ .new(project, current_user: current_user)
+ .execute(params[:issue_id])
+ &.issue
+ end
+
+ def resolving?
+ update_params[:status] == 'resolved'
+ end
+
def update_params
params.except(:issue_id)
end
def parse_response(response)
- { updated: response[:updated].present? }
+ {
+ updated: response[:updated].present?,
+ closed_issue_iid: response[:closed_issue_iid]
+ }
+ end
+
+ def check_permissions
+ return error('Error Tracking is not enabled') unless enabled?
+ return error('Access denied', :unauthorized) unless can_update?
end
end
end
diff --git a/app/services/error_tracking/list_issues_service.rb b/app/services/error_tracking/list_issues_service.rb
index 132e9dfa7bd..d34ea8aa3b0 100644
--- a/app/services/error_tracking/list_issues_service.rb
+++ b/app/services/error_tracking/list_issues_service.rb
@@ -12,7 +12,7 @@ module ErrorTracking
private
- def fetch
+ def perform
project_error_tracking_setting.list_sentry_issues(
issue_status: issue_status,
limit: limit,
diff --git a/app/services/error_tracking/list_projects_service.rb b/app/services/error_tracking/list_projects_service.rb
index 09a0b952e84..6523a66bbed 100644
--- a/app/services/error_tracking/list_projects_service.rb
+++ b/app/services/error_tracking/list_projects_service.rb
@@ -12,7 +12,7 @@ module ErrorTracking
private
- def fetch
+ def perform
project_error_tracking_setting.list_sentry_projects
end
diff --git a/app/services/pages_domains/create_acme_order_service.rb b/app/services/pages_domains/create_acme_order_service.rb
index 8eab5c52432..c600f497fa5 100644
--- a/app/services/pages_domains/create_acme_order_service.rb
+++ b/app/services/pages_domains/create_acme_order_service.rb
@@ -3,9 +3,6 @@
module PagesDomains
class CreateAcmeOrderService
attr_reader :pages_domain
- # TODO: remove this hack after https://gitlab.com/gitlab-org/gitlab/issues/30146 is implemented
- # This makes GitLab automatically retry the certificate obtaining process every 2 hours if process wasn't finished
- SHORT_EXPIRATION_DELAY = 2.hours
def initialize(pages_domain)
@pages_domain = pages_domain
@@ -20,7 +17,7 @@ module PagesDomains
private_key = OpenSSL::PKey::RSA.new(4096)
saved_order = pages_domain.acme_orders.create!(
url: order.url,
- expires_at: [order.expires, SHORT_EXPIRATION_DELAY.from_now].min,
+ expires_at: order.expires,
private_key: private_key.to_pem,
challenge_token: challenge.token,
diff --git a/app/services/system_note_service.rb b/app/services/system_note_service.rb
index 38e0a7d34ad..033c80fd8ed 100644
--- a/app/services/system_note_service.rb
+++ b/app/services/system_note_service.rb
@@ -99,6 +99,12 @@ module SystemNoteService
::SystemNotes::TimeTrackingService.new(noteable: noteable, project: project, author: author).change_time_spent
end
+ def close_after_error_tracking_resolve(issue, project, author)
+ body = _('resolved the corresponding error and closed the issue.')
+
+ create_note(NoteSummary.new(issue, project, author, body, action: 'closed'))
+ end
+
def change_status(noteable, project, author, status, source = nil)
::SystemNotes::IssuablesService.new(noteable: noteable, project: project, author: author).change_status(status, source)
end
diff --git a/app/services/users/build_service.rb b/app/services/users/build_service.rb
index d18f20bc1db..56631bf2785 100644
--- a/app/services/users/build_service.rb
+++ b/app/services/users/build_service.rb
@@ -23,7 +23,7 @@ module Users
@reset_token = user.generate_reset_token if params[:reset_password]
if user_params[:force_random_password]
- random_password = Devise.friendly_token.first(User.password_length.min)
+ random_password = User.random_password
user.password = user.password_confirmation = random_password
end
end
diff --git a/changelogs/unreleased/197925-setting-minimum-password-length-breaks-sign-up-with-saml.yml b/changelogs/unreleased/197925-setting-minimum-password-length-breaks-sign-up-with-saml.yml
new file mode 100644
index 00000000000..0530fd88749
--- /dev/null
+++ b/changelogs/unreleased/197925-setting-minimum-password-length-breaks-sign-up-with-saml.yml
@@ -0,0 +1,5 @@
+---
+title: Fixes random passwords generated not conforming to minimum_password_length setting
+merge_request: 23387
+author:
+type: fixed
diff --git a/changelogs/unreleased/198030-fix-wrong-data.yml b/changelogs/unreleased/198030-fix-wrong-data.yml
new file mode 100644
index 00000000000..d18203cdfef
--- /dev/null
+++ b/changelogs/unreleased/198030-fix-wrong-data.yml
@@ -0,0 +1,5 @@
+---
+title: Remove invalid data from jira_tracker_data table
+merge_request: 23621
+author:
+type: fixed
diff --git a/changelogs/unreleased/198289-unable-to-sign-out-from-secondary-geo-node.yml b/changelogs/unreleased/198289-unable-to-sign-out-from-secondary-geo-node.yml
new file mode 100644
index 00000000000..ac8db19b2c4
--- /dev/null
+++ b/changelogs/unreleased/198289-unable-to-sign-out-from-secondary-geo-node.yml
@@ -0,0 +1,5 @@
+---
+title: Allow users to sign out on a read-only instance
+merge_request: 23545
+author:
+type: fixed
diff --git a/changelogs/unreleased/39825-close-issue-after-error-resolve.yml b/changelogs/unreleased/39825-close-issue-after-error-resolve.yml
new file mode 100644
index 00000000000..9a59c812290
--- /dev/null
+++ b/changelogs/unreleased/39825-close-issue-after-error-resolve.yml
@@ -0,0 +1,5 @@
+---
+title: Close Issue when resolving corresponding Sentry error
+merge_request: 22744
+author:
+type: added
diff --git a/changelogs/unreleased/jprovazn-fix-group-preloader.yml b/changelogs/unreleased/jprovazn-fix-group-preloader.yml
new file mode 100644
index 00000000000..b2211fb81af
--- /dev/null
+++ b/changelogs/unreleased/jprovazn-fix-group-preloader.yml
@@ -0,0 +1,5 @@
+---
+title: Fix loading of sub-epics caused by wrong subscription check.
+merge_request: 23184
+author:
+type: fixed
diff --git a/changelogs/unreleased/revert-22364.yml b/changelogs/unreleased/revert-22364.yml
new file mode 100644
index 00000000000..2b2d066adab
--- /dev/null
+++ b/changelogs/unreleased/revert-22364.yml
@@ -0,0 +1,6 @@
+---
+title: Reverts MR diff redesign which fixes Web IDE visual bugs including file dropdown
+ not showing up
+merge_request: 23428
+author:
+type: fixed
diff --git a/changelogs/unreleased/sh-add-missing-backtrace-define.yml b/changelogs/unreleased/sh-add-missing-backtrace-define.yml
new file mode 100644
index 00000000000..fd07321d012
--- /dev/null
+++ b/changelogs/unreleased/sh-add-missing-backtrace-define.yml
@@ -0,0 +1,5 @@
+---
+title: Fix Bitbucket Server importer error handler
+merge_request: 23310
+author:
+type: fixed
diff --git a/db/post_migrate/20200123155929_remove_invalid_jira_data.rb b/db/post_migrate/20200123155929_remove_invalid_jira_data.rb
new file mode 100644
index 00000000000..7ddac15c3fb
--- /dev/null
+++ b/db/post_migrate/20200123155929_remove_invalid_jira_data.rb
@@ -0,0 +1,25 @@
+# frozen_string_literal: true
+
+# See http://doc.gitlab.com/ce/development/migration_style_guide.html
+# for more information on how to write migrations for GitLab.
+
+class RemoveInvalidJiraData < ActiveRecord::Migration[5.2]
+ include Gitlab::Database::MigrationHelpers
+
+ DOWNTIME = false
+
+ def up
+ sql = "DELETE FROM jira_tracker_data WHERE \
+ (length(encrypted_api_url) > 0 AND encrypted_api_url_iv IS NULL) \
+ OR (length(encrypted_url) > 0 AND encrypted_url_iv IS NULL) \
+ OR (length(encrypted_username) > 0 AND encrypted_username_iv IS NULL) \
+ OR (length(encrypted_password) > 0 AND encrypted_password_iv IS NULL)"
+
+ execute(sql)
+ end
+
+ def down
+ # We need to figure out why migrating data to jira_tracker_data table
+ # failed and then can recreate the data
+ end
+end
diff --git a/db/schema.rb b/db/schema.rb
index 8ee1f2ffea6..12dd2a0adc8 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -10,7 +10,7 @@
#
# It's strongly recommended that you check this file into your version control system.
-ActiveRecord::Schema.define(version: 2020_01_17_112554) do
+ActiveRecord::Schema.define(version: 2020_01_23_155929) do
# These are extensions that must be enabled in order to support this database
enable_extension "pg_trgm"
diff --git a/doc/administration/logs.md b/doc/administration/logs.md
index c69f787a5d8..80a24a7e972 100644
--- a/doc/administration/logs.md
+++ b/doc/administration/logs.md
@@ -121,7 +121,9 @@ In this example we can see that server processed an HTTP request with URL
## `api_json.log`
-Introduced in GitLab 10.0, this file lives in
+> Introduced in GitLab 10.0.
+
+This file lives in
`/var/log/gitlab/gitlab-rails/api_json.log` for Omnibus GitLab packages or in
`/home/git/gitlab/log/api_json.log` for installations from source.
@@ -159,6 +161,21 @@ October 07, 2014 11:25: User "Claudie Hodkiewicz" (nasir_stehr@olson.co.uk) was
October 07, 2014 11:25: Project "project133" was removed
```
+## `application_json.log`
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/issues/22812) in GitLab 12.7.
+
+This file lives in `/var/log/gitlab/gitlab-rails/application_json.log` for
+Omnibus GitLab packages or in `/home/git/gitlab/log/application_json.log` for
+installations from source.
+
+It contains the JSON version of the logs in `application.log` like the example below:
+
+``` json
+{"severity":"INFO","time":"2020-01-14T13:35:15.466Z","correlation_id":"3823a1550b64417f9c9ed8ee0f48087e","message":"User \"Administrator\" (admin@example.com) was created"}
+{"severity":"INFO","time":"2020-01-14T13:35:15.466Z","correlation_id":"78e3df10c9a18745243d524540bd5be4","message":"Project \"project133\" was removed"}
+```
+
## `integrations_json.log`
This file lives in `/var/log/gitlab/gitlab-rails/integrations_json.log` for
@@ -174,7 +191,9 @@ It contains information about [integrations](../user/project/integrations/projec
## `kubernetes.log`
-Introduced in GitLab 11.6. This file lives in
+> Introduced in GitLab 11.6.
+
+This file lives in
`/var/log/gitlab/gitlab-rails/kubernetes.log` for Omnibus GitLab
packages or in `/home/git/gitlab/log/kubernetes.log` for
installations from source.
@@ -320,13 +339,17 @@ It logs information whenever a [repository check is run][repocheck] on a project
## `importer.log`
-Introduced in GitLab 11.3. This file lives in `/var/log/gitlab/gitlab-rails/importer.log` for
+> Introduced in GitLab 11.3.
+
+This file lives in `/var/log/gitlab/gitlab-rails/importer.log` for
Omnibus GitLab packages or in `/home/git/gitlab/log/importer.log` for
installations from source.
## `auth.log`
-Introduced in GitLab 12.0. This file lives in `/var/log/gitlab/gitlab-rails/auth.log` for
+> Introduced in GitLab 12.0.
+
+This file lives in `/var/log/gitlab/gitlab-rails/auth.log` for
Omnibus GitLab packages or in `/home/git/gitlab/log/auth.log` for
installations from source.
@@ -356,7 +379,9 @@ GraphQL queries are recorded in that file. For example:
## `migrations.log`
-Introduced in GitLab 12.3. This file lives in `/var/log/gitlab/gitlab-rails/migrations.log` for
+> Introduced in GitLab 12.3.
+
+This file lives in `/var/log/gitlab/gitlab-rails/migrations.log` for
Omnibus GitLab packages or in `/home/git/gitlab/log/migrations.log` for
installations from source.
@@ -406,7 +431,9 @@ It is stored at:
## `elasticsearch.log`
-Introduced in GitLab 12.6. This file lives in
+> Introduced in GitLab 12.6.
+
+This file lives in
`/var/log/gitlab/gitlab-rails/elasticsearch.log` for Omnibus GitLab
packages or in `/home/git/gitlab/log/elasticsearch.log` for installations
from source.
diff --git a/doc/api/keys.md b/doc/api/keys.md
index 30b0cda6c8b..e05b1191715 100644
--- a/doc/api/keys.md
+++ b/doc/api/keys.md
@@ -129,8 +129,14 @@ Example response:
}
```
-Deploy Keys are bound to the creating user, so if you query with a deploy key
-fingerprint you get additional information about the projects using that key:
+## Get user by deploy key fingerprint
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/issues/119209) in GitLab 12.7.
+
+Deploy keys are bound to the creating user, so if you query with a deploy key
+fingerprint you get additional information about the projects using that key.
+
+Example request:
```sh
curl --header "PRIVATE-TOKEN: <your_access_token>" 'https://gitlab.example.com/api/v4/keys?fingerprint=SHA256%3AnUhzNyftwADy8AH3wFY31tAKs7HufskYTte2aXo%2FlCg
diff --git a/doc/api/merge_request_approvals.md b/doc/api/merge_request_approvals.md
index 4552a56d808..4cee25f4680 100644
--- a/doc/api/merge_request_approvals.md
+++ b/doc/api/merge_request_approvals.md
@@ -63,7 +63,8 @@ POST /projects/:id/approvals
### Get project-level rules
-> [Introduced](https://gitlab.com/gitlab-org/gitlab/issues/11877) in [GitLab Starter](https://about.gitlab.com/pricing/) 12.3.
+> - [Introduced](https://gitlab.com/gitlab-org/gitlab/issues/11877) in [GitLab Starter](https://about.gitlab.com/pricing/) 12.3.
+> - `protected_branches` property was [introduced](https://gitlab.com/gitlab-org/gitlab/issues/460) in [GitLab Premium](https://about.gitlab.com/pricing/) 12.7.
You can request information about a project's approval rules using the following endpoint:
@@ -130,6 +131,31 @@ GET /projects/:id/approval_rules
"ldap_access": null
}
],
+ "protected_branches": [
+ {
+ "id": 1,
+ "name": "master",
+ "push_access_levels": [
+ {
+ "access_level": 30,
+ "access_level_description": "Developers + Maintainers"
+ }
+ ],
+ "merge_access_levels": [
+ {
+ "access_level": 30,
+ "access_level_description": "Developers + Maintainers"
+ }
+ ],
+ "unprotect_access_levels": [
+ {
+ "access_level": 40,
+ "access_level_description": "Maintainers"
+ }
+ ],
+ "code_owner_approval_required": "false"
+ }
+ ],
"contains_hidden_groups": false
}
]
@@ -147,13 +173,14 @@ POST /projects/:id/approval_rules
**Parameters:**
-| Attribute | Type | Required | Description |
-|----------------------|---------|----------|-----------------------------------------------------------|
-| `id` | integer | yes | The ID of a project |
-| `name` | string | yes | The name of the approval rule |
-| `approvals_required` | integer | yes | The number of required approvals for this rule |
-| `user_ids` | Array | no | The ids of users as approvers |
-| `group_ids` | Array | no | The ids of groups as approvers |
+| Attribute | Type | Required | Description |
+|------------------------|---------|----------|------------------------------------------------------------------|
+| `id` | integer | yes | The ID of a project |
+| `name` | string | yes | The name of the approval rule |
+| `approvals_required` | integer | yes | The number of required approvals for this rule |
+| `user_ids` | Array | no | The ids of users as approvers |
+| `group_ids` | Array | no | The ids of groups as approvers |
+| `protected_branch_ids` | Array | no | **(PREMIUM)** The ids of protected branches to scope the rule by |
```json
{
@@ -207,6 +234,31 @@ POST /projects/:id/approval_rules
"ldap_access": null
}
],
+ "protected_branches": [
+ {
+ "id": 1,
+ "name": "master",
+ "push_access_levels": [
+ {
+ "access_level": 30,
+ "access_level_description": "Developers + Maintainers"
+ }
+ ],
+ "merge_access_levels": [
+ {
+ "access_level": 30,
+ "access_level_description": "Developers + Maintainers"
+ }
+ ],
+ "unprotect_access_levels": [
+ {
+ "access_level": 40,
+ "access_level_description": "Maintainers"
+ }
+ ],
+ "code_owner_approval_required": "false"
+ }
+ ],
"contains_hidden_groups": false
}
```
@@ -225,14 +277,15 @@ PUT /projects/:id/approval_rules/:approval_rule_id
**Parameters:**
-| Attribute | Type | Required | Description |
-|----------------------|---------|----------|-----------------------------------------------------------|
-| `id` | integer | yes | The ID of a project |
-| `approval_rule_id` | integer | yes | The ID of a approval rule |
-| `name` | string | yes | The name of the approval rule |
-| `approvals_required` | integer | yes | The number of required approvals for this rule |
-| `user_ids` | Array | no | The ids of users as approvers |
-| `group_ids` | Array | no | The ids of groups as approvers |
+| Attribute | Type | Required | Description |
+|------------------------|---------|----------|------------------------------------------------------------------|
+| `id` | integer | yes | The ID of a project |
+| `approval_rule_id` | integer | yes | The ID of a approval rule |
+| `name` | string | yes | The name of the approval rule |
+| `approvals_required` | integer | yes | The number of required approvals for this rule |
+| `user_ids` | Array | no | The ids of users as approvers |
+| `group_ids` | Array | no | The ids of groups as approvers |
+| `protected_branch_ids` | Array | no | **(PREMIUM)** The ids of protected branches to scope the rule by |
```json
{
@@ -286,6 +339,31 @@ PUT /projects/:id/approval_rules/:approval_rule_id
"ldap_access": null
}
],
+ "protected_branches": [
+ {
+ "id": 1,
+ "name": "master",
+ "push_access_levels": [
+ {
+ "access_level": 30,
+ "access_level_description": "Developers + Maintainers"
+ }
+ ],
+ "merge_access_levels": [
+ {
+ "access_level": 30,
+ "access_level_description": "Developers + Maintainers"
+ }
+ ],
+ "unprotect_access_levels": [
+ {
+ "access_level": 40,
+ "access_level_description": "Maintainers"
+ }
+ ],
+ "code_owner_approval_required": "false"
+ }
+ ],
"contains_hidden_groups": false
}
```
diff --git a/doc/api/protected_branches.md b/doc/api/protected_branches.md
index 4a750b42f65..e6844536c33 100644
--- a/doc/api/protected_branches.md
+++ b/doc/api/protected_branches.md
@@ -34,6 +34,7 @@ Example response:
```json
[
{
+ "id": 1,
"name": "master",
"push_access_levels": [
{
@@ -61,6 +62,7 @@ Example response:
```json
[
{
+ "id": 1,
"name": "master",
"push_access_levels": [
{
@@ -105,6 +107,7 @@ Example response:
```json
{
+ "id": 1,
"name": "master",
"push_access_levels": [
{
@@ -129,6 +132,7 @@ Example response:
```json
{
+ "id": 1,
"name": "master",
"push_access_levels": [
{
@@ -179,6 +183,7 @@ Example response:
```json
{
+ "id": 1,
"name": "*-stable",
"push_access_levels": [
{
@@ -209,6 +214,7 @@ Example response:
```json
{
+ "id": 1,
"name": "*-stable",
"push_access_levels": [
{
@@ -251,6 +257,7 @@ Example response:
```json
{
+ "id": 1,
"name": "*-stable",
"push_access_levels": [
{
diff --git a/doc/user/analytics/code_review_analytics.md b/doc/user/analytics/code_review_analytics.md
index 87c29c265bf..cd2b0dd2bf7 100644
--- a/doc/user/analytics/code_review_analytics.md
+++ b/doc/user/analytics/code_review_analytics.md
@@ -4,31 +4,55 @@ description: "Learn how long your open merge requests have spent in code review,
# Code Review Analytics **(STARTER)**
-> [Introduced](https://gitlab.com/gitlab-org/gitlab/issues/38062) in GitLab ([Starter](https://about.gitlab.com/pricing/)) 12.7.
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/issues/38062) in [GitLab Starter](https://about.gitlab.com/pricing/) 12.7.
-Want to learn how long your open merge requests have spent in code review? Or what distinguishes your longest-running code reviews? These are some of the questions Code Review Analytics is designed to answer.
+Code Review Analytics makes it easy to view the longest-running reviews among open merge requests,
+enabling you to take action on individual MRs and reduce overall cycle time.
NOTE: **Note:**
-Initially no data will appear. Data will populate as users comment on open merge requests.
+Initially, no data will appear. Data is populated as users comment on open merge requests.
## Overview
-Code Review Analytics displays a collection of merge requests in a table. These are all the open merge requests that are considered to be in code review. This feature considers code review to begin when a merge request receives its first comment from someone other than the author. The rows of the table are sorted by review time so the longest reviews appear at the top. There are also columns to display the author, approvers, comment count, and line -/+ counts.
+Code Review Analytics displays a table of open merge requests which are currently considered to be in code review.
+The code review period for an MR is automatically identified as the time since the first non-author comment.
-This feature is designed for [development team leaders](https://about.gitlab.com/handbook/marketing/product-marketing/roles-personas/#delaney-development-team-lead) and others who want to understand broad code review dynamics, and identify patterns to help explain them. You can use Code Review Analytics to expose your team's unique challenges with code review, and identify improvements that might substantially accelerate your development cycle.
+To access Code Review Analytics, from your project's menu, go to **Project Analytics > Code Review**.
+
+- The table is sorted by review duration, helping you quickly find the longest-running reviews which may need intervention or to be broken down into smaller parts.
+- You can filter the list of MRs by milestone and label.
+- Columns to display the author, approvers, comment count, and line change (-/+) counts.
## Use cases
-Perhaps your team agrees that code review is moving too slow, or the [Cycle Analytics feature](https://docs.gitlab.com/ee/user/analytics/cycle_analytics.html) shows that "Review" is your team's most time-consuming step. You can use Code Review Analytics to see what is currently moving slowest, and analyze the patterns and trends between them. Lots of comments or commits? Maybe the code is too complex. A particular author is involved? Maybe more training is advisable. Few comments and approvers? Maybe your team is understaffed.
+This feature is designed for [development team leaders](https://about.gitlab.com/handbook/marketing/product-marketing/roles-personas/#delaney-development-team-lead)
+and others who want to understand broad code review dynamics, and identify patterns to help explain them.
+
+You can use Code Review Analytics to expose your team's unique challenges with code review, and
+identify improvements that might substantially accelerate your development cycle.
+
+Code Review Analytics can be used when:
+
+- Your team agrees that code review is moving too slow.
+- The [Cycle Analytics feature](cycle_analytics.md) shows that reviews are your team's most time-consuming step.
+
+You can use Code Review Analytics to see the types of work that are currently moving the slowest, and analyze the patterns
+and trends between them. For example:
+
+- Lots of comments or commits? Maybe the code is too complex.
+- A particular author is involved? Maybe more training is required.
+- Few comments and approvers? Maybe your team is understaffed.
## Permissions
- On [Starter or Bronze tier](https://about.gitlab.com/pricing/) and above.
-- By users with [Reporter access] and above.
+- By users with Reporter access and above.
-## Feature flag
+## Disable with feature flag
-Code Review Analytics is [currently protected by a feature flag](https://gitlab.com/gitlab-org/gitlab/issues/194165) that defaults to "enabled" - meaning the feature is available. If you experience performance problems or otherwise wish to disable the feature, a GitLab administrator can execute a command in a Rails console:
+Code Review Analytics is [currently enabled by a feature flag](https://gitlab.com/gitlab-org/gitlab/issues/194165)
+that defaults to ON, meaning the feature is available. If you experience performance problems or
+otherwise wish to disable the feature, a GitLab administrator can execute a command in a Rails console:
```ruby
Feature.disable(:code_review_analytics)
diff --git a/doc/user/analytics/cycle_analytics.md b/doc/user/analytics/cycle_analytics.md
index dfc0f488ff9..e0bb4e03c41 100644
--- a/doc/user/analytics/cycle_analytics.md
+++ b/doc/user/analytics/cycle_analytics.md
@@ -163,6 +163,15 @@ This chart uses the global page filters for displaying data based on the selecte
group, projects, and timeframe. In addition, specific stages can be selected
from within the chart itself.
+### Chart median line
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/issues/36675) in GitLab 12.7.
+
+The median line on the chart displays data that is offset by the number of days selected.
+For example, if 30 days worth of data has been selected (for example, 2019-12-16 to 2020-01-15) the
+median line will represent the previous 30 days worth of data (2019-11-16 to 2019-12-16)
+as a metric to compare against.
+
### Enabling chart
By default, this chart is disabled for self-managed instances. To enable it, ask an
diff --git a/doc/user/analytics/index.md b/doc/user/analytics/index.md
index 707ba01eb79..07d756af582 100644
--- a/doc/user/analytics/index.md
+++ b/doc/user/analytics/index.md
@@ -16,11 +16,11 @@ Once enabled, click on **Analytics** from the top navigation bar.
From the centralized analytics workspace, the following analytics are available:
- [Code Review Analytics](code_review_analytics.md), enabled with the `code_review_analytics`
- [feature flag](../../development/feature_flags/development.html#enabling-a-feature-flag-in-development). **(STARTER)**
+ [feature flag](../../development/feature_flags/development.md#enabling-a-feature-flag-in-development). **(STARTER)**
- [Cycle Analytics](cycle_analytics.md), enabled with the `cycle_analytics`
- [feature flag](../../development/feature_flags/development.html#enabling-a-feature-flag-in-development). **(PREMIUM)**
+ [feature flag](../../development/feature_flags/development.md#enabling-a-feature-flag-in-development). **(PREMIUM)**
- [Productivity Analytics](productivity_analytics.md), enabled with the `productivity_analytics`
- [feature flag](../../development/feature_flags/development.html#enabling-a-feature-flag-in-development). **(PREMIUM)**
+ [feature flag](../../development/feature_flags/development.md#enabling-a-feature-flag-in-development). **(PREMIUM)**
NOTE: **Note:**
Project-level Cycle Analytics are still available at a project's **Project > Cycle Analytics**.
diff --git a/doc/user/application_security/dependency_scanning/index.md b/doc/user/application_security/dependency_scanning/index.md
index c47fd6f1ff1..0c1896e210d 100644
--- a/doc/user/application_security/dependency_scanning/index.md
+++ b/doc/user/application_security/dependency_scanning/index.md
@@ -135,7 +135,7 @@ using environment variables.
| `DS_ANALYZER_IMAGE_PREFIX` | Override the name of the Docker registry providing the official default images (proxy). Read more about [customizing analyzers](analyzers.md). |
| `DS_ANALYZER_IMAGE_TAG` | Override the Docker tag of the official default images. Read more about [customizing analyzers](analyzers.md). |
| `DS_PYTHON_VERSION` | Version of Python. If set to 2, dependencies are installed using Python 2.7 instead of Python 3.6. ([Introduced](https://gitlab.com/gitlab-org/gitlab/issues/12296) in GitLab 12.1)|
-| `DS_PIP_VERSION` | Force the install of a specific pip version (example: `"19.3"`), otherwise the pip installed in the docker image is used. |
+| `DS_PIP_VERSION` | Force the install of a specific pip version (example: `"19.3"`), otherwise the pip installed in the Docker image is used. ([Introduced](https://gitlab.com/gitlab-org/gitlab/issues/12811) in GitLab 12.7) |
| `DS_PIP_DEPENDENCY_PATH` | Path to load Python pip dependencies from. ([Introduced](https://gitlab.com/gitlab-org/gitlab/issues/12412) in GitLab 12.2) |
| `GEMNASIUM_DB_LOCAL_PATH` | Path to local gemnasium database (default `/gemnasium-db`).
| `GEMNASIUM_DB_REMOTE_URL` | Repository URL for fetching the gemnasium database (default `https://gitlab.com/gitlab-org/security-products/gemnasium-db.git`).
diff --git a/doc/user/clusters/applications.md b/doc/user/clusters/applications.md
index 47d835a1622..e195cf19e65 100644
--- a/doc/user/clusters/applications.md
+++ b/doc/user/clusters/applications.md
@@ -661,6 +661,65 @@ management project. Refer to the
[chart](https://gitlab.com/gitlab-org/charts/gitlab-runner) for the
available configuration options.
+### Install Cilium using GitLab CI
+
+> [Introduced](https://gitlab.com/gitlab-org/cluster-integration/cluster-applications/merge_requests/22) in GitLab 12.8.
+
+[Cilium](https://cilium.io/) is a networking plugin for Kubernetes
+that you can use to implement support for
+[NetworkPolicy](https://kubernetes.io/docs/concepts/services-networking/network-policies/)
+resources.
+
+Enable Cilium in the `.gitlab/managed-apps/config.yaml` file to install it:
+
+```yaml
+# possible values are gke, eks or you can leave it blank
+clusterType: gke
+
+cilium:
+ installed: true
+```
+
+The `clusterType` variable enables the recommended Helm variables for
+a corresponding cluster type, the default value is blank. You can
+check the recommended variables for each cluster type in the official
+documentation:
+
+- [Google GKE](https://cilium.readthedocs.io/en/stable/gettingstarted/k8s-install-gke/#prepare-deploy-cilium)
+- [AWS EKS](https://cilium.readthedocs.io/en/stable/gettingstarted/k8s-install-eks/#prepare-deploy-cilium)
+
+You can customize Cilium's Helm variables by defining the
+`.gitlab/managed-apps/cilium/values.yaml` file in your cluster
+management project. Refer to the
+[Cilium chart](https://github.com/cilium/cilium/tree/master/install/kubernetes/cilium)
+for the available configuration options.
+
+CAUTION: **Caution:**
+Installation and removal of the Cilium [requires restart](https://cilium.readthedocs.io/en/stable/gettingstarted/k8s-install-gke/#restart-remaining-pods)
+of all affected pods in all namespaces to ensure that they are
+[managed](https://cilium.readthedocs.io/en/stable/troubleshooting/#ensure-pod-is-managed-by-cilium)
+by the correct networking plugin.
+
+NOTE: **Note:**
+Major upgrades might require additional setup steps, please consult
+the official [upgrade guide](https://docs.cilium.io/en/stable/install/upgrade/) for more
+information.
+
+By default, the drop log for traffic is logged out by the
+`cilium-monitor` sidecar container. You can check these logs via:
+
+```bash
+kubectl -n gitlab-managed-apps logs cilium-XXXX cilium-monitor
+```
+
+Drop logging can be disabled via `.gitlab/managed-apps/cilium/values.yaml`:
+
+```yml
+agent:
+ monitor:
+ enabled: false
+```
+
## Upgrading applications
> [Introduced](https://gitlab.com/gitlab-org/gitlab-foss/merge_requests/24789) in GitLab 11.8.
diff --git a/doc/user/img/markdown_copy_from_spreadsheet_v12_7.png b/doc/user/img/markdown_copy_from_spreadsheet_v12_7.png
new file mode 100644
index 00000000000..dccd6f10450
--- /dev/null
+++ b/doc/user/img/markdown_copy_from_spreadsheet_v12_7.png
Binary files differ
diff --git a/doc/user/img/markdown_paste_table_v12_7.png b/doc/user/img/markdown_paste_table_v12_7.png
new file mode 100644
index 00000000000..d3ba61da7d7
--- /dev/null
+++ b/doc/user/img/markdown_paste_table_v12_7.png
Binary files differ
diff --git a/doc/user/instance_statistics/convdev.md b/doc/user/instance_statistics/convdev.md
new file mode 100644
index 00000000000..a1a4eca191c
--- /dev/null
+++ b/doc/user/instance_statistics/convdev.md
@@ -0,0 +1,5 @@
+---
+redirect_to: '../instance_statistics/dev_ops_score.md'
+---
+
+This document was moved to [another location](../instance_statistics/dev_ops_score.md).
diff --git a/doc/user/instance_statistics/dev_ops_score.md b/doc/user/instance_statistics/dev_ops_score.md
index 68c5bb48c3c..a68f2a1e92a 100644
--- a/doc/user/instance_statistics/dev_ops_score.md
+++ b/doc/user/instance_statistics/dev_ops_score.md
@@ -1,5 +1,6 @@
# DevOps Score
+> [Introduced](https://gitlab.com/gitlab-org/gitlab-foss/issues/30469) in GitLab 9.3.
> [Renamed from Conversational Development Index](https://gitlab.com/gitlab-org/gitlab/issues/20976) in GitLab 12.6.
NOTE: **Note:**
diff --git a/doc/user/markdown.md b/doc/user/markdown.md
index 913a4332b1d..5bfbc6c1ec8 100644
--- a/doc/user/markdown.md
+++ b/doc/user/markdown.md
@@ -1375,6 +1375,22 @@ to the sides of the "dash" lines in the second row. This will affect every cell
| Cell 1 | Cell 2 | Cell 3 | Cell 4 | Cell 5 | Cell 6 |
| Cell 7 | Cell 8 | Cell 9 | Cell 10 | Cell 11 | Cell 12 |
+#### Copy from spreadsheet and paste in Markdown
+
+[Introduced](https://gitlab.com/gitlab-org/gitlab/issues/27205) in GitLab 12.7.
+
+If you're working in spreadsheet software (e.g. Microsoft Excel, Google
+Sheets, Apple Numbers), you can copy from a spreadsheet, and GitLab will
+paste it as a Markdown table. For example, suppose you have the
+following spreadsheet:
+
+![Copy from spreadsheet](img/markdown_copy_from_spreadsheet_v12_7.png)
+
+Select the cells and copy them to your clipboard. Open a GitLab Markdown
+entry and paste the spreadsheet:
+
+![Paste to Markdown table](img/markdown_paste_table_v12_7.png)
+
## References
- This document leveraged heavily from the [Markdown-Cheatsheet](https://github.com/adam-p/markdown-here/wiki/Markdown-Cheatsheet).
diff --git a/doc/user/packages/conan_repository/index.md b/doc/user/packages/conan_repository/index.md
index bcf2fea24e3..e9f86ebf4b2 100644
--- a/doc/user/packages/conan_repository/index.md
+++ b/doc/user/packages/conan_repository/index.md
@@ -266,6 +266,8 @@ The GitLab Conan repository supports the following Conan CLI commands:
## Using GitLab CI with Conan packages
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/issues/11678) in [GitLab Premium](https://about.gitlab.com/pricing/) 12.7.
+
To work with Conan commands within [GitLab CI](./../../../ci/README.md), you can use
`CI_JOB_TOKEN` in place of the personal access token in your commands.
diff --git a/doc/user/project/integrations/prometheus.md b/doc/user/project/integrations/prometheus.md
index 17e64f1692d..6c6bb4034cf 100644
--- a/doc/user/project/integrations/prometheus.md
+++ b/doc/user/project/integrations/prometheus.md
@@ -151,21 +151,24 @@ There are 2 methods to specify a variable in a query or dashboard:
By default, all projects include a GitLab-defined Prometheus dashboard, which
includes a few key metrics, but you can also define your own custom dashboards.
+You may create a new file from scratch or duplicate a GitLab-defined Prometheus
+dashboard.
+
NOTE: **Note:**
The custom metrics as defined below do not support alerts, unlike
[additional metrics](#adding-additional-metrics-premium).
#### Adding a new dashboard to your project
-You can configure a custom dashboard by adding a new `.yml` file into a project's repository. Only `.yml` files present in the projects **default** branch are displayed on the project's **Operations > Metrics** section.
-
-You may create a new file from scratch or duplicate a GitLab-defined dashboard.
+You can configure a custom dashboard by adding a new YAML file into your project's
+`.gitlab/dashboards/` directory. In order for the dashboards to be displayed on
+the project's **Operations > Metrics** page, the files must have a `.yml`
+extension and should be present in the project's **default** branch.
-**Add a `.yml` file manually**
+For example:
-1. Create a YAML file with the `.yml` extension under your repository's root
- directory inside `.gitlab/dashboards/`. For example, create
- `.gitlab/dashboards/prom_alerts.yml` with the following contents:
+1. Create `.gitlab/dashboards/prom_alerts.yml` under your repository's root
+ directory with the following contents:
```yaml
dashboard: 'Dashboard Title'
@@ -194,7 +197,7 @@ NOTE: **Note:**
Configuration files nested under subdirectories of `.gitlab/dashboards` are not
supported and will not be available in the UI.
-**Duplicate a GitLab-defined dashboard as a new `.yml` file**
+#### Duplicating a GitLab-defined dashboard
> [Introduced](https://gitlab.com/gitlab-org/gitlab/issues/37238) in GitLab 12.7.
diff --git a/doc/user/project/issues/design_management.md b/doc/user/project/issues/design_management.md
index c5358f338a5..fd4a01043ef 100644
--- a/doc/user/project/issues/design_management.md
+++ b/doc/user/project/issues/design_management.md
@@ -54,8 +54,8 @@ Design Management requires that projects are using
- Design Management data [won't be moved](https://gitlab.com/gitlab-org/gitlab/issues/13426)
when an issue is moved, nor [deleted](https://gitlab.com/gitlab-org/gitlab/issues/13427)
when an issue is deleted.
-- Design Management
- [isn't supported by Geo](https://gitlab.com/groups/gitlab-org/-/epics/1633) yet.
+- From GitLab 12.7, Design Management data [can be replicated](../../../administration/geo/replication/datatypes.md#limitations-on-replicationverification)
+ by Geo but [not verified](https://gitlab.com/gitlab-org/gitlab/issues/32467).
- Only the latest version of the designs can be deleted.
- Deleted designs cannot be recovered but you can see them on previous designs versions.
diff --git a/doc/user/project/operations/error_tracking.md b/doc/user/project/operations/error_tracking.md
index 447d294bef8..82234ebca96 100644
--- a/doc/user/project/operations/error_tracking.md
+++ b/doc/user/project/operations/error_tracking.md
@@ -55,6 +55,7 @@ This page has:
- A link to the Sentry issue.
- A link to the GitLab commit if the Sentry [release id/version](https://docs.sentry.io/workflow/releases/?platform=javascript#configure-sdk) on the Sentry Issue's first release matches a commit SHA in your GitLab hosted project.
- Other details about the issue, including a full stack trace.
+- In [GitLab 12.7 and newer](https://gitlab.com/gitlab-org/gitlab/issues/36246), language and urgency are displayed.
By default, a **Create issue** button is displayed. Once you have used it to create an issue, the button is hidden.
@@ -78,6 +79,10 @@ Ignoring an error will prevent it from appearing in the [Error Tracking List](#e
### Resolving errors
-From within the [Error Details](#error-details) page you can resolve a Sentry error by simply clicking the **Resolve** button near the top of the page.
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/issues/39825) in GitLab 12.7.
-Marking an error as resolved indicates that the error has stopped firing events. If another event occurs, the error reverts to unresolved.
+From within the [Error Details](#error-details) page you can resolve a Sentry error by
+clicking the **Resolve** button near the top of the page.
+
+Marking an error as resolved indicates that the error has stopped firing events. If another event
+occurs, the error reverts to unresolved.
diff --git a/doc/user/project/repository/git_blame.md b/doc/user/project/repository/git_blame.md
index 4b645e4c4bc..1c63d73acdb 100644
--- a/doc/user/project/repository/git_blame.md
+++ b/doc/user/project/repository/git_blame.md
@@ -23,10 +23,14 @@ noted information:
If you hover over a commit in the UI, you'll see a precise date and time
for that commit.
-![Blame previous commit](img/file_blame_previous_commit_v12_7.png "Blame previous commit")
+## Blame previous commit
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/issues/19299) in GitLab 12.7.
To see earlier revisions of a specific line, click **View blame prior to this change**
-until you've found the changes you're interested in viewing.
+until you've found the changes you're interested in viewing:
+
+![Blame previous commit](img/file_blame_previous_commit_v12_7.png "Blame previous commit")
## Associated `git` command
diff --git a/doc/user/project/service_desk.md b/doc/user/project/service_desk.md
index e9fce474040..d0c32bafe19 100644
--- a/doc/user/project/service_desk.md
+++ b/doc/user/project/service_desk.md
@@ -69,7 +69,7 @@ Follow these steps to do so:
have access to your GitLab instance. We recommend **putting this behind an alias** so it can be
changed if needed, and **[enabling Akismet](../../integration/akismet.md)** on your GitLab
instance to add spam checking to this service. Unblocked email spam would result in many spam
- issues being created, and may disrupt your GitLab service.
+ issues being created.
If you have [templates](description_templates.md) in your repository, you can optionally select
one from the selector menu to append it to all Service Desk issues.
diff --git a/lib/gitlab/auth/o_auth/auth_hash.rb b/lib/gitlab/auth/o_auth/auth_hash.rb
index 76f2827af1a..b37a9225dd7 100644
--- a/lib/gitlab/auth/o_auth/auth_hash.rb
+++ b/lib/gitlab/auth/o_auth/auth_hash.rb
@@ -34,7 +34,7 @@ module Gitlab
end
def password
- @password ||= Gitlab::Utils.force_utf8(Devise.friendly_token[0, 8].downcase)
+ @password ||= Gitlab::Utils.force_utf8(::User.random_password.downcase)
end
def location
diff --git a/lib/gitlab/bitbucket_server_import/importer.rb b/lib/gitlab/bitbucket_server_import/importer.rb
index 886fbaaff48..16fe5b46b1f 100644
--- a/lib/gitlab/bitbucket_server_import/importer.rb
+++ b/lib/gitlab/bitbucket_server_import/importer.rb
@@ -172,6 +172,7 @@ module Gitlab
stage: 'import_pull_requests', iid: pull_request.iid, error: e.message
)
+ backtrace = Gitlab::BacktraceCleaner.clean_backtrace(e.backtrace)
errors << { type: :pull_request, iid: pull_request.iid, errors: e.message, backtrace: backtrace.join("\n"), raw_response: pull_request.raw }
end
end
diff --git a/lib/gitlab/middleware/read_only/controller.rb b/lib/gitlab/middleware/read_only/controller.rb
index b18f0eed1fa..c749816cf6a 100644
--- a/lib/gitlab/middleware/read_only/controller.rb
+++ b/lib/gitlab/middleware/read_only/controller.rb
@@ -24,6 +24,10 @@ module Gitlab
'projects/compare' => %w{create}
}.freeze
+ WHITELISTED_LOGOUT_ROUTES = {
+ 'sessions' => %w{destroy}
+ }.freeze
+
GRAPHQL_URL = '/api/graphql'
def initialize(app, env)
@@ -85,7 +89,7 @@ module Gitlab
# Overridden in EE module
def whitelisted_routes
- grack_route? || internal_route? || lfs_route? || compare_git_revisions_route? || sidekiq_route? || graphql_query?
+ grack_route? || internal_route? || lfs_route? || compare_git_revisions_route? || sidekiq_route? || logout_route? || graphql_query?
end
def grack_route?
@@ -118,6 +122,13 @@ module Gitlab
WHITELISTED_GIT_LFS_ROUTES[route_hash[:controller]]&.include?(route_hash[:action])
end
+ def logout_route?
+ # Calling route_hash may be expensive. Only do it if we think there's a possible match
+ return false unless request.post? && request.path.end_with?('/users/sign_out')
+
+ WHITELISTED_LOGOUT_ROUTES[route_hash[:controller]]&.include?(route_hash[:action])
+ end
+
def sidekiq_route?
request.path.start_with?("#{relative_url}/admin/sidekiq")
end
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index 04ce92d64ec..bc0717560d0 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -6295,15 +6295,9 @@ msgstr ""
msgid "Deselect all"
msgstr ""
-msgid "Design Management"
-msgstr ""
-
msgid "Design Management files and data"
msgstr ""
-msgid "Design Sync Not Enabled"
-msgstr ""
-
msgid "DesignManagement|%{current_design} of %{designs_count}"
msgstr ""
@@ -8065,6 +8059,11 @@ msgstr ""
msgid "Fetching licenses failed. You are not permitted to perform this action."
msgstr ""
+msgid "File"
+msgid_plural "Files"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "File Hooks"
msgstr ""
@@ -8407,9 +8406,6 @@ msgstr ""
msgid "Geo Settings"
msgstr ""
-msgid "Geo Troubleshooting"
-msgstr ""
-
msgid "Geo allows you to replicate your GitLab instance to other geographical locations."
msgstr ""
@@ -9879,9 +9875,6 @@ msgstr ""
msgid "If you believe this may be an error, please refer to the %{linkStart}Geo Troubleshooting%{linkEnd} documentation for more information."
msgstr ""
-msgid "If you believe this page to be an error, check out the links below for more information."
-msgstr ""
-
msgid "If you lose your recovery codes you can generate new ones, invalidating all previous codes."
msgstr ""
@@ -11639,10 +11632,10 @@ msgstr ""
msgid "MergeRequest|Error loading full diff. Please try again."
msgstr ""
-msgid "MergeRequest|No files found"
+msgid "MergeRequest|Filter files or search with %{modifier_key}+p"
msgstr ""
-msgid "MergeRequest|Search files (%{modifier_key}P)"
+msgid "MergeRequest|No files found"
msgstr ""
msgid "Merged"
@@ -21719,9 +21712,6 @@ msgstr ""
msgid "among other things"
msgstr ""
-msgid "and"
-msgstr ""
-
msgid "archived"
msgstr ""
@@ -22149,11 +22139,6 @@ msgstr ""
msgid "failed to dismiss associated finding(id=%{finding_id}): %{message}"
msgstr ""
-msgid "file"
-msgid_plural "files"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "finding is not found or is already attached to a vulnerability"
msgstr ""
@@ -22738,6 +22723,9 @@ msgstr[1] ""
msgid "reset it."
msgstr ""
+msgid "resolved the corresponding error and closed the issue."
+msgstr ""
+
msgid "score"
msgstr ""
diff --git a/spec/controllers/projects/error_tracking_controller_spec.rb b/spec/controllers/projects/error_tracking_controller_spec.rb
index 588c4b05528..22826938de2 100644
--- a/spec/controllers/projects/error_tracking_controller_spec.rb
+++ b/spec/controllers/projects/error_tracking_controller_spec.rb
@@ -301,7 +301,7 @@ describe Projects::ErrorTrackingController do
context 'update result is successful' do
before do
expect(issue_update_service).to receive(:execute)
- .and_return(status: :success, updated: true)
+ .and_return(status: :success, updated: true, closed_issue_iid: 1234)
update_issue
end
diff --git a/spec/features/merge_request/user_sees_versions_spec.rb b/spec/features/merge_request/user_sees_versions_spec.rb
index cd62bab412a..cab86f3fd94 100644
--- a/spec/features/merge_request/user_sees_versions_spec.rb
+++ b/spec/features/merge_request/user_sees_versions_spec.rb
@@ -50,7 +50,7 @@ describe 'Merge request > User sees versions', :js do
expect(page).to have_content 'latest version'
end
- expect(page).to have_content '8 files'
+ expect(page).to have_content '8 Files'
end
it_behaves_like 'allows commenting',
@@ -84,7 +84,7 @@ describe 'Merge request > User sees versions', :js do
end
it 'shows comments that were last relevant at that version' do
- expect(page).to have_content '5 files'
+ expect(page).to have_content '5 Files'
position = Gitlab::Diff::Position.new(
old_path: ".gitmodules",
@@ -128,10 +128,12 @@ describe 'Merge request > User sees versions', :js do
diff_id: merge_request_diff3.id,
start_sha: '6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9'
)
- expect(page).to have_content '4 files'
+ expect(page).to have_content '4 Files'
- additions_content = page.find('.diff-stats.is-compare-versions-header .diff-stats-group .js-file-addition-line').text
- deletions_content = page.find('.diff-stats.is-compare-versions-header .diff-stats-group .js-file-deletion-line').text
+ additions_content = page.find('.diff-stats.is-compare-versions-header .diff-stats-group svg.ic-file-addition')
+ .ancestor('.diff-stats-group').text
+ deletions_content = page.find('.diff-stats.is-compare-versions-header .diff-stats-group svg.ic-file-deletion')
+ .ancestor('.diff-stats-group').text
expect(additions_content).to eq '15'
expect(deletions_content).to eq '6'
@@ -154,10 +156,12 @@ describe 'Merge request > User sees versions', :js do
end
it 'show diff between new and old version' do
- additions_content = page.find('.diff-stats.is-compare-versions-header .diff-stats-group .js-file-addition-line').text
- deletions_content = page.find('.diff-stats.is-compare-versions-header .diff-stats-group .js-file-deletion-line').text
+ additions_content = page.find('.diff-stats.is-compare-versions-header .diff-stats-group svg.ic-file-addition')
+ .ancestor('.diff-stats-group').text
+ deletions_content = page.find('.diff-stats.is-compare-versions-header .diff-stats-group svg.ic-file-deletion')
+ .ancestor('.diff-stats-group').text
- expect(page).to have_content '4 files'
+ expect(page).to have_content '4 Files'
expect(additions_content).to eq '15'
expect(deletions_content).to eq '6'
end
@@ -167,7 +171,7 @@ describe 'Merge request > User sees versions', :js do
page.within '.mr-version-dropdown' do
expect(page).to have_content 'latest version'
end
- expect(page).to have_content '8 files'
+ expect(page).to have_content '8 Files'
end
it_behaves_like 'allows commenting',
@@ -193,7 +197,7 @@ describe 'Merge request > User sees versions', :js do
find('.btn-default').click
click_link 'version 1'
end
- expect(page).to have_content '0 files'
+ expect(page).to have_content '0 Files'
end
end
@@ -219,7 +223,7 @@ describe 'Merge request > User sees versions', :js do
expect(page).to have_content 'version 1'
end
- expect(page).to have_content '0 files'
+ expect(page).to have_content '0 Files'
end
end
diff --git a/spec/features/users/logout_spec.rb b/spec/features/users/logout_spec.rb
index 64202776b9b..a72a42c738d 100644
--- a/spec/features/users/logout_spec.rb
+++ b/spec/features/users/logout_spec.rb
@@ -21,4 +21,16 @@ describe 'Logout/Sign out', :js do
expect(page).not_to have_selector('.flash-notice')
end
+
+ context 'on a read-only instance' do
+ before do
+ allow(Gitlab::Database).to receive(:read_only?).and_return(true)
+ end
+
+ it 'sign out redirects to sign in page' do
+ gitlab_sign_out
+
+ expect(current_path).to eq new_user_session_path
+ end
+ end
end
diff --git a/spec/fixtures/api/schemas/error_tracking/update_issue.json b/spec/fixtures/api/schemas/error_tracking/update_issue.json
index 72514ce647d..75f2c1152d9 100644
--- a/spec/fixtures/api/schemas/error_tracking/update_issue.json
+++ b/spec/fixtures/api/schemas/error_tracking/update_issue.json
@@ -6,9 +6,15 @@
"properties" : {
"result": {
"type": "object",
+ "required" : [
+ "status",
+ "updated",
+ "closed_issue_iid"
+ ],
"properties": {
"status": { "type": "string" },
- "updated": { "type": "boolean" }
+ "updated": { "type": "boolean" },
+ "closed_issue_iid": { "type": ["integer", "null"] }
}
}
},
diff --git a/spec/frontend/diffs/components/compare_versions_spec.js b/spec/frontend/diffs/components/compare_versions_spec.js
index ff92a12eaf6..5f919408459 100644
--- a/spec/frontend/diffs/components/compare_versions_spec.js
+++ b/spec/frontend/diffs/components/compare_versions_spec.js
@@ -49,7 +49,8 @@ describe('CompareVersions', () => {
expect(treeListBtn.exists()).toBe(true);
expect(treeListBtn.attributes('title')).toBe('Hide file browser');
- expect(treeListBtn.find(Icon).props('name')).toBe('file-tree');
+ expect(treeListBtn.findAll(Icon).length).not.toBe(0);
+ expect(treeListBtn.find(Icon).props('name')).toBe('collapse-left');
});
it('should render comparison dropdowns with correct values', () => {
diff --git a/spec/frontend/diffs/components/diff_stats_spec.js b/spec/frontend/diffs/components/diff_stats_spec.js
index aa5c7f6278a..4482abf18c1 100644
--- a/spec/frontend/diffs/components/diff_stats_spec.js
+++ b/spec/frontend/diffs/components/diff_stats_spec.js
@@ -1,4 +1,5 @@
import { shallowMount } from '@vue/test-utils';
+import Icon from '~/vue_shared/components/icon.vue';
import DiffStats from '~/diffs/components/diff_stats.vue';
describe('diff_stats', () => {
@@ -23,11 +24,18 @@ describe('diff_stats', () => {
},
});
- const findFileLine = name => wrapper.find(name);
- const additions = findFileLine('.js-file-addition-line');
- const deletions = findFileLine('.js-file-deletion-line');
+ const findIcon = name =>
+ wrapper
+ .findAll(Icon)
+ .filter(c => c.attributes('name') === name)
+ .at(0).element.parentNode;
- expect(additions.text()).toBe('100');
- expect(deletions.text()).toBe('200');
+ const additions = findIcon('file-addition');
+ const deletions = findIcon('file-deletion');
+ const filesChanged = findIcon('doc-code');
+
+ expect(additions.textContent).toContain('100');
+ expect(deletions.textContent).toContain('200');
+ expect(filesChanged.textContent).toContain('300');
});
});
diff --git a/spec/frontend/vue_shared/components/changed_file_icon_spec.js b/spec/frontend/vue_shared/components/changed_file_icon_spec.js
index 02c4dabeffc..5d2aec6734f 100644
--- a/spec/frontend/vue_shared/components/changed_file_icon_spec.js
+++ b/spec/frontend/vue_shared/components/changed_file_icon_spec.js
@@ -56,10 +56,10 @@ describe('Changed file icon', () => {
describe.each`
file | iconName | tooltipText | desc
- ${changedFile()} | ${'file-modified-solid'} | ${'Unstaged modification'} | ${'with file changed'}
+ ${changedFile()} | ${'file-modified'} | ${'Unstaged modification'} | ${'with file changed'}
${stagedFile()} | ${'file-modified-solid'} | ${'Staged modification'} | ${'with file staged'}
- ${changedAndStagedFile()} | ${'file-modified-solid'} | ${'Unstaged and staged modification'} | ${'with file changed and staged'}
- ${newFile()} | ${'file-addition-solid'} | ${'Unstaged addition'} | ${'with file new'}
+ ${changedAndStagedFile()} | ${'file-modified'} | ${'Unstaged and staged modification'} | ${'with file changed and staged'}
+ ${newFile()} | ${'file-addition'} | ${'Unstaged addition'} | ${'with file new'}
`('$desc', ({ file, iconName, tooltipText }) => {
beforeEach(() => {
factory({ file });
diff --git a/spec/javascripts/ide/components/repo_tab_spec.js b/spec/javascripts/ide/components/repo_tab_spec.js
index 7466ed5468b..3b52f279bf2 100644
--- a/spec/javascripts/ide/components/repo_tab_spec.js
+++ b/spec/javascripts/ide/components/repo_tab_spec.js
@@ -93,13 +93,13 @@ describe('RepoTab', () => {
Vue.nextTick()
.then(() => {
- expect(vm.$el.querySelector('.file-modified-solid')).toBeNull();
+ expect(vm.$el.querySelector('.file-modified')).toBeNull();
vm.$el.dispatchEvent(new Event('mouseout'));
})
.then(Vue.nextTick)
.then(() => {
- expect(vm.$el.querySelector('.file-modified-solid')).not.toBeNull();
+ expect(vm.$el.querySelector('.file-modified')).not.toBeNull();
done();
})
diff --git a/spec/lib/gitlab/auth/ldap/user_spec.rb b/spec/lib/gitlab/auth/ldap/user_spec.rb
index bc09de7b525..071d687b2bf 100644
--- a/spec/lib/gitlab/auth/ldap/user_spec.rb
+++ b/spec/lib/gitlab/auth/ldap/user_spec.rb
@@ -139,6 +139,18 @@ describe Gitlab::Auth::LDAP::User do
expect(gl_user).to be_confirmed
end
end
+
+ context 'when the current minimum password length is different from the default minimum password length' do
+ before do
+ stub_application_setting minimum_password_length: 21
+ end
+
+ it 'creates the user' do
+ ldap_user.save
+
+ expect(gl_user).to be_persisted
+ end
+ end
end
describe 'updating email' do
diff --git a/spec/lib/gitlab/auth/o_auth/user_spec.rb b/spec/lib/gitlab/auth/o_auth/user_spec.rb
index c621c0aa935..022a544395e 100644
--- a/spec/lib/gitlab/auth/o_auth/user_spec.rb
+++ b/spec/lib/gitlab/auth/o_auth/user_spec.rb
@@ -86,6 +86,20 @@ describe Gitlab::Auth::OAuth::User do
end
end
+ context 'when the current minimum password length is different from the default minimum password length' do
+ before do
+ stub_application_setting minimum_password_length: 21
+ end
+
+ it 'creates the user' do
+ stub_omniauth_config(allow_single_sign_on: [provider])
+
+ oauth_user.save
+
+ expect(gl_user).to be_persisted
+ end
+ end
+
it 'marks user as having password_automatically_set' do
stub_omniauth_config(allow_single_sign_on: [provider], external_providers: [provider])
diff --git a/spec/lib/gitlab/auth/saml/user_spec.rb b/spec/lib/gitlab/auth/saml/user_spec.rb
index 5546438b7ee..4c400636ddf 100644
--- a/spec/lib/gitlab/auth/saml/user_spec.rb
+++ b/spec/lib/gitlab/auth/saml/user_spec.rb
@@ -325,6 +325,18 @@ describe Gitlab::Auth::Saml::User do
expect(gl_user).to be_confirmed
end
end
+
+ context 'when the current minimum password length is different from the default minimum password length' do
+ before do
+ stub_application_setting minimum_password_length: 21
+ end
+
+ it 'creates the user' do
+ saml_user.save
+
+ expect(gl_user).to be_persisted
+ end
+ end
end
describe 'blocking' do
diff --git a/spec/lib/gitlab/bitbucket_server_import/importer_spec.rb b/spec/lib/gitlab/bitbucket_server_import/importer_spec.rb
index 8ab7b2c5fa7..cf39d2cb753 100644
--- a/spec/lib/gitlab/bitbucket_server_import/importer_spec.rb
+++ b/spec/lib/gitlab/bitbucket_server_import/importer_spec.rb
@@ -67,6 +67,7 @@ describe Gitlab::BitbucketServerImport::Importer do
author_email: project.owner.email,
created_at: Time.now,
updated_at: Time.now,
+ raw: {},
merged?: true)
allow(subject.client).to receive(:pull_requests).and_return([pull_request])
@@ -239,6 +240,13 @@ describe Gitlab::BitbucketServerImport::Importer do
expect(notes.first.note).to start_with('*Comment on .gitmodules')
expect(notes.second.note).to start_with('*Comment on .gitmodules')
end
+
+ it 'reports an error if an exception is raised' do
+ allow(subject).to receive(:import_bitbucket_pull_request).and_raise(RuntimeError)
+ expect(Gitlab::ErrorTracking).to receive(:log_exception)
+
+ subject.execute
+ end
end
describe 'inaccessible branches' do
diff --git a/spec/migrations/20200123155929_remove_invalid_jira_data_spec.rb b/spec/migrations/20200123155929_remove_invalid_jira_data_spec.rb
new file mode 100644
index 00000000000..0e640623ea9
--- /dev/null
+++ b/spec/migrations/20200123155929_remove_invalid_jira_data_spec.rb
@@ -0,0 +1,70 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+require Rails.root.join('db', 'post_migrate', '20200123155929_remove_invalid_jira_data.rb')
+
+describe RemoveInvalidJiraData, :migration do
+ let(:jira_tracker_data) { table(:jira_tracker_data) }
+ let(:services) { table(:services) }
+
+ let(:service) { services.create(id: 1) }
+ let(:data) do
+ {
+ service_id: service.id,
+ encrypted_api_url: 'http:url.com',
+ encrypted_api_url_iv: 'somevalue',
+ encrypted_url: 'http:url.com',
+ encrypted_url_iv: 'somevalue',
+ encrypted_username: 'username',
+ encrypted_username_iv: 'somevalue',
+ encrypted_password: 'username',
+ encrypted_password_iv: 'somevalue'
+ }
+ end
+
+ let!(:valid_data) { jira_tracker_data.create(data) }
+ let!(:empty_data) { jira_tracker_data.create(service_id: service.id) }
+ let!(:invalid_api_url) do
+ data[:encrypted_api_url_iv] = nil
+ jira_tracker_data.create(data)
+ end
+ let!(:missing_api_url) do
+ data[:encrypted_api_url] = ''
+ data[:encrypted_api_url_iv] = nil
+ jira_tracker_data.create(data)
+ end
+ let!(:invalid_url) do
+ data[:encrypted_url_iv] = nil
+ jira_tracker_data.create(data)
+ end
+ let!(:missing_url) do
+ data[:encrypted_url] = ''
+ jira_tracker_data.create(data)
+ end
+ let!(:invalid_username) do
+ data[:encrypted_username_iv] = nil
+ jira_tracker_data.create(data)
+ end
+ let!(:missing_username) do
+ data[:encrypted_username] = nil
+ data[:encrypted_username_iv] = nil
+ jira_tracker_data.create(data)
+ end
+ let!(:invalid_password) do
+ data[:encrypted_password_iv] = nil
+ jira_tracker_data.create(data)
+ end
+ let!(:missing_password) do
+ data[:encrypted_password] = nil
+ data[:encrypted_username_iv] = nil
+ jira_tracker_data.create(data)
+ end
+
+ it 'removes the invalid data' do
+ valid_data_records = [valid_data, empty_data, missing_api_url, missing_url, missing_username, missing_password]
+
+ expect { migrate! }.to change { jira_tracker_data.count }.from(10).to(6)
+
+ expect(jira_tracker_data.all).to match_array(valid_data_records)
+ end
+end
diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb
index 5620f211d9c..6f393d169a2 100644
--- a/spec/models/user_spec.rb
+++ b/spec/models/user_spec.rb
@@ -508,6 +508,20 @@ describe User, :do_not_mock_admin_mode do
end
end
+ describe '.random_password' do
+ let(:random_password) { described_class.random_password }
+
+ before do
+ expect(User).to receive(:password_length).and_return(88..128)
+ end
+
+ context 'length' do
+ it 'conforms to the current password length settings' do
+ expect(random_password.length).to eq(128)
+ end
+ end
+ end
+
describe '.password_length' do
let(:password_length) { described_class.password_length }
diff --git a/spec/services/error_tracking/issue_details_service_spec.rb b/spec/services/error_tracking/issue_details_service_spec.rb
index 4d5505bb5a9..26bb3b44126 100644
--- a/spec/services/error_tracking/issue_details_service_spec.rb
+++ b/spec/services/error_tracking/issue_details_service_spec.rb
@@ -3,24 +3,7 @@
require 'spec_helper'
describe ErrorTracking::IssueDetailsService do
- let_it_be(:user) { create(:user) }
- let_it_be(:project) { create(:project) }
-
- let(:sentry_url) { 'https://sentrytest.gitlab.com/api/0/projects/sentry-org/sentry-project' }
- let(:token) { 'test-token' }
- let(:result) { subject.execute }
-
- let(:error_tracking_setting) do
- create(:project_error_tracking_setting, api_url: sentry_url, token: token, project: project)
- end
-
- subject { described_class.new(project, user) }
-
- before do
- expect(project).to receive(:error_tracking_setting).at_least(:once).and_return(error_tracking_setting)
-
- project.add_reporter(user)
- end
+ include_context 'sentry error tracking context'
describe '#execute' do
context 'with authorized user' do
diff --git a/spec/services/error_tracking/issue_latest_event_service_spec.rb b/spec/services/error_tracking/issue_latest_event_service_spec.rb
index cda15042814..7f53eabd717 100644
--- a/spec/services/error_tracking/issue_latest_event_service_spec.rb
+++ b/spec/services/error_tracking/issue_latest_event_service_spec.rb
@@ -3,24 +3,7 @@
require 'spec_helper'
describe ErrorTracking::IssueLatestEventService do
- let_it_be(:user) { create(:user) }
- let_it_be(:project) { create(:project) }
-
- let(:sentry_url) { 'https://sentrytest.gitlab.com/api/0/projects/sentry-org/sentry-project' }
- let(:token) { 'test-token' }
- let(:result) { subject.execute }
-
- let(:error_tracking_setting) do
- create(:project_error_tracking_setting, api_url: sentry_url, token: token, project: project)
- end
-
- subject { described_class.new(project, user) }
-
- before do
- expect(project).to receive(:error_tracking_setting).at_least(:once).and_return(error_tracking_setting)
-
- project.add_reporter(user)
- end
+ include_context 'sentry error tracking context'
describe '#execute' do
context 'with authorized user' do
diff --git a/spec/services/error_tracking/issue_update_service_spec.rb b/spec/services/error_tracking/issue_update_service_spec.rb
new file mode 100644
index 00000000000..ad1dafe6ccc
--- /dev/null
+++ b/spec/services/error_tracking/issue_update_service_spec.rb
@@ -0,0 +1,106 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe ErrorTracking::IssueUpdateService do
+ include_context 'sentry error tracking context'
+
+ let(:arguments) { { issue_id: 1234, status: 'resolved' } }
+
+ subject { described_class.new(project, user, arguments) }
+
+ shared_examples 'does not perform close issue flow' do
+ it 'does not call the close issue service' do
+ expect(issue_close_service)
+ .not_to receive(:execute)
+ end
+
+ it 'does not create system note' do
+ expect(SystemNoteService).not_to receive(:close_after_error_tracking_resolve)
+ end
+ end
+
+ describe '#execute' do
+ context 'with authorized user' do
+ context 'when update_issue returns success' do
+ let(:update_issue_response) { { updated: true } }
+
+ before do
+ expect(error_tracking_setting)
+ .to receive(:update_issue).and_return(update_issue_response)
+ end
+
+ it 'returns the response' do
+ expect(result).to eq(update_issue_response.merge(status: :success, closed_issue_iid: nil))
+ end
+
+ it 'updates any related issue' do
+ expect(subject).to receive(:update_related_issue)
+
+ result
+ end
+
+ context 'related issue and resolving' do
+ let(:issue) { create(:issue, project: project) }
+ let(:sentry_issue) { create(:sentry_issue, issue: issue) }
+ let(:arguments) { { issue_id: sentry_issue.sentry_issue_identifier, status: 'resolved' } }
+
+ let(:issue_close_service) { spy(:issue_close_service) }
+
+ before do
+ allow_any_instance_of(SentryIssueFinder)
+ .to receive(:execute)
+ .and_return(sentry_issue)
+
+ allow(Issues::CloseService)
+ .to receive(:new)
+ .and_return(issue_close_service)
+ end
+
+ after do
+ result
+ end
+
+ it 'closes the issue' do
+ expect(issue_close_service)
+ .to receive(:execute)
+ .with(issue, system_note: false)
+ .and_return(issue)
+ end
+
+ it 'creates a system note' do
+ expect(SystemNoteService).to receive(:close_after_error_tracking_resolve)
+ end
+
+ it 'returns a response with closed issue' do
+ closed_issue = create(:issue, :closed, project: project)
+
+ expect(issue_close_service)
+ .to receive(:execute)
+ .with(issue, system_note: false)
+ .and_return(closed_issue)
+
+ expect(result).to eq(status: :success, updated: true, closed_issue_iid: closed_issue.iid)
+ end
+
+ context 'issue is already closed' do
+ let(:issue) { create(:issue, :closed, project: project) }
+
+ include_examples 'does not perform close issue flow'
+ end
+
+ context 'status is not resolving' do
+ let(:arguments) { { issue_id: sentry_issue.sentry_issue_identifier, status: 'ignored' } }
+
+ include_examples 'does not perform close issue flow'
+ end
+ end
+ end
+
+ include_examples 'error tracking service sentry error handling', :update_issue
+ end
+
+ include_examples 'error tracking service unauthorized user'
+ include_examples 'error tracking service disabled'
+ end
+end
diff --git a/spec/services/error_tracking/list_issues_service_spec.rb b/spec/services/error_tracking/list_issues_service_spec.rb
index ecb6bcc541b..1e39146fd18 100644
--- a/spec/services/error_tracking/list_issues_service_spec.rb
+++ b/spec/services/error_tracking/list_issues_service_spec.rb
@@ -3,8 +3,8 @@
require 'spec_helper'
describe ErrorTracking::ListIssuesService do
- let_it_be(:user) { create(:user) }
- let_it_be(:project) { create(:project) }
+ include_context 'sentry error tracking context'
+
let(:params) { { search_term: 'something', sort: 'last_seen', cursor: 'some-cursor' } }
let(:list_sentry_issues_args) do
{
@@ -16,22 +16,8 @@ describe ErrorTracking::ListIssuesService do
}
end
- let(:sentry_url) { 'https://sentrytest.gitlab.com/api/0/projects/sentry-org/sentry-project' }
- let(:token) { 'test-token' }
- let(:result) { subject.execute }
-
- let(:error_tracking_setting) do
- create(:project_error_tracking_setting, api_url: sentry_url, token: token, project: project)
- end
-
subject { described_class.new(project, user, params) }
- before do
- expect(project).to receive(:error_tracking_setting).at_least(:once).and_return(error_tracking_setting)
-
- project.add_reporter(user)
- end
-
describe '#execute' do
context 'with authorized user' do
context 'when list_sentry_issues returns issues' do
diff --git a/spec/services/pages_domains/create_acme_order_service_spec.rb b/spec/services/pages_domains/create_acme_order_service_spec.rb
index 154b3fd5600..d59aa9b979e 100644
--- a/spec/services/pages_domains/create_acme_order_service_spec.rb
+++ b/spec/services/pages_domains/create_acme_order_service_spec.rb
@@ -45,34 +45,12 @@ describe PagesDomains::CreateAcmeOrderService do
expect { OpenSSL::PKey::RSA.new(saved_order.private_key) }.not_to raise_error
end
- it 'properly saves order url' do
+ it 'properly saves order attributes' do
service.execute
saved_order = PagesDomainAcmeOrder.last
expect(saved_order.url).to eq(order_double.url)
- end
-
- context 'when order expires in 2 days' do
- it 'sets expiration time in 2 hours' do
- Timecop.freeze do
- service.execute
-
- saved_order = PagesDomainAcmeOrder.last
- expect(saved_order.expires_at).to be_like_time(2.hours.from_now)
- end
- end
- end
-
- context 'when order expires in an hour' do
- it 'sets expiration time accordingly to order' do
- Timecop.freeze do
- allow(order_double).to receive(:expires).and_return(1.hour.from_now)
- service.execute
-
- saved_order = PagesDomainAcmeOrder.last
- expect(saved_order.expires_at).to be_like_time(1.hour.from_now)
- end
- end
+ expect(saved_order.expires_at).to be_like_time(order_double.expires)
end
it 'properly saves challenge attributes' do
diff --git a/spec/support/shared_contexts/sentry_error_tracking_shared_context.rb b/spec/support/shared_contexts/sentry_error_tracking_shared_context.rb
new file mode 100644
index 00000000000..ba729f21e58
--- /dev/null
+++ b/spec/support/shared_contexts/sentry_error_tracking_shared_context.rb
@@ -0,0 +1,22 @@
+# frozen_string_literal: true
+
+shared_context 'sentry error tracking context' do
+ let_it_be(:user) { create(:user) }
+ let_it_be(:project) { create(:project) }
+
+ let(:sentry_url) { 'https://sentrytest.gitlab.com/api/0/projects/sentry-org/sentry-project' }
+ let(:token) { 'test-token' }
+ let(:result) { subject.execute }
+
+ subject { described_class.new(project, user) }
+
+ let(:error_tracking_setting) do
+ create(:project_error_tracking_setting, api_url: sentry_url, token: token, project: project)
+ end
+
+ before do
+ expect(project).to receive(:error_tracking_setting).at_least(:once).and_return(error_tracking_setting)
+
+ project.add_reporter(user)
+ end
+end