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:
-rw-r--r--.gitignore1
-rw-r--r--.gitlab/CODEOWNERS (renamed from .gitlab/CODEOWNERS.disabled)4
-rw-r--r--Gemfile2
-rw-r--r--Gemfile.lock12
-rw-r--r--app/assets/images/favicon-yellow.pngbin1667 -> 1481 bytes
-rw-r--r--app/assets/javascripts/batch_comments/mixins/resolved_status.js6
-rw-r--r--app/assets/javascripts/lib/graphql.js8
-rw-r--r--app/assets/javascripts/lib/utils/datetime_utility.js28
-rw-r--r--app/assets/javascripts/lib/utils/number_utils.js9
-rw-r--r--app/assets/javascripts/monitoring/components/charts/area.vue16
-rw-r--r--app/assets/javascripts/notes/components/note_actions.vue9
-rw-r--r--app/assets/javascripts/notes/components/note_awards_list.vue6
-rw-r--r--app/assets/javascripts/repository/components/table/index.vue103
-rw-r--r--app/assets/javascripts/repository/components/table/row.vue20
-rw-r--r--app/assets/javascripts/repository/fragmentTypes.json1
-rw-r--r--app/assets/javascripts/repository/graphql.js65
-rw-r--r--app/assets/javascripts/repository/queries/getFiles.graphql58
-rw-r--r--app/assets/javascripts/repository/queries/getProjectPath.graphql3
-rw-r--r--app/assets/javascripts/repository/router.js12
-rw-r--r--app/assets/javascripts/repository/utils/icon.js2
-rw-r--r--app/assets/javascripts/search_autocomplete.js1
-rw-r--r--app/assets/javascripts/set_status_modal/set_status_modal_wrapper.vue6
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/deployment.vue2
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/mr_widget_pipeline_container.vue2
-rw-r--r--app/assets/javascripts/vue_shared/components/user_popover/user_popover.vue10
-rw-r--r--app/assets/stylesheets/components/avatar.scss (renamed from app/assets/stylesheets/framework/avatar.scss)68
-rw-r--r--app/assets/stylesheets/framework.scss1
-rw-r--r--app/assets/stylesheets/framework/awards.scss5
-rw-r--r--app/assets/stylesheets/framework/files.scss1
-rw-r--r--app/assets/stylesheets/framework/filters.scss2
-rw-r--r--app/assets/stylesheets/framework/forms.scss4
-rw-r--r--app/assets/stylesheets/framework/highlight.scss3
-rw-r--r--app/assets/stylesheets/framework/mixins.scss9
-rw-r--r--app/assets/stylesheets/framework/variables.scss1
-rw-r--r--app/assets/stylesheets/framework/variables_overrides.scss1
-rw-r--r--app/assets/stylesheets/pages/detail_page.scss1
-rw-r--r--app/assets/stylesheets/pages/diff.scss6
-rw-r--r--app/assets/stylesheets/pages/events.scss4
-rw-r--r--app/assets/stylesheets/pages/login.scss7
-rw-r--r--app/models/clusters/applications/jupyter.rb9
-rw-r--r--app/models/clusters/cluster.rb20
-rw-r--r--app/models/identity.rb1
-rw-r--r--app/models/project_auto_devops.rb19
-rw-r--r--app/services/system_note_service.rb12
-rw-r--r--app/views/award_emoji/_awards_block.html.haml6
-rw-r--r--app/views/events/event/_push.html.haml3
-rw-r--r--app/views/issues/_issue.atom.builder1
-rw-r--r--app/views/layouts/devise.html.haml12
-rw-r--r--app/views/profiles/show.html.haml6
-rw-r--r--app/views/projects/buttons/_download_links.html.haml2
-rw-r--r--app/views/projects/commits/_commit.html.haml4
-rw-r--r--app/views/projects/notes/_actions.html.haml6
-rw-r--r--app/views/shared/icons/_emoji_slightly_smiling_face.svg1
-rw-r--r--app/views/shared/icons/_emoji_smile.svg1
-rw-r--r--app/views/shared/icons/_emoji_smiley.svg1
-rw-r--r--app/views/snippets/notes/_actions.html.haml6
-rw-r--r--changelogs/unreleased/13453_minimal_atom_fix.yml5
-rw-r--r--changelogs/unreleased/38561-border-radii.yml5
-rw-r--r--changelogs/unreleased/49041-issue-board-input-height.yml5
-rw-r--r--changelogs/unreleased/56959-remove-auto-devops-domain-ci-variable.yml5
-rw-r--r--changelogs/unreleased/59026-replace-favicon.yml5
-rw-r--r--changelogs/unreleased/59987-move-sign-in-2fa-on-users-sign_in-above-intro-content-on-mobile.yml5
-rw-r--r--changelogs/unreleased/60250-remove-mr_push_options-flag.yml5
-rw-r--r--changelogs/unreleased/60778-input-text-height.yml5
-rw-r--r--changelogs/unreleased/61049-links-activity-stream.yml5
-rw-r--r--changelogs/unreleased/61313-fix-dropdown-searchbar.yml5
-rw-r--r--changelogs/unreleased/61393-emoji-button.yml5
-rw-r--r--changelogs/unreleased/61827-prevent-user-popover-icon-shrink.yml5
-rw-r--r--changelogs/unreleased/61880-download-btn-group.yml5
-rw-r--r--changelogs/unreleased/62107-fix-detail-page-header-height.yml5
-rw-r--r--changelogs/unreleased/api_masked_variables.yml5
-rw-r--r--changelogs/unreleased/fix-import-member-access.yml5
-rw-r--r--changelogs/unreleased/fix-milestone-references-with-escaped-html-entities.yml5
-rw-r--r--changelogs/unreleased/jupyter_pre_spawn_hook_v2.yml5
-rw-r--r--changelogs/unreleased/patch-64.yml5
-rw-r--r--changelogs/unreleased/relative-urls-for-system-notes.yml5
-rw-r--r--changelogs/unreleased/sh-fix-omniauth-generic-strategy.yml5
-rw-r--r--changelogs/unreleased/update-smileys-new.yml5
-rw-r--r--config/database.yml.example0
-rw-r--r--config/initializers/rack_attack_logging.rb10
-rw-r--r--config/karma.config.js26
-rw-r--r--doc/administration/logs.md9
-rw-r--r--doc/api/epic_links.md3
-rw-r--r--doc/api/project_level_variables.md12
-rw-r--r--doc/ci/yaml/README.md2
-rw-r--r--doc/development/contributing/issue_workflow.md47
-rw-r--r--doc/development/fe_guide/style_guide_scss.md40
-rw-r--r--doc/development/i18n/externalization.md1
-rw-r--r--doc/development/migration_style_guide.md6
-rw-r--r--doc/security/rack_attack.md2
-rw-r--r--doc/topics/autodevops/index.md15
-rw-r--r--doc/user/admin_area/geo_nodes.md22
-rw-r--r--doc/user/admin_area/settings/continuous_integration.md16
-rw-r--r--doc/user/admin_area/settings/email.md24
-rw-r--r--doc/user/admin_area/settings/external_authorization.md16
-rw-r--r--doc/user/group/index.md204
-rw-r--r--doc/user/group/saml_sso/index.md10
-rw-r--r--doc/user/project/clusters/index.md87
-rw-r--r--doc/user/project/integrations/webhooks.md2
-rw-r--r--doc/user/project/quick_actions.md2
-rw-r--r--doc/user/project/settings/import_export.md1
-rw-r--r--lib/api/entities.rb1
-rw-r--r--lib/api/helpers/internal_helpers.rb2
-rw-r--r--lib/api/internal.rb8
-rw-r--r--lib/api/variables.rb2
-rw-r--r--lib/banzai/filter/abstract_reference_filter.rb8
-rw-r--r--lib/banzai/filter/label_reference_filter.rb8
-rw-r--r--lib/banzai/filter/milestone_reference_filter.rb4
-rw-r--r--lib/gitlab/auth_logger.rb9
-rw-r--r--lib/gitlab/ci/templates/Jobs/Deploy.gitlab-ci.yml12
-rw-r--r--lib/gitlab/ci/templates/Security/SAST.gitlab-ci.yml1
-rw-r--r--lib/gitlab/import_export/members_mapper.rb6
-rw-r--r--lib/gitlab/omniauth_initializer.rb15
-rw-r--r--lib/gitlab/quick_actions/issue_and_merge_request_actions.rb2
-rw-r--r--locale/gitlab.pot35
-rw-r--r--package.json4
-rw-r--r--public/visual-review-toolbar.js30
-rw-r--r--qa/docs/WRITING_TESTS_FROM_SCRATCH.md6
-rwxr-xr-xscripts/frontend/test.js114
-rw-r--r--spec/frontend/repository/components/table/__snapshots__/row_spec.js.snap2
-rw-r--r--spec/frontend/repository/components/table/index_spec.js51
-rw-r--r--spec/frontend/repository/components/table/row_spec.js18
-rw-r--r--spec/frontend/repository/utils/icon_spec.js2
-rw-r--r--spec/javascripts/jobs/components/job_app_spec.js5
-rw-r--r--spec/lib/banzai/filter/milestone_reference_filter_spec.rb21
-rw-r--r--spec/lib/gitlab/ci/config_spec.rb2
-rw-r--r--spec/lib/gitlab/import_export/members_mapper_spec.rb7
-rw-r--r--spec/lib/gitlab/omniauth_initializer_spec.rb22
-rw-r--r--spec/models/ci/build_spec.rb24
-rw-r--r--spec/models/clusters/cluster_spec.rb59
-rw-r--r--spec/models/project_auto_devops_spec.rb60
-rw-r--r--spec/models/project_spec.rb58
-rw-r--r--spec/requests/api/internal_spec.rb12
-rw-r--r--spec/requests/api/variables_spec.rb5
-rw-r--r--spec/requests/rack_attack_global_spec.rb22
-rw-r--r--spec/services/system_note_service_spec.rb4
-rw-r--r--vendor/jupyter/values.yaml20
-rw-r--r--yarn.lock190
138 files changed, 1233 insertions, 894 deletions
diff --git a/.gitignore b/.gitignore
index 627c806787b..cb718a6939f 100644
--- a/.gitignore
+++ b/.gitignore
@@ -79,3 +79,4 @@ package-lock.json
/junit_*.xml
/coverage-frontend/
jsdoc/
+**/tmp/rubocop_cache/** \ No newline at end of file
diff --git a/.gitlab/CODEOWNERS.disabled b/.gitlab/CODEOWNERS
index 52fb651f551..0156a4d749a 100644
--- a/.gitlab/CODEOWNERS.disabled
+++ b/.gitlab/CODEOWNERS
@@ -1,6 +1,6 @@
# Backend Maintainers are the default for all ruby files
-*.rb @ashmckenzie @ayufan @dbalexandre @DouweM @dzaporozhets @godfat @grzesiek @mkozono @nick.thomas @rspeicher @rymai @smcgivern @mayra-cabrera
-*.rake @ashmckenzie @ayufan @dbalexandre @DouweM @dzaporozhets @godfat @grzesiek @mkozono @nick.thomas @rspeicher @rymai @smcgivern @mayra-cabrera
+*.rb @ashmckenzie @ayufan @dbalexandre @DouweM @dzaporozhets @godfat @grzesiek @mkozono @nick.thomas @rspeicher @rymai @smcgivern @mayra-cabrera @reprazent
+*.rake @ashmckenzie @ayufan @dbalexandre @DouweM @dzaporozhets @godfat @grzesiek @mkozono @nick.thomas @rspeicher @rymai @smcgivern @mayra-cabrera @reprazent
# Technical writing team are the default reviewers for everything in `doc/`
/doc/ @axil @marcia
diff --git a/Gemfile b/Gemfile
index df2d2616ad3..fe56a0b4cc4 100644
--- a/Gemfile
+++ b/Gemfile
@@ -372,6 +372,7 @@ group :development, :test do
gem 'activerecord_sane_schema_dumper', '1.0'
gem 'stackprof', '~> 0.2.10', require: false
+ gem 'derailed_benchmarks', require: false
gem 'simple_po_parser', '~> 1.1.2', require: false
@@ -399,6 +400,7 @@ gem 'html2text'
gem 'ruby-prof', '~> 0.17.0'
gem 'rbtrace', '~> 0.4', require: false
+gem 'memory_profiler', require: false
# OAuth
gem 'oauth2', '~> 1.4'
diff --git a/Gemfile.lock b/Gemfile.lock
index 064413168f9..9a2411713c0 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -155,6 +155,14 @@ GEM
html-pipeline
declarative (0.0.10)
declarative-option (0.1.0)
+ derailed_benchmarks (1.3.5)
+ benchmark-ips (~> 2)
+ get_process_mem (~> 0)
+ heapy (~> 0)
+ memory_profiler (~> 0)
+ rack (>= 1)
+ rake (> 10, < 13)
+ thor (~> 0.19)
descendants_tracker (0.0.4)
thread_safe (~> 0.3, >= 0.3.1)
device_detector (1.0.0)
@@ -377,6 +385,7 @@ GEM
hashie (>= 3.0)
health_check (2.6.0)
rails (>= 4.0)
+ heapy (0.1.4)
hipchat (1.5.2)
httparty
mimemagic
@@ -478,6 +487,7 @@ GEM
memoist (0.16.0)
memoizable (0.4.2)
thread_safe (~> 0.3, >= 0.3.1)
+ memory_profiler (0.9.13)
method_source (0.9.2)
mime-types (3.2.2)
mime-types-data (~> 3.2015)
@@ -1034,6 +1044,7 @@ DEPENDENCIES
creole (~> 0.5.0)
database_cleaner (~> 1.7.0)
deckar01-task_list (= 2.2.0)
+ derailed_benchmarks
device_detector
devise (~> 4.6)
devise-two-factor (~> 3.0.0)
@@ -1111,6 +1122,7 @@ DEPENDENCIES
lograge (~> 0.5)
loofah (~> 2.2)
mail_room (~> 0.9.1)
+ memory_profiler
method_source (~> 0.8)
mimemagic (~> 0.3.2)
mini_magick
diff --git a/app/assets/images/favicon-yellow.png b/app/assets/images/favicon-yellow.png
index 2d5289818b4..a80827808fc 100644
--- a/app/assets/images/favicon-yellow.png
+++ b/app/assets/images/favicon-yellow.png
Binary files differ
diff --git a/app/assets/javascripts/batch_comments/mixins/resolved_status.js b/app/assets/javascripts/batch_comments/mixins/resolved_status.js
index 96ee9f62ba4..3bbbaa86b51 100644
--- a/app/assets/javascripts/batch_comments/mixins/resolved_status.js
+++ b/app/assets/javascripts/batch_comments/mixins/resolved_status.js
@@ -1,10 +1,12 @@
+import { sprintf, __ } from '~/locale';
+
export default {
computed: {
resolveButtonTitle() {
- let title = 'Mark comment as resolved';
+ let title = __('Mark comment as resolved');
if (this.resolvedBy) {
- title = `Resolved by ${this.resolvedBy.name}`;
+ title = sprintf(__('Resolved by %{name}'), { name: this.resolvedBy.name });
}
return title;
diff --git a/app/assets/javascripts/lib/graphql.js b/app/assets/javascripts/lib/graphql.js
index 498c2348ca2..47e91dedd5a 100644
--- a/app/assets/javascripts/lib/graphql.js
+++ b/app/assets/javascripts/lib/graphql.js
@@ -3,12 +3,12 @@ import { InMemoryCache } from 'apollo-cache-inmemory';
import { createUploadLink } from 'apollo-upload-client';
import csrf from '~/lib/utils/csrf';
-export default (resolvers = {}, baseUrl = '') => {
+export default (resolvers = {}, config = {}) => {
let uri = `${gon.relative_url_root}/api/graphql`;
- if (baseUrl) {
+ if (config.baseUrl) {
// Prepend baseUrl and ensure that `///` are replaced with `/`
- uri = `${baseUrl}${uri}`.replace(/\/{3,}/g, '/');
+ uri = `${config.baseUrl}${uri}`.replace(/\/{3,}/g, '/');
}
return new ApolloClient({
@@ -18,7 +18,7 @@ export default (resolvers = {}, baseUrl = '') => {
[csrf.headerKey]: csrf.token,
},
}),
- cache: new InMemoryCache(),
+ cache: new InMemoryCache(config.cacheConfig),
resolvers,
});
};
diff --git a/app/assets/javascripts/lib/utils/datetime_utility.js b/app/assets/javascripts/lib/utils/datetime_utility.js
index 4d6327840db..624878cb5d7 100644
--- a/app/assets/javascripts/lib/utils/datetime_utility.js
+++ b/app/assets/javascripts/lib/utils/datetime_utility.js
@@ -3,7 +3,7 @@ import _ from 'underscore';
import timeago from 'timeago.js';
import dateFormat from 'dateformat';
import { pluralize } from './text_utility';
-import { languageCode, s__ } from '../../locale';
+import { languageCode, s__, __ } from '../../locale';
window.timeago = timeago;
@@ -63,7 +63,15 @@ export const pad = (val, len = 2) => `0${val}`.slice(-len);
* @returns {String}
*/
export const getDayName = date =>
- ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'][date.getDay()];
+ [
+ __('Sunday'),
+ __('Monday'),
+ __('Tuesday'),
+ __('Wednesday'),
+ __('Thursday'),
+ __('Friday'),
+ __('Saturday'),
+ ][date.getDay()];
/**
* @example
@@ -320,13 +328,13 @@ export const getSundays = date => {
}
const daysToSunday = [
- 'Saturday',
- 'Friday',
- 'Thursday',
- 'Wednesday',
- 'Tuesday',
- 'Monday',
- 'Sunday',
+ __('Saturday'),
+ __('Friday'),
+ __('Thursday'),
+ __('Wednesday'),
+ __('Tuesday'),
+ __('Monday'),
+ __('Sunday'),
];
const month = date.getMonth();
@@ -336,7 +344,7 @@ export const getSundays = date => {
while (dateOfMonth.getMonth() === month) {
const dayName = getDayName(dateOfMonth);
- if (dayName === 'Sunday') {
+ if (dayName === __('Sunday')) {
sundays.push(new Date(dateOfMonth.getTime()));
}
diff --git a/app/assets/javascripts/lib/utils/number_utils.js b/app/assets/javascripts/lib/utils/number_utils.js
index 19c4de6083d..9ddfb4bca11 100644
--- a/app/assets/javascripts/lib/utils/number_utils.js
+++ b/app/assets/javascripts/lib/utils/number_utils.js
@@ -1,4 +1,5 @@
import { BYTES_IN_KIB } from './constants';
+import { sprintf, __ } from '~/locale';
/**
* Function that allows a number with an X amount of decimals
@@ -72,13 +73,13 @@ export function bytesToGiB(number) {
*/
export function numberToHumanSize(size) {
if (size < BYTES_IN_KIB) {
- return `${size} bytes`;
+ return sprintf(__('%{size} bytes'), { size });
} else if (size < BYTES_IN_KIB * BYTES_IN_KIB) {
- return `${bytesToKiB(size).toFixed(2)} KiB`;
+ return sprintf(__('%{size} KiB'), { size: bytesToKiB(size).toFixed(2) });
} else if (size < BYTES_IN_KIB * BYTES_IN_KIB * BYTES_IN_KIB) {
- return `${bytesToMiB(size).toFixed(2)} MiB`;
+ return sprintf(__('%{size} MiB'), { size: bytesToMiB(size).toFixed(2) });
}
- return `${bytesToGiB(size).toFixed(2)} GiB`;
+ return sprintf(__('%{size} GiB'), { size: bytesToGiB(size).toFixed(2) });
}
/**
diff --git a/app/assets/javascripts/monitoring/components/charts/area.vue b/app/assets/javascripts/monitoring/components/charts/area.vue
index afe8d87a8d6..c43791f2426 100644
--- a/app/assets/javascripts/monitoring/components/charts/area.vue
+++ b/app/assets/javascripts/monitoring/components/charts/area.vue
@@ -125,17 +125,17 @@ export default {
},
earliestDatapoint() {
return this.chartData.reduce((acc, series) => {
- if (!series.data.length) {
+ const { data } = series;
+ const { length } = data;
+ if (!length) {
return acc;
}
- const [[timestamp]] = series.data.sort(([a], [b]) => {
- if (a < b) {
- return -1;
- }
- return a > b ? 1 : 0;
- });
- return timestamp < acc || acc === null ? timestamp : acc;
+ const [first] = data[0];
+ const [last] = data[length - 1];
+ const seriesEarliest = first < last ? first : last;
+
+ return seriesEarliest < acc || acc === null ? seriesEarliest : acc;
}, null);
},
isMultiSeries() {
diff --git a/app/assets/javascripts/notes/components/note_actions.vue b/app/assets/javascripts/notes/components/note_actions.vue
index 7e8f23d6a96..5a4ff15d198 100644
--- a/app/assets/javascripts/notes/components/note_actions.vue
+++ b/app/assets/javascripts/notes/components/note_actions.vue
@@ -148,12 +148,9 @@ export default {
href="#"
title="Add reaction"
>
- <icon
- css-classes="link-highlight award-control-icon-neutral"
- name="emoji_slightly_smiling_face"
- />
- <icon css-classes="link-highlight award-control-icon-positive" name="emoji_smiley" />
- <icon css-classes="link-highlight award-control-icon-super-positive" name="emoji_smiley" />
+ <icon css-classes="link-highlight award-control-icon-neutral" name="slight-smile" />
+ <icon css-classes="link-highlight award-control-icon-positive" name="smiley" />
+ <icon css-classes="link-highlight award-control-icon-super-positive" name="smiley" />
</a>
</div>
<reply-button
diff --git a/app/assets/javascripts/notes/components/note_awards_list.vue b/app/assets/javascripts/notes/components/note_awards_list.vue
index 17e5fcab5b7..941b6d5cab3 100644
--- a/app/assets/javascripts/notes/components/note_awards_list.vue
+++ b/app/assets/javascripts/notes/components/note_awards_list.vue
@@ -189,13 +189,13 @@ export default {
type="button"
>
<span class="award-control-icon award-control-icon-neutral">
- <icon name="emoji_slightly_smiling_face" />
+ <icon name="slight-smile" />
</span>
<span class="award-control-icon award-control-icon-positive">
- <icon name="emoji_smiley" />
+ <icon name="smiley" />
</span>
<span class="award-control-icon award-control-icon-super-positive">
- <icon name="emoji_smiley" />
+ <icon name="smiley" />
</span>
<i
aria-hidden="true"
diff --git a/app/assets/javascripts/repository/components/table/index.vue b/app/assets/javascripts/repository/components/table/index.vue
index ad3d8f9329d..758f4b88be2 100644
--- a/app/assets/javascripts/repository/components/table/index.vue
+++ b/app/assets/javascripts/repository/components/table/index.vue
@@ -1,11 +1,15 @@
<script>
import { GlLoadingIcon } from '@gitlab/ui';
+import createFlash from '~/flash';
import { sprintf, __ } from '../../../locale';
import getRefMixin from '../../mixins/get_ref';
import getFiles from '../../queries/getFiles.graphql';
+import getProjectPath from '../../queries/getProjectPath.graphql';
import TableHeader from './header.vue';
import TableRow from './row.vue';
+const PAGE_SIZE = 100;
+
export default {
components: {
GlLoadingIcon,
@@ -14,14 +18,8 @@ export default {
},
mixins: [getRefMixin],
apollo: {
- files: {
- query: getFiles,
- variables() {
- return {
- ref: this.ref,
- path: this.path,
- };
- },
+ projectPath: {
+ query: getProjectPath,
},
},
props: {
@@ -32,7 +30,14 @@ export default {
},
data() {
return {
- files: [],
+ projectPath: '',
+ nextPageCursor: '',
+ entries: {
+ trees: [],
+ submodules: [],
+ blobs: [],
+ },
+ isLoadingFiles: false,
};
},
computed: {
@@ -42,8 +47,63 @@ export default {
{ path: this.path, ref: this.ref },
);
},
- isLoadingFiles() {
- return this.$apollo.queries.files.loading;
+ },
+ watch: {
+ $route: function routeChange() {
+ this.entries.trees = [];
+ this.entries.submodules = [];
+ this.entries.blobs = [];
+ this.nextPageCursor = '';
+ this.fetchFiles();
+ },
+ },
+ mounted() {
+ // We need to wait for `ref` and `projectPath` to be set
+ this.$nextTick(() => this.fetchFiles());
+ },
+ methods: {
+ fetchFiles() {
+ this.isLoadingFiles = true;
+
+ return this.$apollo
+ .query({
+ query: getFiles,
+ variables: {
+ projectPath: this.projectPath,
+ ref: this.ref,
+ path: this.path,
+ nextPageCursor: this.nextPageCursor,
+ pageSize: PAGE_SIZE,
+ },
+ })
+ .then(({ data }) => {
+ if (!data) return;
+
+ const pageInfo = this.hasNextPage(data.project.repository.tree);
+
+ this.isLoadingFiles = false;
+ this.entries = Object.keys(this.entries).reduce(
+ (acc, key) => ({
+ ...acc,
+ [key]: this.normalizeData(key, data.project.repository.tree[key].edges),
+ }),
+ {},
+ );
+
+ if (pageInfo && pageInfo.hasNextPage) {
+ this.nextPageCursor = pageInfo.endCursor;
+ this.fetchFiles();
+ }
+ })
+ .catch(() => createFlash(__('An error occurding while fetching folder content.')));
+ },
+ normalizeData(key, data) {
+ return this.entries[key].concat(data.map(({ node }) => node));
+ },
+ hasNextPage(data) {
+ return []
+ .concat(data.trees.pageInfo, data.submodules.pageInfo, data.blobs.pageInfo)
+ .find(({ hasNextPage }) => hasNextPage);
},
},
};
@@ -58,18 +118,21 @@ export default {
tableCaption
}}
</caption>
- <table-header />
+ <table-header v-once />
<tbody>
- <table-row
- v-for="entry in files"
- :id="entry.id"
- :key="entry.id"
- :path="entry.flatPath"
- :type="entry.type"
- />
+ <template v-for="val in entries">
+ <table-row
+ v-for="entry in val"
+ :id="entry.id"
+ :key="`${entry.flatPath}-${entry.id}`"
+ :current-path="path"
+ :path="entry.flatPath"
+ :type="entry.type"
+ />
+ </template>
</tbody>
</table>
- <gl-loading-icon v-if="isLoadingFiles" class="my-3" size="md" />
+ <gl-loading-icon v-show="isLoadingFiles" class="my-3" size="md" />
</div>
</div>
</template>
diff --git a/app/assets/javascripts/repository/components/table/row.vue b/app/assets/javascripts/repository/components/table/row.vue
index 0ad0fdbd605..9a264bef87e 100644
--- a/app/assets/javascripts/repository/components/table/row.vue
+++ b/app/assets/javascripts/repository/components/table/row.vue
@@ -6,7 +6,11 @@ export default {
mixins: [getRefMixin],
props: {
id: {
- type: Number,
+ type: String,
+ required: true,
+ },
+ currentPath: {
+ type: String,
required: true,
},
path: {
@@ -26,7 +30,7 @@ export default {
return `fa-${getIconName(this.type, this.path)}`;
},
isFolder() {
- return this.type === 'folder';
+ return this.type === 'tree';
},
isSubmodule() {
return this.type === 'commit';
@@ -34,6 +38,12 @@ export default {
linkComponent() {
return this.isFolder ? 'router-link' : 'a';
},
+ fullPath() {
+ return this.path.replace(new RegExp(`^${this.currentPath}/`), '');
+ },
+ shortSha() {
+ return this.id.slice(0, 8);
+ },
},
methods: {
openRow() {
@@ -49,9 +59,11 @@ export default {
<tr v-once :class="`file_${id}`" class="tree-item" @click="openRow">
<td class="tree-item-file-name">
<i :aria-label="type" role="img" :class="iconName" class="fa fa-fw"></i>
- <component :is="linkComponent" :to="routerLinkTo" class="str-truncated">{{ path }}</component>
+ <component :is="linkComponent" :to="routerLinkTo" class="str-truncated">
+ {{ fullPath }}
+ </component>
<template v-if="isSubmodule">
- @ <a href="#" class="commit-sha">{{ id }}</a>
+ @ <a href="#" class="commit-sha">{{ shortSha }}</a>
</template>
</td>
<td class="d-none d-sm-table-cell tree-commit"></td>
diff --git a/app/assets/javascripts/repository/fragmentTypes.json b/app/assets/javascripts/repository/fragmentTypes.json
new file mode 100644
index 00000000000..949ebca432b
--- /dev/null
+++ b/app/assets/javascripts/repository/fragmentTypes.json
@@ -0,0 +1 @@
+{"__schema":{"types":[{"kind":"INTERFACE","name":"Entry","possibleTypes":[{"name":"Blob"},{"name":"Submodule"},{"name":"TreeEntry"}]}]}}
diff --git a/app/assets/javascripts/repository/graphql.js b/app/assets/javascripts/repository/graphql.js
index c85db5c01e5..c64d16ef02a 100644
--- a/app/assets/javascripts/repository/graphql.js
+++ b/app/assets/javascripts/repository/graphql.js
@@ -1,45 +1,42 @@
import Vue from 'vue';
import VueApollo from 'vue-apollo';
+import { IntrospectionFragmentMatcher } from 'apollo-cache-inmemory';
import createDefaultClient from '~/lib/graphql';
+import introspectionQueryResultData from './fragmentTypes.json';
Vue.use(VueApollo);
-const defaultClient = createDefaultClient({
- Query: {
- files() {
- return [
- {
- __typename: 'file',
- id: 1,
- name: 'app',
- flatPath: 'app',
- type: 'folder',
- },
- {
- __typename: 'file',
- id: 2,
- name: 'gitlab-svg',
- flatPath: 'gitlab-svg',
- type: 'commit',
- },
- {
- __typename: 'file',
- id: 3,
- name: 'index.js',
- flatPath: 'index.js',
- type: 'blob',
- },
- {
- __typename: 'file',
- id: 4,
- name: 'test.pdf',
- flatPath: 'fixtures/test.pdf',
- type: 'blob',
- },
- ];
+// We create a fragment matcher so that we can create a fragment from an interface
+// Without this, Apollo throws a heuristic fragment matcher warning
+const fragmentMatcher = new IntrospectionFragmentMatcher({
+ introspectionQueryResultData,
+});
+
+const defaultClient = createDefaultClient(
+ {},
+ {
+ cacheConfig: {
+ fragmentMatcher,
+ dataIdFromObject: obj => {
+ // eslint-disable-next-line no-underscore-dangle
+ switch (obj.__typename) {
+ // We need to create a dynamic ID for each entry
+ // Each entry can have the same ID as the ID is a commit ID
+ // So we create a unique cache ID with the path and the ID
+ case 'TreeEntry':
+ case 'Submodule':
+ case 'Blob':
+ return `${obj.flatPath}-${obj.id}`;
+ default:
+ // If the type doesn't match any of the above we fallback
+ // to using the default Apollo ID
+ // eslint-disable-next-line no-underscore-dangle
+ return obj.id || obj._id;
+ }
+ },
},
},
-});
+);
export default new VueApollo({
defaultClient,
diff --git a/app/assets/javascripts/repository/queries/getFiles.graphql b/app/assets/javascripts/repository/queries/getFiles.graphql
index fb446780ed1..a9b61d28560 100644
--- a/app/assets/javascripts/repository/queries/getFiles.graphql
+++ b/app/assets/javascripts/repository/queries/getFiles.graphql
@@ -1,7 +1,55 @@
-query getFiles($path: String!, $ref: String!) {
- files(path: $path, ref: $ref) @client {
- id
- flatPath
- type
+fragment TreeEntry on Entry {
+ id
+ flatPath
+ type
+}
+
+fragment PageInfo on PageInfo {
+ hasNextPage
+ endCursor
+}
+
+query getFiles(
+ $projectPath: ID!
+ $path: String
+ $ref: String!
+ $pageSize: Int!
+ $nextPageCursor: String
+) {
+ project(fullPath: $projectPath) {
+ repository {
+ tree(path: $path, ref: $ref) {
+ trees(first: $pageSize, after: $nextPageCursor) {
+ edges {
+ node {
+ ...TreeEntry
+ }
+ }
+ pageInfo {
+ ...PageInfo
+ }
+ }
+ submodules(first: $pageSize, after: $nextPageCursor) {
+ edges {
+ node {
+ ...TreeEntry
+ }
+ }
+ pageInfo {
+ ...PageInfo
+ }
+ }
+ blobs(first: $pageSize, after: $nextPageCursor) {
+ edges {
+ node {
+ ...TreeEntry
+ }
+ }
+ pageInfo {
+ ...PageInfo
+ }
+ }
+ }
+ }
}
}
diff --git a/app/assets/javascripts/repository/queries/getProjectPath.graphql b/app/assets/javascripts/repository/queries/getProjectPath.graphql
new file mode 100644
index 00000000000..74e73e07577
--- /dev/null
+++ b/app/assets/javascripts/repository/queries/getProjectPath.graphql
@@ -0,0 +1,3 @@
+query getProjectPath {
+ projectPath
+}
diff --git a/app/assets/javascripts/repository/router.js b/app/assets/javascripts/repository/router.js
index b42a96a4ee2..f7132b99d9e 100644
--- a/app/assets/javascripts/repository/router.js
+++ b/app/assets/javascripts/repository/router.js
@@ -12,16 +12,11 @@ export default function createRouter(base, baseRef) {
base: joinPaths(gon.relative_url_root || '', base),
routes: [
{
- path: '/',
- name: 'projectRoot',
- component: IndexPage,
- },
- {
path: `/tree/${baseRef}(/.*)?`,
name: 'treePath',
component: TreePage,
props: route => ({
- path: route.params.pathMatch,
+ path: route.params.pathMatch.replace(/^\//, ''),
}),
beforeEnter(to, from, next) {
document
@@ -31,6 +26,11 @@ export default function createRouter(base, baseRef) {
next();
},
},
+ {
+ path: '/',
+ name: 'projectRoot',
+ component: IndexPage,
+ },
],
});
}
diff --git a/app/assets/javascripts/repository/utils/icon.js b/app/assets/javascripts/repository/utils/icon.js
index 3e93ff0ec39..661ebb6edfc 100644
--- a/app/assets/javascripts/repository/utils/icon.js
+++ b/app/assets/javascripts/repository/utils/icon.js
@@ -1,5 +1,5 @@
const entryTypeIcons = {
- folder: 'folder',
+ tree: 'folder',
commit: 'archive',
};
diff --git a/app/assets/javascripts/search_autocomplete.js b/app/assets/javascripts/search_autocomplete.js
index e5c3cebfb9a..ab43c2139bf 100644
--- a/app/assets/javascripts/search_autocomplete.js
+++ b/app/assets/javascripts/search_autocomplete.js
@@ -407,6 +407,7 @@ export class SearchAutocomplete {
if (this.searchInput.val() === '') {
return this.restoreOriginalState();
}
+ this.dropdownMenu.removeClass('show');
}
restoreOriginalState() {
diff --git a/app/assets/javascripts/set_status_modal/set_status_modal_wrapper.vue b/app/assets/javascripts/set_status_modal/set_status_modal_wrapper.vue
index 10e2c8453e2..35eba266625 100644
--- a/app/assets/javascripts/set_status_modal/set_status_modal_wrapper.vue
+++ b/app/assets/javascripts/set_status_modal/set_status_modal_wrapper.vue
@@ -194,9 +194,9 @@ export default {
v-show="noEmoji"
class="js-no-emoji-placeholder no-emoji-placeholder position-relative"
>
- <icon name="emoji_slightly_smiling_face" css-classes="award-control-icon-neutral" />
- <icon name="emoji_smiley" css-classes="award-control-icon-positive" />
- <icon name="emoji_smile" css-classes="award-control-icon-super-positive" />
+ <icon name="slight-smile" css-classes="award-control-icon-neutral" />
+ <icon name="smiley" css-classes="award-control-icon-positive" />
+ <icon name="smile" css-classes="award-control-icon-super-positive" />
</span>
</button>
</span>
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/deployment.vue b/app/assets/javascripts/vue_merge_request_widget/components/deployment.vue
index 8f4cae8ae58..ad0464a3a98 100644
--- a/app/assets/javascripts/vue_merge_request_widget/components/deployment.vue
+++ b/app/assets/javascripts/vue_merge_request_widget/components/deployment.vue
@@ -49,7 +49,7 @@ export default {
required: false,
default: () => ({
sourceProjectId: '',
- issueId: '',
+ mergeRequestId: '',
appUrl: '',
}),
},
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_pipeline_container.vue b/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_pipeline_container.vue
index b9f5f602117..0686409a785 100644
--- a/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_pipeline_container.vue
+++ b/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_pipeline_container.vue
@@ -48,7 +48,7 @@ export default {
visualReviewAppMeta() {
return {
appUrl: this.mr.appUrl,
- issueId: this.mr.iid,
+ mergeRequestId: this.mr.iid,
sourceProjectId: this.mr.sourceProjectId,
};
},
diff --git a/app/assets/javascripts/vue_shared/components/user_popover/user_popover.vue b/app/assets/javascripts/vue_shared/components/user_popover/user_popover.vue
index 4dbfd1ba6f4..a60d5eb491e 100644
--- a/app/assets/javascripts/vue_shared/components/user_popover/user_popover.vue
+++ b/app/assets/javascripts/vue_shared/components/user_popover/user_popover.vue
@@ -71,11 +71,15 @@ export default {
</div>
<div class="text-secondary">
<div v-if="user.bio" class="js-bio d-flex mb-1">
- <icon name="profile" css-classes="category-icon" />
+ <icon name="profile" css-classes="category-icon flex-shrink-0" />
<span class="ml-1">{{ user.bio }}</span>
</div>
<div v-if="user.organization" class="js-organization d-flex mb-1">
- <icon v-show="!jobInfoIsLoading" name="work" css-classes="category-icon" />
+ <icon
+ v-show="!jobInfoIsLoading"
+ name="work"
+ css-classes="category-icon flex-shrink-0"
+ />
<span class="ml-1">{{ user.organization }}</span>
</div>
<gl-skeleton-loading
@@ -88,7 +92,7 @@ export default {
<icon
v-show="!locationIsLoading && user.location"
name="location"
- css-classes="category-icon"
+ css-classes="category-icon flex-shrink-0"
/>
<span class="ml-1">{{ user.location }}</span>
<gl-skeleton-loading
diff --git a/app/assets/stylesheets/framework/avatar.scss b/app/assets/stylesheets/components/avatar.scss
index 37a729c7a63..4ab197b935b 100644
--- a/app/assets/stylesheets/framework/avatar.scss
+++ b/app/assets/stylesheets/components/avatar.scss
@@ -1,33 +1,28 @@
-@mixin avatar-size($size, $margin-right) {
- width: $size;
- height: $size;
- margin-right: $margin-right;
-}
-
.avatar-circle {
float: left;
margin-right: 15px;
border-radius: $avatar-radius;
border: 1px solid $gray-normal;
- &.s16 { @include avatar-size(16px, 6px); }
- &.s18 { @include avatar-size(18px, 6px); }
- &.s19 { @include avatar-size(19px, 6px); }
- &.s20 { @include avatar-size(20px, 7px); }
+ &.s16 { @include avatar-size(16px, 8px); }
+ &.s18 { @include avatar-size(18px, 8px); }
+ &.s19 { @include avatar-size(19px, 8px); }
+ &.s20 { @include avatar-size(20px, 8px); }
&.s24 { @include avatar-size(24px, 8px); }
&.s26 { @include avatar-size(26px, 8px); }
- &.s32 { @include avatar-size(32px, 10px); }
- &.s36 { @include avatar-size(36px, 10px); }
- &.s40 { @include avatar-size(40px, 10px); }
- &.s46 { @include avatar-size(46px, 15px); }
- &.s48 { @include avatar-size(48px, 10px); }
- &.s60 { @include avatar-size(60px, 12px); }
- &.s64 { @include avatar-size(64px, 14px); }
- &.s70 { @include avatar-size(70px, 14px); }
- &.s90 { @include avatar-size(90px, 15px); }
- &.s100 { @include avatar-size(100px, 15px); }
- &.s110 { @include avatar-size(110px, 15px); }
- &.s140 { @include avatar-size(140px, 15px); }
- &.s160 { @include avatar-size(160px, 20px); }
+ &.s32 { @include avatar-size(32px, 8px); }
+ &.s36 { @include avatar-size(36px, 16px); }
+ &.s40 { @include avatar-size(40px, 16px); }
+ &.s46 { @include avatar-size(46px, 16px); }
+ &.s48 { @include avatar-size(48px, 16px); }
+ &.s60 { @include avatar-size(60px, 16px); }
+ &.s64 { @include avatar-size(64px, 16px); }
+ &.s70 { @include avatar-size(70px, 16px); }
+ &.s90 { @include avatar-size(90px, 16px); }
+ &.s96 { @include avatar-size(96px, 16px); }
+ &.s100 { @include avatar-size(100px, 16px); }
+ &.s110 { @include avatar-size(110px, 16px); }
+ &.s140 { @include avatar-size(140px, 16px); }
+ &.s160 { @include avatar-size(160px, 16px); }
}
.avatar {
@@ -39,6 +34,7 @@
padding: 0;
background: $gray-lightest;
overflow: hidden;
+ border-color: rgba($black, $gl-avatar-border-opacity);
&.avatar-inline {
float: none;
@@ -64,41 +60,37 @@
&.avatar-placeholder {
border: 0;
}
-
- &:not([href]):hover {
- border-color: darken($gray-normal, 10%);
- }
}
.identicon {
text-align: center;
vertical-align: top;
- color: $gl-gray-700;
+ color: $gray-800;
background-color: $gray-darker;
// Sizes
- &.s16 { font-size: 12px;
- line-height: 1.33; }
+ &.s16 { font-size: 10px;
+ line-height: 16px; }
- &.s24 { font-size: 13px;
- line-height: 1.8; }
+ &.s24 { font-size: 12px;
+ line-height: 24px; }
&.s26 { font-size: 20px;
line-height: 1.33; }
- &.s32 { font-size: 20px;
- line-height: 30px; }
+ &.s32 { font-size: 14px;
+ line-height: 32px; }
&.s40 { font-size: 16px;
line-height: 38px; }
&.s48 { font-size: 20px;
- line-height: 46px; }
+ line-height: 48px; }
&.s60 { font-size: 32px;
line-height: 58px; }
- &.s64 { font-size: 32px;
+ &.s64 { font-size: 28px;
line-height: 64px; }
&.s70 { font-size: 34px;
@@ -107,6 +99,9 @@
&.s90 { font-size: 36px;
line-height: 88px; }
+ &.s96 { font-size: 48px;
+ line-height: 96px; }
+
&.s100 { font-size: 36px;
line-height: 98px; }
@@ -144,7 +139,6 @@
.avatar {
border-radius: 0;
- border: 0;
height: auto;
width: 100%;
margin: 0;
diff --git a/app/assets/stylesheets/framework.scss b/app/assets/stylesheets/framework.scss
index ab9047c54e4..9b0d19b0ef0 100644
--- a/app/assets/stylesheets/framework.scss
+++ b/app/assets/stylesheets/framework.scss
@@ -8,7 +8,6 @@
@import 'framework/animations';
@import 'framework/vue_transitions';
-@import 'framework/avatar';
@import 'framework/asciidoctor';
@import 'framework/banner';
@import 'framework/blocks';
diff --git a/app/assets/stylesheets/framework/awards.scss b/app/assets/stylesheets/framework/awards.scss
index 648e1944388..a8df7e1bfad 100644
--- a/app/assets/stylesheets/framework/awards.scss
+++ b/app/assets/stylesheets/framework/awards.scss
@@ -151,8 +151,7 @@
outline: 0;
.award-control-icon svg {
- background: $award-emoji-positive-add-bg;
- fill: $award-emoji-positive-add-lines;
+ fill: $blue-500;
}
.award-control-icon-neutral {
@@ -236,7 +235,7 @@
}
path {
- fill: $border-gray-normal;
+ fill: $gray-700;
}
}
diff --git a/app/assets/stylesheets/framework/files.scss b/app/assets/stylesheets/framework/files.scss
index 53d3645cd63..17c117188b3 100644
--- a/app/assets/stylesheets/framework/files.scss
+++ b/app/assets/stylesheets/framework/files.scss
@@ -241,6 +241,7 @@
*/
&.code {
padding: 0;
+ border-radius: 0 0 $border-radius-default $border-radius-default;
}
.list-inline.previews {
diff --git a/app/assets/stylesheets/framework/filters.scss b/app/assets/stylesheets/framework/filters.scss
index 5bcfd5d1322..26cbb7f5c13 100644
--- a/app/assets/stylesheets/framework/filters.scss
+++ b/app/assets/stylesheets/framework/filters.scss
@@ -218,7 +218,7 @@
min-width: 200px;
padding-right: 25px;
padding-left: 0;
- height: $input-height;
+ height: $input-height - 2;
line-height: inherit;
border-color: transparent;
diff --git a/app/assets/stylesheets/framework/forms.scss b/app/assets/stylesheets/framework/forms.scss
index d0f99c2df7e..4a9c73a1bc9 100644
--- a/app/assets/stylesheets/framework/forms.scss
+++ b/app/assets/stylesheets/framework/forms.scss
@@ -280,3 +280,7 @@ label {
max-width: $input-lg-width;
width: 100%;
}
+
+.input-group-text {
+ max-height: $input-height;
+}
diff --git a/app/assets/stylesheets/framework/highlight.scss b/app/assets/stylesheets/framework/highlight.scss
index 946f575ac13..741f92110c3 100644
--- a/app/assets/stylesheets/framework/highlight.scss
+++ b/app/assets/stylesheets/framework/highlight.scss
@@ -8,7 +8,7 @@
pre {
padding: 10px 0;
border: 0;
- border-radius: 0;
+ border-radius: 0 0 $border-radius-default $border-radius-default;
font-family: $monospace-font;
font-size: $code-font-size;
line-height: 19px;
@@ -42,6 +42,7 @@
padding: 10px;
text-align: right;
float: left;
+ border-bottom-left-radius: $border-radius-default;
a {
font-family: $monospace-font;
diff --git a/app/assets/stylesheets/framework/mixins.scss b/app/assets/stylesheets/framework/mixins.scss
index 97de0c98325..18671f7c4d8 100644
--- a/app/assets/stylesheets/framework/mixins.scss
+++ b/app/assets/stylesheets/framework/mixins.scss
@@ -376,3 +376,12 @@
}
}
}
+
+/*
+* Mixin that handles the size and right margin of avatars.
+*/
+@mixin avatar-size($size, $margin-right) {
+ width: $size;
+ height: $size;
+ margin-right: $margin-right;
+}
diff --git a/app/assets/stylesheets/framework/variables.scss b/app/assets/stylesheets/framework/variables.scss
index 1cf122102cc..28768bdf88f 100644
--- a/app/assets/stylesheets/framework/variables.scss
+++ b/app/assets/stylesheets/framework/variables.scss
@@ -589,6 +589,7 @@ $issue-board-list-difference-md: $issue-board-list-difference-sm + $issue-boards
*/
$avatar-radius: 50%;
$gl-avatar-size: 40px;
+$gl-avatar-border-opacity: 0.1;
/*
* Blame
diff --git a/app/assets/stylesheets/framework/variables_overrides.scss b/app/assets/stylesheets/framework/variables_overrides.scss
index fb4d3f23cd9..ea96381a098 100644
--- a/app/assets/stylesheets/framework/variables_overrides.scss
+++ b/app/assets/stylesheets/framework/variables_overrides.scss
@@ -7,6 +7,7 @@ $secondary: $gray-light;
$input-disabled-bg: $gray-light;
$input-border-color: $gray-200;
$input-color: $gl-text-color;
+$input-font-size: $gl-font-size;
$font-family-sans-serif: $regular-font;
$font-family-monospace: $monospace-font;
$btn-line-height: 20px;
diff --git a/app/assets/stylesheets/pages/detail_page.scss b/app/assets/stylesheets/pages/detail_page.scss
index cb5f1a84005..c386493231c 100644
--- a/app/assets/stylesheets/pages/detail_page.scss
+++ b/app/assets/stylesheets/pages/detail_page.scss
@@ -21,7 +21,6 @@
.detail-page-header-body {
position: relative;
- line-height: 35px;
display: flex;
flex: 1 1;
min-width: 0;
diff --git a/app/assets/stylesheets/pages/diff.scss b/app/assets/stylesheets/pages/diff.scss
index b2b3720fdde..b3a634e23a3 100644
--- a/app/assets/stylesheets/pages/diff.scss
+++ b/app/assets/stylesheets/pages/diff.scss
@@ -494,6 +494,12 @@ table.code {
}
}
+ .line_holder:last-of-type {
+ td:first-child {
+ border-bottom-left-radius: $border-radius-default;
+ }
+ }
+
&.left-side-selected {
td.line_content.parallel.right-side {
user-select: none;
diff --git a/app/assets/stylesheets/pages/events.scss b/app/assets/stylesheets/pages/events.scss
index 618f23d81b1..e34628002ac 100644
--- a/app/assets/stylesheets/pages/events.scss
+++ b/app/assets/stylesheets/pages/events.scss
@@ -156,6 +156,10 @@
&:hover {
background: none;
}
+
+ a {
+ color: $blue-600;
+ }
}
}
}
diff --git a/app/assets/stylesheets/pages/login.scss b/app/assets/stylesheets/pages/login.scss
index 22a515cbdaa..fd082cbe0cd 100644
--- a/app/assets/stylesheets/pages/login.scss
+++ b/app/assets/stylesheets/pages/login.scss
@@ -21,13 +21,6 @@
color: $login-brand-holder-color;
}
- h1:first-child {
- font-weight: $gl-font-weight-normal;
- margin-bottom: 0.68em;
- margin-top: 0;
- font-size: 34px;
- }
-
h3 {
font-size: 22px;
}
diff --git a/app/models/clusters/applications/jupyter.rb b/app/models/clusters/applications/jupyter.rb
index 36c51522089..bd9c453e2a4 100644
--- a/app/models/clusters/applications/jupyter.rb
+++ b/app/models/clusters/applications/jupyter.rb
@@ -1,5 +1,7 @@
# frozen_string_literal: true
+require 'securerandom'
+
module Clusters
module Applications
class Jupyter < ApplicationRecord
@@ -80,6 +82,9 @@ module Clusters
"secretToken" => secret_token
},
"auth" => {
+ "state" => {
+ "cryptoKey" => crypto_key
+ },
"gitlab" => {
"clientId" => oauth_application.uid,
"clientSecret" => oauth_application.secret,
@@ -95,6 +100,10 @@ module Clusters
}
end
+ def crypto_key
+ @crypto_key ||= SecureRandom.hex(32)
+ end
+
def project_id
cluster&.project&.id
end
diff --git a/app/models/clusters/cluster.rb b/app/models/clusters/cluster.rb
index f7ea7accab2..3c6e185f9e2 100644
--- a/app/models/clusters/cluster.rb
+++ b/app/models/clusters/cluster.rb
@@ -204,7 +204,7 @@ module Clusters
end
def kube_ingress_domain
- @kube_ingress_domain ||= domain.presence || instance_domain || legacy_auto_devops_domain
+ @kube_ingress_domain ||= domain.presence || instance_domain
end
def predefined_variables
@@ -221,24 +221,6 @@ module Clusters
@instance_domain ||= Gitlab::CurrentSettings.auto_devops_domain
end
- # To keep backward compatibility with AUTO_DEVOPS_DOMAIN
- # environment variable, we need to ensure KUBE_INGRESS_BASE_DOMAIN
- # is set if AUTO_DEVOPS_DOMAIN is set on any of the following options:
- # ProjectAutoDevops#Domain, project variables or group variables,
- # as the AUTO_DEVOPS_DOMAIN is needed for CI_ENVIRONMENT_URL
- #
- # This method should is scheduled to be removed on
- # https://gitlab.com/gitlab-org/gitlab-ce/issues/56959
- def legacy_auto_devops_domain
- if project_type?
- project&.auto_devops&.domain.presence ||
- project.variables.find_by(key: 'AUTO_DEVOPS_DOMAIN')&.value.presence ||
- project.group&.variables&.find_by(key: 'AUTO_DEVOPS_DOMAIN')&.value.presence
- elsif group_type?
- group.variables.find_by(key: 'AUTO_DEVOPS_DOMAIN')&.value.presence
- end
- end
-
def restrict_modification
if provider&.on_creation?
errors.add(:base, "cannot modify during creation")
diff --git a/app/models/identity.rb b/app/models/identity.rb
index 8322b9bf35f..1cbd50205ed 100644
--- a/app/models/identity.rb
+++ b/app/models/identity.rb
@@ -13,6 +13,7 @@ class Identity < ApplicationRecord
before_save :ensure_normalized_extern_uid, if: :extern_uid_changed?
after_destroy :clear_user_synced_attributes, if: :user_synced_attributes_metadata_from_provider?
+ scope :for_user, ->(user) { where(user: user) }
scope :with_provider, ->(provider) { where(provider: provider) }
scope :with_extern_uid, ->(provider, extern_uid) do
iwhere(extern_uid: normalize_uid(provider, extern_uid)).with_provider(provider)
diff --git a/app/models/project_auto_devops.rb b/app/models/project_auto_devops.rb
index f972c40f317..90bcb3067f6 100644
--- a/app/models/project_auto_devops.rb
+++ b/app/models/project_auto_devops.rb
@@ -16,27 +16,8 @@ class ProjectAutoDevops < ApplicationRecord
after_save :create_gitlab_deploy_token, if: :needs_to_create_deploy_token?
- def instance_domain
- Gitlab::CurrentSettings.auto_devops_domain
- end
-
- def has_domain?
- domain.present? || instance_domain.present?
- end
-
- # From 11.8, AUTO_DEVOPS_DOMAIN has been replaced by KUBE_INGRESS_BASE_DOMAIN.
- # See Clusters::Cluster#predefined_variables and https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/24580
- # for more info.
- #
- # Suppport AUTO_DEVOPS_DOMAIN is scheduled to be removed on
- # https://gitlab.com/gitlab-org/gitlab-ce/issues/52363
def predefined_variables
Gitlab::Ci::Variables::Collection.new.tap do |variables|
- if has_domain?
- variables.append(key: 'AUTO_DEVOPS_DOMAIN',
- value: domain.presence || instance_domain)
- end
-
variables.concat(deployment_strategy_default_variables)
end
end
diff --git a/app/services/system_note_service.rb b/app/services/system_note_service.rb
index a39ff76b798..1390f7cdf46 100644
--- a/app/services/system_note_service.rb
+++ b/app/services/system_note_service.rb
@@ -25,7 +25,7 @@ module SystemNoteService
text_parts = ["added #{commits_text}"]
text_parts << commits_list(noteable, new_commits, existing_commits, oldrev)
- text_parts << "[Compare with previous version](#{diff_comparison_url(noteable, project, oldrev)})"
+ text_parts << "[Compare with previous version](#{diff_comparison_path(noteable, project, oldrev)})"
body = text_parts.join("\n\n")
@@ -41,7 +41,7 @@ module SystemNoteService
#
# Returns the created Note object
def tag_commit(noteable, project, author, tag_name)
- link = url_helpers.project_tag_url(project, id: tag_name)
+ link = url_helpers.project_tag_path(project, id: tag_name)
body = "tagged commit #{noteable.sha} to [`#{tag_name}`](#{link})"
create_note(NoteSummary.new(noteable, project, author, body, action: 'tag'))
@@ -272,7 +272,7 @@ module SystemNoteService
text_parts = ["changed this line in"]
if version_params = merge_request.version_params_for(diff_refs)
line_code = change_position.line_code(project.repository)
- url = url_helpers.diffs_project_merge_request_url(project, merge_request, version_params.merge(anchor: line_code))
+ url = url_helpers.diffs_project_merge_request_path(project, merge_request, version_params.merge(anchor: line_code))
text_parts << "[version #{version_index} of the diff](#{url})"
else
@@ -405,7 +405,7 @@ module SystemNoteService
#
# "created branch `201-issue-branch-button`"
def new_issue_branch(issue, project, author, branch)
- link = url_helpers.project_compare_url(project, from: project.default_branch, to: branch)
+ link = url_helpers.project_compare_path(project, from: project.default_branch, to: branch)
body = "created branch [`#{branch}`](#{link}) to address this issue"
@@ -668,10 +668,10 @@ module SystemNoteService
@url_helpers ||= Gitlab::Routing.url_helpers
end
- def diff_comparison_url(merge_request, project, oldrev)
+ def diff_comparison_path(merge_request, project, oldrev)
diff_id = merge_request.merge_request_diff.id
- url_helpers.diffs_project_merge_request_url(
+ url_helpers.diffs_project_merge_request_path(
project,
merge_request,
diff_id: diff_id,
diff --git a/app/views/award_emoji/_awards_block.html.haml b/app/views/award_emoji/_awards_block.html.haml
index 8d9c083d223..60ca7e4e267 100644
--- a/app/views/award_emoji/_awards_block.html.haml
+++ b/app/views/award_emoji/_awards_block.html.haml
@@ -13,7 +13,7 @@
%button.btn.award-control.has-tooltip.js-add-award{ type: 'button',
'aria-label': _('Add reaction'),
data: { title: _('Add reaction') } }
- %span{ class: "award-control-icon award-control-icon-neutral" }= custom_icon('emoji_slightly_smiling_face')
- %span{ class: "award-control-icon award-control-icon-positive" }= custom_icon('emoji_smiley')
- %span{ class: "award-control-icon award-control-icon-super-positive" }= custom_icon('emoji_smile')
+ %span{ class: "award-control-icon award-control-icon-neutral" }= sprite_icon('slight-smile')
+ %span{ class: "award-control-icon award-control-icon-positive" }= sprite_icon('smiley')
+ %span{ class: "award-control-icon award-control-icon-super-positive" }= sprite_icon('smile')
= icon('spinner spin', class: "award-control-icon award-control-icon-loading")
diff --git a/app/views/events/event/_push.html.haml b/app/views/events/event/_push.html.haml
index 69914fccc48..21c418cb0e4 100644
--- a/app/views/events/event/_push.html.haml
+++ b/app/views/events/event/_push.html.haml
@@ -32,7 +32,8 @@
- from_label = from
= link_to project_compare_path(project, from: from, to: event.commit_to) do
- Compare #{from_label}...#{truncate_sha(event.commit_to)}
+ %span Compare
+ %span.commit-sha #{from_label}...#{truncate_sha(event.commit_to)}
- if create_mr
%span
diff --git a/app/views/issues/_issue.atom.builder b/app/views/issues/_issue.atom.builder
index 21cf6d0dd65..94c32df7c60 100644
--- a/app/views/issues/_issue.atom.builder
+++ b/app/views/issues/_issue.atom.builder
@@ -12,6 +12,7 @@ xml.entry do
xml.summary issue.title
xml.description issue.description if issue.description
+ xml.content issue.description if issue.description
xml.milestone issue.milestone.title if issue.milestone
xml.due_date issue.due_date if issue.due_date
diff --git a/app/views/layouts/devise.html.haml b/app/views/layouts/devise.html.haml
index f7a561afbb3..ff3410f6268 100644
--- a/app/views/layouts/devise.html.haml
+++ b/app/views/layouts/devise.html.haml
@@ -10,15 +10,17 @@
.container.navless-container
.content
= render "layouts/flash"
- .row.append-bottom-15
- .col-sm-7.brand-holder
- %h1
+ .row.mt-3
+ .col-sm-12
+ %h1.mb-3.font-weight-normal
= brand_title
+ .row.mb-3
+ .col-sm-7.order-12.order-sm-1.brand-holder
= brand_image
- if current_appearance&.description?
= brand_text
- else
- %h3
+ %h3.mt-sm-0
= _('Open source software to collaborate on code')
%p
@@ -29,7 +31,7 @@
= render_if_exists 'layouts/devise_help_text'
- .col-sm-5.new-session-forms-container
+ .col-sm-5.order-1.order-sm-12.new-session-forms-container
= yield
%hr.footer-fixed
diff --git a/app/views/profiles/show.html.haml b/app/views/profiles/show.html.haml
index 917e7acc353..e36d5192a29 100644
--- a/app/views/profiles/show.html.haml
+++ b/app/views/profiles/show.html.haml
@@ -47,9 +47,9 @@
- if @user.status
= emoji_icon @user.status.emoji
%span#js-no-emoji-placeholder.no-emoji-placeholder{ class: ('hidden' if @user.status) }
- = sprite_icon('emoji_slightly_smiling_face', css_class: 'award-control-icon-neutral')
- = sprite_icon('emoji_smiley', css_class: 'award-control-icon-positive')
- = sprite_icon('emoji_smile', css_class: 'award-control-icon-super-positive')
+ = sprite_icon('slight-smile', css_class: 'award-control-icon-neutral')
+ = sprite_icon('smiley', css_class: 'award-control-icon-positive')
+ = sprite_icon('smile', css_class: 'award-control-icon-super-positive')
- reset_message_button = button_tag type: :button,
id: 'js-clear-user-status-button',
class: 'clear-user-status btn has-tooltip',
diff --git a/app/views/projects/buttons/_download_links.html.haml b/app/views/projects/buttons/_download_links.html.haml
index 7f2cd8e109e..d344167a6c5 100644
--- a/app/views/projects/buttons/_download_links.html.haml
+++ b/app/views/projects/buttons/_download_links.html.haml
@@ -1,5 +1,5 @@
- formats = [['zip', 'btn-primary'], ['tar.gz'], ['tar.bz2'], ['tar']]
-.d-flex.justify-content-between
+.btn-group.ml-0.w-100
- formats.each do |(fmt, extra_class)|
= link_to fmt, project_archive_path(project, id: tree_join(ref, archive_prefix), path: path, format: fmt), rel: 'nofollow', download: '', class: "btn btn-xs #{extra_class}"
diff --git a/app/views/projects/commits/_commit.html.haml b/app/views/projects/commits/_commit.html.haml
index e2d078855d9..771e1881e94 100644
--- a/app/views/projects/commits/_commit.html.haml
+++ b/app/views/projects/commits/_commit.html.haml
@@ -9,6 +9,9 @@
- commit_status = commit.present(current_user: current_user).status_for(ref)
- link = commit_path(project, commit, merge_request: merge_request)
+
+- show_project_name = local_assigns.fetch(:show_project_name, false)
+
%li.commit.flex-row.js-toggle-container{ id: "commit-#{commit.short_id}" }
.avatar-cell.d-none.d-sm-block
@@ -32,6 +35,7 @@
- commit_timeago = time_ago_with_tooltip(commit.authored_date, placement: 'bottom')
- commit_text = _('%{commit_author_link} authored %{commit_timeago}') % { commit_author_link: commit_author_link, commit_timeago: commit_timeago }
#{ commit_text.html_safe }
+ = render_if_exists 'projects/commits/project_namespace', show_project_name: show_project_name, project: project
- if commit.description?
%pre.commit-row-description.js-toggle-content.append-bottom-8
diff --git a/app/views/projects/notes/_actions.html.haml b/app/views/projects/notes/_actions.html.haml
index eb6838cec8d..044adb75bea 100644
--- a/app/views/projects/notes/_actions.html.haml
+++ b/app/views/projects/notes/_actions.html.haml
@@ -41,9 +41,9 @@
.note-actions-item
= button_tag title: 'Add reaction', class: "note-action-button note-emoji-button js-add-award js-note-emoji} has-tooltip btn btn-transparent", data: { position: 'right', container: 'body' } do
= icon('spinner spin')
- %span{ class: 'link-highlight award-control-icon-neutral' }= custom_icon('emoji_slightly_smiling_face')
- %span{ class: 'link-highlight award-control-icon-positive' }= custom_icon('emoji_smiley')
- %span{ class: 'link-highlight award-control-icon-super-positive' }= custom_icon('emoji_smile')
+ %span{ class: 'link-highlight award-control-icon-neutral' }= sprite_icon('slight-smile')
+ %span{ class: 'link-highlight award-control-icon-positive' }= sprite_icon('smiley')
+ %span{ class: 'link-highlight award-control-icon-super-positive' }= sprite_icon('smile')
- if note_editable
.note-actions-item
diff --git a/app/views/shared/icons/_emoji_slightly_smiling_face.svg b/app/views/shared/icons/_emoji_slightly_smiling_face.svg
deleted file mode 100644
index 56dbad91554..00000000000
--- a/app/views/shared/icons/_emoji_slightly_smiling_face.svg
+++ /dev/null
@@ -1 +0,0 @@
-<svg width="18" height="18" viewBox="0 0 18 18" xmlns="http://www.w3.org/2000/svg"><path d="M13.29 11.098a4.328 4.328 0 0 1-1.618 2.285c-.79.578-1.68.867-2.672.867-.992 0-1.883-.29-2.672-.867a4.328 4.328 0 0 1-1.617-2.285.721.721 0 0 1 .047-.569.715.715 0 0 1 .445-.369.721.721 0 0 1 .568.047.715.715 0 0 1 .37.445c.195.625.556 1.131 1.084 1.518A2.93 2.93 0 0 0 9 12.75a2.93 2.93 0 0 0 1.775-.58 2.913 2.913 0 0 0 1.084-1.518.711.711 0 0 1 .375-.445.737.737 0 0 1 .575-.047c.195.063.34.186.433.37.094.183.11.372.047.568zM7.5 6c0 .414-.146.768-.44 1.06-.292.294-.646.44-1.06.44-.414 0-.768-.146-1.06-.44A1.445 1.445 0 0 1 4.5 6c0-.414.146-.768.44-1.06.292-.294.646-.44 1.06-.44.414 0 .768.146 1.06.44.294.292.44.646.44 1.06zm6 0c0 .414-.146.768-.44 1.06-.292.294-.646.44-1.06.44-.414 0-.768-.146-1.06-.44A1.445 1.445 0 0 1 10.5 6c0-.414.146-.768.44-1.06.292-.294.646-.44 1.06-.44.414 0 .768.146 1.06.44.294.292.44.646.44 1.06zm3 3a7.29 7.29 0 0 0-.598-2.912 7.574 7.574 0 0 0-1.6-2.39 7.574 7.574 0 0 0-2.39-1.6A7.29 7.29 0 0 0 9 1.5a7.29 7.29 0 0 0-2.912.598 7.574 7.574 0 0 0-2.39 1.6 7.574 7.574 0 0 0-1.6 2.39A7.29 7.29 0 0 0 1.5 9c0 1.016.2 1.986.598 2.912a7.574 7.574 0 0 0 1.6 2.39 7.574 7.574 0 0 0 2.39 1.6A7.29 7.29 0 0 0 9 16.5a7.29 7.29 0 0 0 2.912-.598 7.574 7.574 0 0 0 2.39-1.6 7.574 7.574 0 0 0 1.6-2.39A7.29 7.29 0 0 0 16.5 9zM18 9a8.804 8.804 0 0 1-1.207 4.518 8.96 8.96 0 0 1-3.275 3.275A8.804 8.804 0 0 1 9 18a8.804 8.804 0 0 1-4.518-1.207 8.96 8.96 0 0 1-3.275-3.275A8.804 8.804 0 0 1 0 9c0-1.633.402-3.139 1.207-4.518a8.96 8.96 0 0 1 3.275-3.275A8.804 8.804 0 0 1 9 0c1.633 0 3.139.402 4.518 1.207a8.96 8.96 0 0 1 3.275 3.275A8.804 8.804 0 0 1 18 9z" fill-rule="evenodd"/></svg>
diff --git a/app/views/shared/icons/_emoji_smile.svg b/app/views/shared/icons/_emoji_smile.svg
deleted file mode 100644
index ce645fee46f..00000000000
--- a/app/views/shared/icons/_emoji_smile.svg
+++ /dev/null
@@ -1 +0,0 @@
-<svg width="18" height="18" viewBox="0 0 18 18" xmlns="http://www.w3.org/2000/svg"><path d="M13.29 11.098a4.328 4.328 0 0 1-1.618 2.285c-.79.578-1.68.867-2.672.867-.992 0-1.883-.29-2.672-.867a4.328 4.328 0 0 1-1.617-2.285.721.721 0 0 1 .047-.569.715.715 0 0 1 .445-.369c.195-.062 7.41-.062 7.606 0 .195.063.34.186.433.37.094.183.11.372.047.568zM14 6.37c0 .398-.04.755-.513.755-.473 0-.498-.272-1.237-.272-.74 0-.74.215-1.165.215-.425 0-.585-.3-.585-.698 0-.397.17-.736.513-1.017.341-.281.754-.422 1.237-.422.483 0 .896.14 1.237.422.342.28.513.62.513 1.017zm-6.5 0c0 .398-.04.755-.513.755-.473 0-.498-.272-1.237-.272-.74 0-.74.215-1.165.215-.425 0-.585-.3-.585-.698 0-.397.17-.736.513-1.017.341-.281.754-.422 1.237-.422.483 0 .896.14 1.237.422.342.28.513.62.513 1.017zm9 2.63a7.29 7.29 0 0 0-.598-2.912 7.574 7.574 0 0 0-1.6-2.39 7.574 7.574 0 0 0-2.39-1.6A7.29 7.29 0 0 0 9 1.5a7.29 7.29 0 0 0-2.912.598 7.574 7.574 0 0 0-2.39 1.6 7.574 7.574 0 0 0-1.6 2.39A7.29 7.29 0 0 0 1.5 9c0 1.016.2 1.986.598 2.912a7.574 7.574 0 0 0 1.6 2.39 7.574 7.574 0 0 0 2.39 1.6A7.29 7.29 0 0 0 9 16.5a7.29 7.29 0 0 0 2.912-.598 7.574 7.574 0 0 0 2.39-1.6 7.574 7.574 0 0 0 1.6-2.39A7.29 7.29 0 0 0 16.5 9zM18 9a8.804 8.804 0 0 1-1.207 4.518 8.96 8.96 0 0 1-3.275 3.275A8.804 8.804 0 0 1 9 18a8.804 8.804 0 0 1-4.518-1.207 8.96 8.96 0 0 1-3.275-3.275A8.804 8.804 0 0 1 0 9c0-1.633.402-3.139 1.207-4.518a8.96 8.96 0 0 1 3.275-3.275A8.804 8.804 0 0 1 9 0c1.633 0 3.139.402 4.518 1.207a8.96 8.96 0 0 1 3.275 3.275A8.804 8.804 0 0 1 18 9z" fill-rule="evenodd"/></svg>
diff --git a/app/views/shared/icons/_emoji_smiley.svg b/app/views/shared/icons/_emoji_smiley.svg
deleted file mode 100644
index ddfae50e566..00000000000
--- a/app/views/shared/icons/_emoji_smiley.svg
+++ /dev/null
@@ -1 +0,0 @@
-<svg width="18" height="18" viewBox="0 0 18 18" xmlns="http://www.w3.org/2000/svg"><path d="M13.29 11.098a4.328 4.328 0 0 1-1.618 2.285c-.79.578-1.68.867-2.672.867-.992 0-1.883-.29-2.672-.867a4.328 4.328 0 0 1-1.617-2.285.721.721 0 0 1 .047-.569.715.715 0 0 1 .445-.369c.195-.062 7.41-.062 7.606 0 .195.063.34.186.433.37.094.183.11.372.047.568h.001zM7.5 6c0 .414-.146.768-.44 1.06A1.44 1.44 0 0 1 6 7.5a1.44 1.44 0 0 1-1.06-.44A1.445 1.445 0 0 1 4.5 6c0-.414.146-.768.44-1.06A1.44 1.44 0 0 1 6 4.5c.414 0 .768.146 1.06.44.294.292.44.646.44 1.06zm6 0c0 .414-.146.768-.44 1.06A1.44 1.44 0 0 1 12 7.5a1.44 1.44 0 0 1-1.06-.44A1.445 1.445 0 0 1 10.5 6c0-.414.146-.768.44-1.06A1.44 1.44 0 0 1 12 4.5c.414 0 .768.146 1.06.44.294.292.44.646.44 1.06zm3 3a7.29 7.29 0 0 0-.598-2.912 7.574 7.574 0 0 0-1.6-2.39 7.574 7.574 0 0 0-2.39-1.6A7.29 7.29 0 0 0 9 1.5a7.29 7.29 0 0 0-2.912.598 7.574 7.574 0 0 0-2.39 1.6 7.574 7.574 0 0 0-1.6 2.39A7.29 7.29 0 0 0 1.5 9c0 1.016.2 1.986.598 2.912a7.574 7.574 0 0 0 1.6 2.39 7.574 7.574 0 0 0 2.39 1.6c.92.397 1.91.6 2.912.598a7.29 7.29 0 0 0 2.912-.598 7.574 7.574 0 0 0 2.39-1.6 7.574 7.574 0 0 0 1.6-2.39c.397-.92.6-1.91.598-2.912zM18 9a8.804 8.804 0 0 1-1.207 4.518 8.96 8.96 0 0 1-3.275 3.275A8.804 8.804 0 0 1 9 18a8.804 8.804 0 0 1-4.518-1.207 8.96 8.96 0 0 1-3.275-3.275A8.804 8.804 0 0 1 0 9c0-1.633.402-3.139 1.207-4.518a8.96 8.96 0 0 1 3.275-3.275A8.804 8.804 0 0 1 9 0c1.633 0 3.139.402 4.518 1.207a8.96 8.96 0 0 1 3.275 3.275A8.804 8.804 0 0 1 18 9z" fill-rule="nonzero"/></svg>
diff --git a/app/views/snippets/notes/_actions.html.haml b/app/views/snippets/notes/_actions.html.haml
index 01b95145937..6e20890a47f 100644
--- a/app/views/snippets/notes/_actions.html.haml
+++ b/app/views/snippets/notes/_actions.html.haml
@@ -3,9 +3,9 @@
.note-actions-item
= link_to '#', title: _('Add reaction'), class: "note-action-button note-emoji-button js-add-award js-note-emoji has-tooltip", data: { position: 'right' } do
= icon('spinner spin')
- %span{ class: 'link-highlight award-control-icon-neutral' }= custom_icon('emoji_slightly_smiling_face')
- %span{ class: 'link-highlight award-control-icon-positive' }= custom_icon('emoji_smiley')
- %span{ class: 'link-highlight award-control-icon-super-positive' }= custom_icon('emoji_smile')
+ %span{ class: 'link-highlight award-control-icon-neutral' }= sprite_icon('slight-smile')
+ %span{ class: 'link-highlight award-control-icon-positive' }= sprite_icon('smiley')
+ %span{ class: 'link-highlight award-control-icon-super-positive' }= sprite_icon('smile')
- if note_editable
.note-actions-item
diff --git a/changelogs/unreleased/13453_minimal_atom_fix.yml b/changelogs/unreleased/13453_minimal_atom_fix.yml
new file mode 100644
index 00000000000..e0c18de3b1f
--- /dev/null
+++ b/changelogs/unreleased/13453_minimal_atom_fix.yml
@@ -0,0 +1,5 @@
+---
+title: Added a content field to atom feed
+merge_request: 27652
+author:
+type: fixed
diff --git a/changelogs/unreleased/38561-border-radii.yml b/changelogs/unreleased/38561-border-radii.yml
new file mode 100644
index 00000000000..510af18d651
--- /dev/null
+++ b/changelogs/unreleased/38561-border-radii.yml
@@ -0,0 +1,5 @@
+---
+title: Fix border radii on diff files and repo files
+merge_request:
+author:
+type: fixed
diff --git a/changelogs/unreleased/49041-issue-board-input-height.yml b/changelogs/unreleased/49041-issue-board-input-height.yml
new file mode 100644
index 00000000000..de3fbb2ee11
--- /dev/null
+++ b/changelogs/unreleased/49041-issue-board-input-height.yml
@@ -0,0 +1,5 @@
+---
+title: Reduce height of issue board input to align with buttons
+merge_request:
+author:
+type: other
diff --git a/changelogs/unreleased/56959-remove-auto-devops-domain-ci-variable.yml b/changelogs/unreleased/56959-remove-auto-devops-domain-ci-variable.yml
new file mode 100644
index 00000000000..c1c1708f935
--- /dev/null
+++ b/changelogs/unreleased/56959-remove-auto-devops-domain-ci-variable.yml
@@ -0,0 +1,5 @@
+---
+title: Removes support for AUTO_DEVOPS_DOMAIN
+merge_request: 28460
+author:
+type: removed
diff --git a/changelogs/unreleased/59026-replace-favicon.yml b/changelogs/unreleased/59026-replace-favicon.yml
new file mode 100644
index 00000000000..34228bb8438
--- /dev/null
+++ b/changelogs/unreleased/59026-replace-favicon.yml
@@ -0,0 +1,5 @@
+---
+title: Update favicon from next
+merge_request: 28601
+author: Jarek Ostrowski @jareko
+type: fixed
diff --git a/changelogs/unreleased/59987-move-sign-in-2fa-on-users-sign_in-above-intro-content-on-mobile.yml b/changelogs/unreleased/59987-move-sign-in-2fa-on-users-sign_in-above-intro-content-on-mobile.yml
new file mode 100644
index 00000000000..7863f1f7bbe
--- /dev/null
+++ b/changelogs/unreleased/59987-move-sign-in-2fa-on-users-sign_in-above-intro-content-on-mobile.yml
@@ -0,0 +1,5 @@
+---
+title: Prioritize login form on mobile breakpoint
+merge_request: 28360
+author:
+type: changed
diff --git a/changelogs/unreleased/60250-remove-mr_push_options-flag.yml b/changelogs/unreleased/60250-remove-mr_push_options-flag.yml
new file mode 100644
index 00000000000..b429d83dcc7
--- /dev/null
+++ b/changelogs/unreleased/60250-remove-mr_push_options-flag.yml
@@ -0,0 +1,5 @@
+---
+title: Remove the mr_push_options feature flag
+merge_request: 28278
+author:
+type: changed
diff --git a/changelogs/unreleased/60778-input-text-height.yml b/changelogs/unreleased/60778-input-text-height.yml
new file mode 100644
index 00000000000..c956ead5db2
--- /dev/null
+++ b/changelogs/unreleased/60778-input-text-height.yml
@@ -0,0 +1,5 @@
+---
+title: Fix input group height
+merge_request:
+author:
+type: other
diff --git a/changelogs/unreleased/61049-links-activity-stream.yml b/changelogs/unreleased/61049-links-activity-stream.yml
new file mode 100644
index 00000000000..3aac84adc31
--- /dev/null
+++ b/changelogs/unreleased/61049-links-activity-stream.yml
@@ -0,0 +1,5 @@
+---
+title: Use blue for activity stream links; use monospace font for commit sha
+merge_request:
+author:
+type: other
diff --git a/changelogs/unreleased/61313-fix-dropdown-searchbar.yml b/changelogs/unreleased/61313-fix-dropdown-searchbar.yml
new file mode 100644
index 00000000000..ba191a89da2
--- /dev/null
+++ b/changelogs/unreleased/61313-fix-dropdown-searchbar.yml
@@ -0,0 +1,5 @@
+---
+title: Fix loading.. dropdown at search field
+merge_request: 28275
+author: Pavel Chausov
+type: fixed
diff --git a/changelogs/unreleased/61393-emoji-button.yml b/changelogs/unreleased/61393-emoji-button.yml
new file mode 100644
index 00000000000..2bcfde308db
--- /dev/null
+++ b/changelogs/unreleased/61393-emoji-button.yml
@@ -0,0 +1,5 @@
+---
+title: Change default color of award emoji button
+merge_request:
+author:
+type: other
diff --git a/changelogs/unreleased/61827-prevent-user-popover-icon-shrink.yml b/changelogs/unreleased/61827-prevent-user-popover-icon-shrink.yml
new file mode 100644
index 00000000000..4d6464eed52
--- /dev/null
+++ b/changelogs/unreleased/61827-prevent-user-popover-icon-shrink.yml
@@ -0,0 +1,5 @@
+---
+title: Prevent icons from shrinking in User popover when contents exceed container
+merge_request: 28696
+author:
+type: fixed
diff --git a/changelogs/unreleased/61880-download-btn-group.yml b/changelogs/unreleased/61880-download-btn-group.yml
new file mode 100644
index 00000000000..c1f6b2767c6
--- /dev/null
+++ b/changelogs/unreleased/61880-download-btn-group.yml
@@ -0,0 +1,5 @@
+---
+title: Group download buttons into a .btn-group
+merge_request:
+author:
+type: other
diff --git a/changelogs/unreleased/62107-fix-detail-page-header-height.yml b/changelogs/unreleased/62107-fix-detail-page-header-height.yml
new file mode 100644
index 00000000000..3723f323bcc
--- /dev/null
+++ b/changelogs/unreleased/62107-fix-detail-page-header-height.yml
@@ -0,0 +1,5 @@
+---
+title: Fix the height of the page headers on issues/merge request/snippets pages
+merge_request: 28650
+author: Erik van der Gaag
+type: fixed
diff --git a/changelogs/unreleased/api_masked_variables.yml b/changelogs/unreleased/api_masked_variables.yml
new file mode 100644
index 00000000000..3605339cb91
--- /dev/null
+++ b/changelogs/unreleased/api_masked_variables.yml
@@ -0,0 +1,5 @@
+---
+title: 'API: Allow to get and set "masked" attribute for variables'
+merge_request: 28381
+author: Mathieu Parent
+type: added
diff --git a/changelogs/unreleased/fix-import-member-access.yml b/changelogs/unreleased/fix-import-member-access.yml
new file mode 100644
index 00000000000..5dc4ae738f8
--- /dev/null
+++ b/changelogs/unreleased/fix-import-member-access.yml
@@ -0,0 +1,5 @@
+---
+title: Fix issue importing members with owner access
+merge_request: 28636
+author:
+type: fixed
diff --git a/changelogs/unreleased/fix-milestone-references-with-escaped-html-entities.yml b/changelogs/unreleased/fix-milestone-references-with-escaped-html-entities.yml
new file mode 100644
index 00000000000..1041943f9c4
--- /dev/null
+++ b/changelogs/unreleased/fix-milestone-references-with-escaped-html-entities.yml
@@ -0,0 +1,5 @@
+---
+title: Fix milestone references containing &, <, or >
+merge_request: 28667
+author:
+type: fixed
diff --git a/changelogs/unreleased/jupyter_pre_spawn_hook_v2.yml b/changelogs/unreleased/jupyter_pre_spawn_hook_v2.yml
new file mode 100644
index 00000000000..c5918df8193
--- /dev/null
+++ b/changelogs/unreleased/jupyter_pre_spawn_hook_v2.yml
@@ -0,0 +1,5 @@
+---
+title: Pass user's identity and token from JupyterHub to user's Jupyter environment
+merge_request: 27314
+author: Amit Rathi
+type: added
diff --git a/changelogs/unreleased/patch-64.yml b/changelogs/unreleased/patch-64.yml
new file mode 100644
index 00000000000..1bf022e7e41
--- /dev/null
+++ b/changelogs/unreleased/patch-64.yml
@@ -0,0 +1,5 @@
+---
+title: Update SAST.gitlab-ci.yml - Add SAST_GITLEAKS_ENTROPY_LEVEL
+merge_request: 28607
+author:
+type: fixed
diff --git a/changelogs/unreleased/relative-urls-for-system-notes.yml b/changelogs/unreleased/relative-urls-for-system-notes.yml
new file mode 100644
index 00000000000..ec834e9f277
--- /dev/null
+++ b/changelogs/unreleased/relative-urls-for-system-notes.yml
@@ -0,0 +1,5 @@
+---
+title: Change links in system notes to use relative paths
+merge_request: 28588
+author: Luke Picciau
+type: fixed
diff --git a/changelogs/unreleased/sh-fix-omniauth-generic-strategy.yml b/changelogs/unreleased/sh-fix-omniauth-generic-strategy.yml
new file mode 100644
index 00000000000..561c19c9685
--- /dev/null
+++ b/changelogs/unreleased/sh-fix-omniauth-generic-strategy.yml
@@ -0,0 +1,5 @@
+---
+title: Fix OmniAuth OAuth2Generic strategy not loading
+merge_request: 28680
+author:
+type: fixed
diff --git a/changelogs/unreleased/update-smileys-new.yml b/changelogs/unreleased/update-smileys-new.yml
new file mode 100644
index 00000000000..0e3f606c81b
--- /dev/null
+++ b/changelogs/unreleased/update-smileys-new.yml
@@ -0,0 +1,5 @@
+---
+title: Update new smiley icons, find n replace old names with new ones
+merge_request: 28338
+author: Jarek Ostrowski
+type: changed
diff --git a/config/database.yml.example b/config/database.yml.example
new file mode 100644
index 00000000000..e69de29bb2d
--- /dev/null
+++ b/config/database.yml.example
diff --git a/config/initializers/rack_attack_logging.rb b/config/initializers/rack_attack_logging.rb
index 8bb9ea29c33..2a3fdc8de5f 100644
--- a/config/initializers/rack_attack_logging.rb
+++ b/config/initializers/rack_attack_logging.rb
@@ -1,7 +1,15 @@
+# frozen_string_literal: true
+#
# Adds logging for all Rack Attack blocks and throttling events.
ActiveSupport::Notifications.subscribe('rack.attack') do |name, start, finish, request_id, req|
if [:throttle, :blacklist].include? req.env['rack.attack.match_type']
- Rails.logger.info("Rack_Attack: #{req.env['rack.attack.match_type']} #{req.ip} #{req.request_method} #{req.fullpath}")
+ Gitlab::AuthLogger.error(
+ message: 'Rack_Attack',
+ env: req.env['rack.attack.match_type'],
+ ip: req.ip,
+ request_method: req.request_method,
+ fullpath: req.fullpath
+ )
end
end
diff --git a/config/karma.config.js b/config/karma.config.js
index b2fc3a32816..2a5bf3581e0 100644
--- a/config/karma.config.js
+++ b/config/karma.config.js
@@ -9,11 +9,22 @@ const IS_EE = require('./helpers/is_ee_env');
const ROOT_PATH = path.resolve(__dirname, '..');
const SPECS_PATH = /^(?:\.[\\\/])?(ee[\\\/])?spec[\\\/]javascripts[\\\/]/;
-function fatalError(message) {
+function exitError(message) {
console.error(chalk.red(`\nError: ${message}\n`));
process.exit(1);
}
+function exitWarn(message) {
+ console.error(chalk.yellow(`\nWarn: ${message}\n`));
+ process.exit(0);
+}
+
+function exit(message, isError = true) {
+ const fn = isError ? exitError : exitWarn;
+
+ fn(message);
+}
+
// disable problematic options
webpackConfig.entry = undefined;
webpackConfig.mode = 'development';
@@ -31,7 +42,8 @@ webpackConfig.plugins.push(
}),
);
-const specFilters = argumentsParser
+const options = argumentsParser
+ .option('--no-fail-on-empty-test-suite')
.option(
'-f, --filter-spec [filter]',
'Filter run spec files by path. Multiple filters are like a logical OR.',
@@ -41,7 +53,9 @@ const specFilters = argumentsParser
},
[],
)
- .parse(process.argv).filterSpec;
+ .parse(process.argv);
+
+const specFilters = options.filterSpec;
const createContext = (specFiles, regex, suffix) => {
const newContext = specFiles.reduce((context, file) => {
@@ -73,11 +87,13 @@ if (specFilters.length) {
filteredSpecFiles = [...new Set(filteredSpecFiles)];
if (filteredSpecFiles.length < 1) {
- fatalError('Your filter did not match any test files.');
+ const isError = options.failOnEmptyTestSuite;
+
+ exit('Your filter did not match any test files.', isError);
}
if (!filteredSpecFiles.every(file => SPECS_PATH.test(file))) {
- fatalError('Test files must be located within /spec/javascripts.');
+ exitError('Test files must be located within /spec/javascripts.');
}
const CE_FILES = filteredSpecFiles.filter(file => !file.startsWith('ee'));
diff --git a/doc/administration/logs.md b/doc/administration/logs.md
index 3d40cda491a..a7e57e44e86 100644
--- a/doc/administration/logs.md
+++ b/doc/administration/logs.md
@@ -280,6 +280,14 @@ installations from source.
Currently it logs the progress of project imports from the Bitbucket Server
importer. Future importers may use this file.
+## `auth.log`
+
+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.
+
+It logs information whenever [Rack Attack] registers an abusive request.
+
## Reconfigure Logs
Reconfigure log files live in `/var/log/gitlab/reconfigure` for Omnibus GitLab
@@ -298,3 +306,4 @@ Omnibus GitLab packages or in `/home/git/gitlab/log/sidekiq_exporter.log` for
installations from source.
[repocheck]: repository_checks.md
+[Rack Attack]: ../security/rack_attack.md
diff --git a/doc/api/epic_links.md b/doc/api/epic_links.md
index 619ae6ea2dc..d6e43ae7074 100644
--- a/doc/api/epic_links.md
+++ b/doc/api/epic_links.md
@@ -125,7 +125,7 @@ POST /groups/:id/epics/:epic_iid/epics
| --------------- | -------------- | -------- | ------------------------------------------------------------------------------------------------------------------ |
| `id` | integer/string | yes | The ID or [URL-encoded path of the group](README.md#namespaced-path-encoding) owned by the authenticated user |
| `epic_iid` | integer | yes | The internal ID of the (future parent) epic. |
-| `title` | integer | yes | The global ID of the child epic. Internal ID can't be used because they can conflict with epics from other groups. |
+| `title` | string | yes | The title of a newly created epic. |
```bash
curl --header POST "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/groups/1/epics/5/epics?title=Newpic
@@ -141,6 +141,7 @@ Example response:
"group_id": 49,
"parent_id": 23,
"has_children": false,
+ "has_issues": false,
"reference": "&2",
"url": "http://localhost/groups/group16/-/epics/2",
"relation_url": "http://localhost/groups/group16/-/epics/1/links/24"
diff --git a/doc/api/project_level_variables.md b/doc/api/project_level_variables.md
index 4a6f5624394..3b00f6f140e 100644
--- a/doc/api/project_level_variables.md
+++ b/doc/api/project_level_variables.md
@@ -52,7 +52,9 @@ curl --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/a
{
"key": "TEST_VARIABLE_1",
"variable_type": "env_var",
- "value": "TEST_1"
+ "value": "TEST_1",
+ "protected": false,
+ "masked": true
}
```
@@ -71,6 +73,7 @@ POST /projects/:id/variables
| `value` | string | yes | The `value` of a variable |
| `variable_type` | string | no | The type of a variable. Available types are: `env_var` (default) and `file` |
| `protected` | boolean | no | Whether the variable is protected |
+| `masked` | boolean | no | Whether the variable is masked |
```
curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/1/variables" --form "key=NEW_VARIABLE" --form "value=new value"
@@ -81,7 +84,8 @@ curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" "https://gitla
"key": "NEW_VARIABLE",
"value": "new value",
"variable_type": "env_var",
- "protected": false
+ "protected": false,
+ "masked": false
}
```
@@ -100,6 +104,7 @@ PUT /projects/:id/variables/:key
| `value` | string | yes | The `value` of a variable |
| `variable_type` | string | no | The type of a variable. Available types are: `env_var` (default) and `file` |
| `protected` | boolean | no | Whether the variable is protected |
+| `masked` | boolean | no | Whether the variable is masked |
```
curl --request PUT --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/1/variables/NEW_VARIABLE" --form "value=updated value"
@@ -110,7 +115,8 @@ curl --request PUT --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab
"key": "NEW_VARIABLE",
"value": "updated value",
"variable_type": "env_var",
- "protected": true
+ "protected": true,
+ "masked": false
}
```
diff --git a/doc/ci/yaml/README.md b/doc/ci/yaml/README.md
index 31ff56e06f8..8667eacd3d5 100644
--- a/doc/ci/yaml/README.md
+++ b/doc/ci/yaml/README.md
@@ -1986,7 +1986,7 @@ production:
- deploy
environment:
name: production
- url: https://$CI_PROJECT_PATH_SLUG.$AUTO_DEVOPS_DOMAIN
+ url: https://$CI_PROJECT_PATH_SLUG.$KUBE_INGRESS_BASE_DOMAIN
only:
- master
```
diff --git a/doc/development/contributing/issue_workflow.md b/doc/development/contributing/issue_workflow.md
index fef94c0a4b5..e3a1dc711fd 100644
--- a/doc/development/contributing/issue_workflow.md
+++ b/doc/development/contributing/issue_workflow.md
@@ -7,7 +7,7 @@ scheduling into milestones. Labelling is a task for everyone.
Most issues will have labels for at least one of the following:
- Type: ~feature, ~bug, ~customer, etc.
-- Subject: ~wiki, ~"container registry", ~ldap, ~api, ~frontend, etc.
+- Subject: ~wiki, ~"Container Registry", ~ldap, ~api, ~frontend, etc.
- Team: ~Plan, ~Manage, ~Quality, etc.
- Stage: ~"devops:plan", ~"devops:create", etc.
- Release Scoping: ~Deliverable, ~Stretch, ~"Next Patch Release"
@@ -44,7 +44,7 @@ Subject labels are labels that define what area or feature of GitLab this issue
hits. They are not always necessary, but very convenient.
Examples of subject labels are ~wiki, ~ldap, ~api,
-~issues, ~"merge requests", ~labels, and ~"container registry".
+~issues, ~"merge requests", ~labels, and ~"Container Registry".
If you are an expert in a particular area, it makes it easier to find issues to
work on. You can also subscribe to those labels to receive an email each time an
@@ -92,20 +92,21 @@ Stage labels specify which [DevOps stage][devops-stages] the issue belongs to.
The current stage labels are:
-- ~"devops:manage"
-- ~"devops:plan"
-- ~"devops:create"
-- ~"devops:verify"
-- ~"devops:package"
-- ~"devops:release"
-- ~"devops:configure"
-- ~"devops:monitor"
-- ~"devops:secure"
-- ~"devops:defend"
-- ~"devops:enablement"
-
-These labels should be mutually exclusive. If an issue belongs to multiple
-stages, the most relevant should be used.
+- ~"devops::manage"
+- ~"devops::plan"
+- ~"devops::create"
+- ~"devops::verify"
+- ~"devops::package"
+- ~"devops::release"
+- ~"devops::configure"
+- ~"devops::monitor"
+- ~"devops::secure"
+- ~"devops::defend"
+- ~"devops::growth"
+- ~"devops::enablement"
+
+These labels are [scoped labels](../../user/project/labels.md#scoped-labels-premium)
+and thus are mutually exclusive.
They differ from the [Team labels](#team-labels) because teams may work on
issues outside their stage.
@@ -127,20 +128,18 @@ Group labels specify which [groups][structure-groups] the issue belongs to.
Examples include:
-- ~"group:control"
-- ~"group:editor"
+- ~"group::control"
+- ~"group::editor"
-These labels should be mutually exclusive. If an issue belongs to multiple
-groups, the most relevant should be used.
+These labels are [scoped labels](../../user/project/labels.md#scoped-labels-premium)
+and thus are mutually exclusive.
Groups are nested beneath a particular stage, so only one stage label and one group label
-should be applied to a single issue. You can find the groups listed in the
-[Product Categories pages][product-categories]. For example, ~"group:control" and
-~"group:framework" labels can be applied to issues related to the [Manage stage][manage-stage].
+can be applied to a single issue. You can find the groups listed in the
+[Product Categories pages][product-categories].
[structure-groups]: https://about.gitlab.com/company/team/structure/#groups
[product-categories]: https://about.gitlab.com/handbook/product/categories/
-[manage-stage]: https://about.gitlab.com/handbook/product/categories/#manage-stage
## Release Scoping labels
diff --git a/doc/development/fe_guide/style_guide_scss.md b/doc/development/fe_guide/style_guide_scss.md
index 36880dd746d..b25dce65ffe 100644
--- a/doc/development/fe_guide/style_guide_scss.md
+++ b/doc/development/fe_guide/style_guide_scss.md
@@ -9,20 +9,44 @@ easy to maintain, and performant for the end-user.
As part of the effort for [cleaning up our CSS and moving our components into GitLab-UI](https://gitlab.com/groups/gitlab-org/-/epics/950)
led by the [GitLab UI WG](https://gitlab.com/gitlab-com/www-gitlab-com/merge_requests/20623) we prefer the use of utility classes over adding new CSS. However, complex CSS can be addressed by adding component classes.
-We have a few internal utility classes in [`common.scss`](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/app/assets/stylesheets/framework/common.scss)
-and we use [Bootstrap's Utility Classes](https://getbootstrap.com/docs/4.3/utilities/)
+#### Where are utility classes defined?
+
+- [Bootstrap's Utility Classes](https://getbootstrap.com/docs/4.3/utilities/)
+- [`common.scss`](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/app/assets/stylesheets/framework/common.scss) (old)
+- [`utilities.scss`](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/app/assets/stylesheets/utilities.scss) (new)
+
+#### Where should I put new utility classes?
New utility classes should be added to [`utilities.scss`](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/app/assets/stylesheets/utilities.scss). Existing classes include:
-**Background color**: `.bg-variant-shade` e.g. `.bg-warning-400`
-**Text color**: `.text-variant-shade` e.g. `.text-success-500`
+| Name | Pattern | Example |
+|------|---------|---------|
+| Background color | `.bg-{variant}-{shade}` | `.bg-warning-400` |
+| Text color | `.text-{variant}-{shade}` | `.text-success-500` |
+| Font size | `.text-{size}` | `.text-2` |
+
+- `{variant}` is one of 'primary', 'secondary', 'success', 'warning', 'error'
+- `{shade}` is on of the shades listed on [colors](https://design.gitlab.com/foundations/colors/)
+- `{size}` is a number from 1-6 from our [Type scale](https://design.gitlab.com/foundations/typography)
+
+#### When should I create component classes?
+
+We recommend a "utility-first" approach.
+
+1. Start with utility classes.
+2. If composing utility classes into a component class removes code duplication and encapsulates a clear responsibility, do it.
+
+This encourages an organic growth of component classes and prevents the creation of one-off unreusable classes. Also, the kind of classes that emerge from "utility-first" tend to be design-centered (e.g. `.button`, `.alert`, `.card`) rather than domain-centered (e.g. `.security-report-widget`, `.commit-header-icon`).
+
+Examples of component classes that were created using "utility-first" include:
-- variant is one of 'primary', 'secondary', 'success', 'warning', 'error'
-- shade is on of the shades listed on [colors](https://design.gitlab.com/foundations/colors/)
+- [`.circle-icon-container`](https://gitlab.com/gitlab-org/gitlab-ce/blob/579fa8b8ec7eb38d40c96521f517c9dab8c3b97a/app/assets/stylesheets/framework/icons.scss#L85)
+- [`.d-flex-center`](https://gitlab.com/gitlab-org/gitlab-ce/blob/900083d89cd6af391d26ab7922b3f64fa2839bef/app/assets/stylesheets/framework/common.scss#L425)
-**Font size**: `.text-size` e.g. `.text-2`
+Inspiration:
-- **size** is number from 1-6 from our [Type scale](https://design.gitlab.com/foundations/typography)
+- https://tailwindcss.com/docs/utility-first
+- https://tailwindcss.com/docs/extracting-components
### Naming
diff --git a/doc/development/i18n/externalization.md b/doc/development/i18n/externalization.md
index 38d56322de8..38425674567 100644
--- a/doc/development/i18n/externalization.md
+++ b/doc/development/i18n/externalization.md
@@ -195,6 +195,7 @@ For example use `%{created_at}` in Ruby but `%{createdAt}` in JavaScript.
Sometimes you need to add some context to the text that you want to translate
(if the word occurs in a sentence and/or the word is ambiguous).
+Namespaces should be PascalCase.
- In Ruby/HAML:
diff --git a/doc/development/migration_style_guide.md b/doc/development/migration_style_guide.md
index 0c326eeb851..9b26f691b55 100644
--- a/doc/development/migration_style_guide.md
+++ b/doc/development/migration_style_guide.md
@@ -186,7 +186,11 @@ end
When adding a foreign-key constraint to either an existing or new
column remember to also add a index on the column.
-This is _required_ for all foreign-keys.
+This is **required** for all foreign-keys, e.g., to support efficient cascading
+deleting: when a lot of rows in a table get deleted, the referenced records need
+to be deleted too. The database has to look for corresponding records in the
+referenced table. Without an index, this will result in a sequential scan on the
+table which can take a long time.
Here's an example where we add a new column with a foreign key
constraint. Note it includes `index: true` to create an index for it.
diff --git a/doc/security/rack_attack.md b/doc/security/rack_attack.md
index ad83dc05a93..66081d7e376 100644
--- a/doc/security/rack_attack.md
+++ b/doc/security/rack_attack.md
@@ -94,7 +94,7 @@ In case you want to remove a blocked IP, follow these steps:
1. Find the IPs that have been blocked in the production log:
```sh
- grep "Rack_Attack" /var/log/gitlab/gitlab-rails/production.log
+ grep "Rack_Attack" /var/log/gitlab/gitlab-rails/auth.log
```
1. Since the blacklist is stored in Redis, you need to open up `redis-cli`:
diff --git a/doc/topics/autodevops/index.md b/doc/topics/autodevops/index.md
index 5a8744d71f9..4ceccaabf86 100644
--- a/doc/topics/autodevops/index.md
+++ b/doc/topics/autodevops/index.md
@@ -126,10 +126,6 @@ Auto Deploy, and Auto Monitoring will be silently skipped.
## Auto DevOps base domain
-NOTE: **Note**
-`AUTO_DEVOPS_DOMAIN` environment variable is deprecated and
-[is scheduled to be removed](https://gitlab.com/gitlab-org/gitlab-ce/issues/56959).
-
The Auto DevOps base domain is required if you want to make use of [Auto
Review Apps](#auto-review-apps) and [Auto Deploy](#auto-deploy). It can be defined
in any of the following places:
@@ -162,6 +158,12 @@ Auto DevOps base domain to `1.2.3.4.nip.io`.
Once set up, all requests will hit the load balancer, which in turn will route
them to the Kubernetes pods that run your application(s).
+NOTE: **Note:**
+From GitLab 11.8, `KUBE_INGRESS_BASE_DOMAIN` replaces `AUTO_DEVOPS_DOMAIN`.
+Support for `AUTO_DEVOPS_DOMAIN` was [removed in GitLab
+12.0](https://gitlab.com/gitlab-org/gitlab-ce/issues/56959).
+
+
## Using multiple Kubernetes clusters **[PREMIUM]**
When using Auto DevOps, you may want to deploy different environments to
@@ -209,10 +211,6 @@ and verifying that your app is deployed as a review app in the Kubernetes
cluster with the `review/*` environment scope. Similarly, you can check the
other environments.
-NOTE: **Note:**
-From GitLab 11.8, `KUBE_INGRESS_BASE_DOMAIN` replaces `AUTO_DEVOPS_DOMAIN`.
-`AUTO_DEVOPS_DOMAIN` [is scheduled to be removed](https://gitlab.com/gitlab-org/gitlab-ce/issues/56959).
-
## Enabling/Disabling Auto DevOps
When first using Auto Devops, review the [requirements](#requirements) to ensure all necessary components to make
@@ -734,7 +732,6 @@ also be customized, and you can easily use a [custom buildpack](#custom-buildpac
| **Variable** | **Description** |
| ------------ | --------------- |
-| `AUTO_DEVOPS_DOMAIN` | The [Auto DevOps domain](#auto-devops-base-domain). By default, set automatically by the [Auto DevOps setting](#enablingdisabling-auto-devops). This variable is deprecated and [is scheduled to be removed](https://gitlab.com/gitlab-org/gitlab-ce/issues/56959). Use `KUBE_INGRESS_BASE_DOMAIN` instead. |
| `AUTO_DEVOPS_CHART` | The Helm Chart used to deploy your apps; defaults to the one [provided by GitLab](https://gitlab.com/gitlab-org/charts/auto-deploy-app). |
| `AUTO_DEVOPS_CHART_REPOSITORY` | The Helm Chart repository used to search for charts; defaults to `https://charts.gitlab.io`. |
| `AUTO_DEVOPS_CHART_REPOSITORY_NAME` | From Gitlab 11.11, this variable can be used to set the name of the helm repository; defaults to "gitlab" |
diff --git a/doc/user/admin_area/geo_nodes.md b/doc/user/admin_area/geo_nodes.md
index 776ab139c64..fb0f9a3285d 100644
--- a/doc/user/admin_area/geo_nodes.md
+++ b/doc/user/admin_area/geo_nodes.md
@@ -1,9 +1,13 @@
+---
+type: howto
+---
+
# Geo nodes admin area **[PREMIUM ONLY]**
-For more information about setting up GitLab Geo, read the
-[Geo documentation](https://docs.gitlab.com/ee/administration/geo/replication/index.html).
+You can configure various settings for GitLab Geo nodes. For more information, see
+[Geo documentation](https://docs.gitlab.com/ee/administration/geo/replication/index.md).
-When you're done, you can navigate to **Admin area > Geo** (`/admin/geo/nodes`).
+On the primary node, go to **Admin area > Geo**. On secondary nodes, go to **Admin area > Geo > Nodes**.
## Common settings
@@ -68,3 +72,15 @@ a unique `name` is set for each Geo node. The `gitlab.rb` setting
The load balancer must use sticky sessions in order to avoid authentication
failures and cross site request errors.
+
+<!-- ## Troubleshooting
+
+Include any troubleshooting steps that you can foresee. If you know beforehand what issues
+one might have when setting this up, or when something is changed, or on upgrading, it's
+important to describe those, too. Think of things that may go wrong and include them here.
+This is important to minimize requests for support, and to avoid doc comments with
+questions that you know someone might ask.
+
+Each scenario can be a third-level heading, e.g. `### Getting error message X`.
+If you have none to add when creating a doc, leave this section in place
+but commented out to help encourage others to add to it in the future. --> \ No newline at end of file
diff --git a/doc/user/admin_area/settings/continuous_integration.md b/doc/user/admin_area/settings/continuous_integration.md
index 9dd476656ed..6c4abce83c2 100644
--- a/doc/user/admin_area/settings/continuous_integration.md
+++ b/doc/user/admin_area/settings/continuous_integration.md
@@ -1,3 +1,7 @@
+---
+type: reference
+---
+
# Continuous Integration and Deployment Admin settings **[CORE ONLY]**
In this area, you will find settings for Auto DevOps, Runners and job artifacts.
@@ -145,3 +149,15 @@ To set the duration for which the jobs will be considered as old and expired:
Once that time passes, the jobs will be archived and no longer able to be
retried. Make it empty to never expire jobs. It has to be no less than 1 day,
for example: <code>15 days</code>, <code>1 month</code>, <code>2 years</code>.
+
+<!-- ## Troubleshooting
+
+Include any troubleshooting steps that you can foresee. If you know beforehand what issues
+one might have when setting this up, or when something is changed, or on upgrading, it's
+important to describe those, too. Think of things that may go wrong and include them here.
+This is important to minimize requests for support, and to avoid doc comments with
+questions that you know someone might ask.
+
+Each scenario can be a third-level heading, e.g. `### Getting error message X`.
+If you have none to add when creating a doc, leave this section in place
+but commented out to help encourage others to add to it in the future. --> \ No newline at end of file
diff --git a/doc/user/admin_area/settings/email.md b/doc/user/admin_area/settings/email.md
index 01a98cf15dc..912c2cff481 100644
--- a/doc/user/admin_area/settings/email.md
+++ b/doc/user/admin_area/settings/email.md
@@ -1,12 +1,18 @@
+---
+type: reference
+---
+
# Email
+You can customize some of the content in emails sent from your GitLab instance.
+
## Custom logo
The logo in the header of some emails can be customized, see the [logo customization section](../../../customization/branded_page_and_email_header.md).
## Custom additional text **[PREMIUM ONLY]**
->[Introduced][ee-5031] in [GitLab Premium][eep] 10.7.
+> [Introduced][ee-5031] in [GitLab Premium][eep] 10.7.
The additional text will appear at the bottom of any email and can be used for
legal/auditing/compliance reasons.
@@ -24,8 +30,8 @@ legal/auditing/compliance reasons.
> [Introduced](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/22560) in GitLab 11.5.
-This configuration option sets the email hostname for [private commit emails](../../profile/index.md#private-commit-email),
-and it's, by default, set to `users.noreply.YOUR_CONFIGURED_HOSTNAME`.
+This configuration option sets the email hostname for [private commit emails](../../profile/index.md#private-commit-email).
+ By default it is set to `users.noreply.YOUR_CONFIGURED_HOSTNAME`.
In order to change this option:
@@ -36,3 +42,15 @@ In order to change this option:
NOTE: **Note**: Once the hostname gets configured, every private commit email using the previous hostname, will not get
recognized by GitLab. This can directly conflict with certain [Push rules](https://docs.gitlab.com/ee/push_rules/push_rules.html) such as
`Check whether author is a GitLab user` and `Check whether committer is the current authenticated user`.
+
+<!-- ## Troubleshooting
+
+Include any troubleshooting steps that you can foresee. If you know beforehand what issues
+one might have when setting this up, or when something is changed, or on upgrading, it's
+important to describe those, too. Think of things that may go wrong and include them here.
+This is important to minimize requests for support, and to avoid doc comments with
+questions that you know someone might ask.
+
+Each scenario can be a third-level heading, e.g. `### Getting error message X`.
+If you have none to add when creating a doc, leave this section in place
+but commented out to help encourage others to add to it in the future. --> \ No newline at end of file
diff --git a/doc/user/admin_area/settings/external_authorization.md b/doc/user/admin_area/settings/external_authorization.md
index 06e00e02f3d..11c0867da17 100644
--- a/doc/user/admin_area/settings/external_authorization.md
+++ b/doc/user/admin_area/settings/external_authorization.md
@@ -1,3 +1,7 @@
+---
+type: reference
+---
+
# External authorization control **[CORE ONLY]**
> [Introduced](https://gitlab.com/gitlab-org/gitlab-ee/issues/4216) in
@@ -108,5 +112,17 @@ The label will be shown on all project pages in the upper right corner.
![classification label on project page](img/classification_label_on_project_page.png)
+<!-- ## Troubleshooting
+
+Include any troubleshooting steps that you can foresee. If you know beforehand what issues
+one might have when setting this up, or when something is changed, or on upgrading, it's
+important to describe those, too. Think of things that may go wrong and include them here.
+This is important to minimize requests for support, and to avoid doc comments with
+questions that you know someone might ask.
+
+Each scenario can be a third-level heading, e.g. `### Getting error message X`.
+If you have none to add when creating a doc, leave this section in place
+but commented out to help encourage others to add to it in the future. -->
+
[omnibus-ssl-docs]: https://docs.gitlab.com/omnibus/settings/ssl.html
[omnibus-log-docs]: https://docs.gitlab.com/omnibus/settings/logs.html
diff --git a/doc/user/group/index.md b/doc/user/group/index.md
index a5e3bfda70e..7493e65e237 100644
--- a/doc/user/group/index.md
+++ b/doc/user/group/index.md
@@ -5,33 +5,35 @@ and grant members access to several projects at once.
Groups can also be nested in [subgroups](subgroups/index.md).
-Find your groups by clicking **Groups** in the top navigation.
+Find your groups by clicking **Groups > Your Groups** in the top navigation.
![GitLab Groups](img/groups.png)
> The groups dropdown in the top navigation was [introduced][ce-36234] in [GitLab 11.1](https://about.gitlab.com/2018/07/22/gitlab-11-1-released/#groups-dropdown-in-navigation).
-The Groups page displays all groups you are a member of, how many projects it holds,
-how many members it has, the group visibility, and, if you have enough permissions,
-a link to the group settings. By clicking the last button you can leave that group.
+The Groups page displays:
+
+- All groups you are a member of.
+- How many projects each group contains.
+- How many members a group has.
+- The group visibility.
+- A link to the group settings if you have sufficient permissions.
+
+By clicking the last button, you can leave that group.
## Use cases
-You can create groups for numerous reasons. To name a few:
-
-- Organize related projects under the same [namespace](#namespaces), add members to that
- group and grant access to all their projects at once
-- Create a group, include members of your team, and make it easier to
- `@mention` all the team at once in issues and merge requests
- - Create a group for your company members, and create [subgroups](subgroups/index.md)
- for each individual team. Let's say you create a group called `company-team`, and among others,
- you created subgroups in this group for each individual team `backend-team`,
- `frontend-team`, and `production-team`:
- 1. When you start a new implementation from an issue, you add a comment:
+You can create groups for numerous reasons. To name a couple:
+
+- Grant access to multiple projects and multiple team members in fewer steps by organizing related projects under the same [namespace](#namespaces) and adding members to the top-level group.
+- Make it easier to `@mention` all of your team at once in issues and merge requests by creating a group and including the appropriate members.
+
+For example, you could create a group for your company members, and create a [subgroup](subgroups/index.md) for each individual team. Let's say you create a group called `company-team`, and you create subgroups in this group for the individual teams `backend-team`, `frontend-team`, and `production-team`.
+ - When you start a new implementation from an issue, you add a comment:
_"`@company-team`, let's do it! `@company-team/backend-team` you're good to go!"_
- 1. When your backend team needs help from frontend, they add a comment:
+ - When your backend team needs help from frontend, they add a comment:
_"`@company-team/frontend-team` could you help us here please?"_
- 1. When the frontend team completes their implementation, they comment:
+ - When the frontend team completes their implementation, they comment:
_"`@company-team/backend-team`, it's done! Let's ship it `@company-team/production-team`!"_
## Namespaces
@@ -59,8 +61,8 @@ By doing so:
## Issues and merge requests within a group
-Issues and merge requests are part of projects. For a given group, view all the
-[issues](../project/issues/index.md#issues-list) and [merge requests](../project/merge_requests/index.md#merge-requests-per-group) across all the projects in that group,
+Issues and merge requests are part of projects. For a given group, you can view all of the
+[issues](../project/issues/index.md#issues-list) and [merge requests](../project/merge_requests/index.md#merge-requests-per-group) across all projects in that group,
together in a single list view.
## Create a new group
@@ -68,13 +70,13 @@ together in a single list view.
> For a list of words that are not allowed to be used as group names see the
> [reserved names](../reserved_names.md).
-You can create a group in GitLab from:
+To create a new Group, either:
-1. The Groups page: from the top menu, click **Groups**, and click the green button **New group**:
+- In the top menu, click **Groups** and then **Your Groups**, and click the green button **New group**.
![new group from groups page](img/new_group_from_groups.png)
-1. Elsewhere: expand the `plus` sign button on the top navbar and choose **New group**:
+- Or, in the top menu, expand the `plus` sign and choose **New group**.
![new group from elsewhere](img/new_group_from_other_pages.png)
@@ -82,18 +84,18 @@ Add the following information:
![new group info](img/create_new_group_info.png)
-1. The **Group name** will populate the URL automatically. Optionally, you can change it.
- This is the name that is displayed in the group views.
+1. The **Group name** will automatically populate the URL. Optionally, you can change it.
+ This is the name that displays in group views.
The name can contain only:
- - Alphanumeric characters.
- - Underscores.
- - Dashes and dots.
- - Spaces.
-1. The **Group URL**, which will be the namespace under which your projects will be hosted.
+ - Alphanumeric characters
+ - Underscores
+ - Dashes and dots
+ - Spaces
+1. The **Group URL** is the namespace under which your projects will be hosted.
The URL can contain only:
- - Alphanumeric characters.
- - Underscores.
- - Dashes and dots. It cannot start with dashes or end in dot.
+ - Alphanumeric characters
+ - Underscores
+ - Dashes and dots (it cannot start with dashes or end in a dot)
1. Optionally, you can add a brief description to tell others
what this group is about.
1. Optionally, choose an avatar for your group.
@@ -101,45 +103,39 @@ Add the following information:
## Add users to a group
-Add members to a group by navigating to the group's dashboard, and clicking **Members**:
+A benefit of putting multiple projects in one group is that you can
+give a user to access to all projects in the group with one action.
+
+Add members to a group by navigating to the group's dashboard and clicking **Members**.
![add members to group](img/add_new_members.png)
-Select the [permission level](../permissions.md#permissions) and add the new member. You can also set the expiring
-date for that user, from which they will no longer have access to your group.
+Select the [permission level](../permissions.md#permissions), and add the new member. You can also set the expiring date for that user; this is the date on which they will no longer have access to your group.
-One of the benefits of putting multiple projects in one group is that you can
-give a user to access to all projects in the group with one action.
+Consider a group with two projects:
-Consider we have a group with two projects:
-
-- On the **Group Members** page we can now add a new user to the group.
-- Now because this user is a **Developer** member of the group, he automatically
+- On the **Group Members** page, you can now add a new user to the group.
+- Now, because this user is a **Developer** member of the group, they automatically
gets **Developer** access to **all projects** within that group.
-If necessary, you can increase the access level of an individual user for a specific project,
-by adding them again as a new member to the project with the new permission levels.
+To increase the access level of an existing user for a specific project,
+add them again as a new member to the project with the desired permission level.
## Request access to a group
-As a group owner you can enable or disable non members to request access to
-your group. Go to the group settings and click on **Allow users to request access**.
+As a group owner, you can enable or disable the ability for non members to request access to
+your group. Go to the group settings, and click **Allow users to request access**.
-As a user, you can request to be a member of a group. Go to the group you'd
-like to be a member of, and click the **Request Access** button on the right
+As a user, you can request to be a member of a group, if that setting is enabled. Go to the group for which you'd like to be a member, and click the **Request Access** button on the right
side of your screen.
![Request access button](img/request_access_button.png)
----
-
Group owners and maintainers will be notified of your request and will be able to approve or
decline it on the members page.
![Manage access requests](img/access_requests_management.png)
----
-
If you change your mind before your request is approved, just click the
**Withdraw Access Request** button.
@@ -149,29 +145,27 @@ If you change your mind before your request is approved, just click the
There are two different ways to add a new project to a group:
-- Select a group and then click on the **New project** button.
+- Select a group, and then click **New project**. You can then continue [creating your project](../../gitlab-basics/create-project.md).
![New project](img/create_new_project_from_group.png)
- You can then continue on [creating a project](../../gitlab-basics/create-project.md).
-
- While you are creating a project, select a group namespace
you've already created from the dropdown menu.
![Select group](img/select_group_dropdown.png)
-### Default project creation level
+### Default project-creation level
> [Introduced][ee-2534] in [GitLab Premium][ee] 10.5.
> Brought to [GitLab Starter][ee] in 10.7.
> [Moved](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/25975) to [GitLab Core](https://about.gitlab.com/pricing/) in 11.10.
-Group owners or administrators can allow users with the
+Group owners and administrators can allow users with the
Developer role to create projects under groups.
-By default, [Developers and Maintainers](../permissions.md#group-members-permissions) can create projects under a group, but this can be changed either within the group settings for a group, or
-be set globally by a GitLab administrator in the Admin area
-at **Settings > General > Visibility and access controls**.
+By default, [Developers and Maintainers](../permissions.md#group-members-permissions) can create projects under a group. You can change this setting for a specific group within the group settings, or
+you can set this option globally in the Admin area
+at **Settings > General > Visibility and access controls** (you must be a GitLab administrator).
Available settings are `No one`, `Maintainers`, or `Developers + Maintainers`.
@@ -182,13 +176,13 @@ Learn how to [transfer a project into a group](../project/settings/index.md#tran
## Sharing a project with a group
You can [share your projects with a group](../project/members/share_project_with_groups.md)
-and give your group members access to the project all at once.
+and give all group members access to the project at once.
Alternatively, you can [lock the sharing with group feature](#share-with-group-lock).
## Manage group memberships via LDAP
-In GitLab Enterprise Edition it is possible to manage GitLab group memberships using LDAP groups.
+In GitLab Enterprise Edition, it is possible to manage GitLab group memberships using LDAP groups.
See [the GitLab Enterprise Edition documentation](../../integration/ldap.md) for more information.
## Epics **[ULTIMATE]**
@@ -211,38 +205,42 @@ Get an overview of the vulnerabilities of all the projects in a group and its su
> Introduced in [GitLab Ultimate][ee] 11.9 behind the `insights` feature flag.
-Configure the Insights that matter for your groups or projects to explore data
-such as triage hygiene, issues created/closed per a given period, average time
-for merge requests to be merged and much more.
+Configure the Insights that matter for your groups or projects, allowing users to explore data
+such as:
+
+- Triage hygiene
+- Issues created/closed per a given period
+- Average time for merge requests to be merged
+- Much more
[Learn more about Insights](insights/index.md).
## Transferring groups
-From GitLab 10.5, groups can be transferred in the following ways:
+From GitLab 10.5, you can transfer groups in the following ways:
-- Top-level groups can be transferred to a group, converting them into subgroups.
-- Subgroups can be transferred to a new parent group.
-- Subgroups can be transferred out from a parent group, converting them into top-level groups.
+- Transfer a subgroup to a new parent group.
+- Convert a top-level group into a subgroup by transfering it to the desired group.
+- Convert a subgroup into a top-level group by transfering it out of its current group.
When transferring groups, note:
- Changing a group's parent can have unintended side effects. See [Redirects when changing repository paths](../project/index.md#redirects-when-changing-repository-paths).
- You can only transfer groups to groups you manage.
-- You will need to update your local repositories to point to the new location.
-- If the parent group's visibility is lower than the group's current visibility, visibility levels for subgroups and projects will be changed to match the new parent group's visibility.
-- Only explicit group membership is transferred, not inherited membership. If the group's owners have only inherited membership, this would leave the group without an owner. In this case, the user transferring the group becomes the group's owner.
+- You must update your local repositories to point to the new location.
+- If the parent group's visibility is lower than the group's current visibility, visibility levels for subgroups and projects will change to match the new parent group's visibility.
+- Only explicit group membership is transferred, not inherited membership. If the group's owners have only inherited membership, this leaves the group without an owner. In this case, the user transferring the group becomes the group's owner.
## Group settings
-Once you have created a group, you can manage its settings by navigating to
+After creating a group, you can manage its settings by navigating to
the group's dashboard, and clicking **Settings**.
![group settings](img/group_settings.png)
### General settings
-Besides giving you the option to edit any settings you've previously
+In addition to editing any settings you previously
set when [creating the group](#create-a-new-group), you can also
access further configurations for your group.
@@ -253,14 +251,14 @@ Changing a group's path can have unintended side effects. Read
before proceeding.
If you are vacating the path so it can be claimed by another group or user,
-you may need to rename the group name as well since both names and paths must
+you may need to rename the group, too, since both names and paths must
be unique.
To change your group path:
1. Navigate to your group's **Settings > General**.
-1. Enter a new name under "Group path".
-1. Hit **Save group**.
+1. Enter a new name under **Group path**.
+1. Click **Save group**.
CAUTION: **Caution:**
It is currently not possible to rename a namespace if it contains a
@@ -276,20 +274,17 @@ username, you can create a new group and transfer projects to it.
Add a security layer to your group by
[enforcing two-factor authentication (2FA)](../../security/two_factor_authentication.md#enforcing-2fa-for-all-users-in-a-group)
-to all group members.
+for all group members.
#### Share with group lock
Prevent projects in a group from [sharing
-a project with another group](../project/members/share_project_with_groups.md).
-This allows for tighter control over project access.
+a project with another group](../project/members/share_project_with_groups.md) to enable tighter control over project access.
-For example, consider you have two distinct teams (Group A and Group B)
-working together in a project.
-To inherit the group membership, you share the project between the
+For example, let's say you have two distinct teams (Group A and Group B) working together in a project, and to inherit the group membership, you share the project between the
two groups A and B. **Share with group lock** prevents any project within
-the group from being shared with another group. By doing so, you
-guarantee only the right group members have access to those projects.
+the group from being shared with another group,
+guaranteeing that only the right group members have access to those projects.
To enable this feature, navigate to the group settings page. Select
**Share with group lock** and **Save the group**.
@@ -298,25 +293,22 @@ To enable this feature, navigate to the group settings page. Select
#### Member Lock **[STARTER]**
-With Member lock, it is possible to lock membership in a project to the
-level of members in the group.
-
-Member lock lets a group owner lock down any new project membership to all the
-projects within the group, allowing tighter control over project membership.
+Member lock lets a group owner prevent any new project membership to all of the
+projects within a group, allowing tighter control over project membership.
-For instance, if you want to lock the group for an [Audit Event](https://docs.gitlab.com/ee/administration/audit_events.html),
-you enable Member lock to guarantee that membership of a project cannot be modified during that audit.
+For example, if you want to lock the group for an [Audit Event](https://docs.gitlab.com/ee/administration/audit_events.html),
+enable Member lock to guarantee that project membership cannot be modified during that audit.
To enable this feature:
1. Navigate to the group's **Settings > General** page.
-1. Expand the **Permissions, LFS, 2FA** section and select **Member lock**.
-1. Click the **Save changes** button.
+1. Expand the **Permissions, LFS, 2FA** section, and select **Member lock**.
+1. Click **Save changes**.
![Checkbox for membership lock](img/member_lock.png)
This will disable the option for all users who previously had permissions to
-operate project memberships so no new users can be added. Furthermore, any
+operate project memberships, so no new users can be added. Furthermore, any
request to add a new user to a project through API will not be possible.
#### Group file templates **[PREMIUM]**
@@ -327,11 +319,11 @@ types with every project in a group. It is analogous to the
feature, and the selected project should follow the same naming conventions as
are documented on that page.
-Only projects that are in the group may be chosen as the source of templates.
-This includes projects shared with the group, but **excludes** projects in
+You can only choose projects in the group as the template source.
+This includes projects shared with the group, but it **excludes** projects in
subgroups or parent groups of the group being configured.
-This feature may be configured for subgroups as well as parent groups. A project
+You can configure this feature for both subgroups and parent groups. A project
in a subgroup will have access to the templates for that subgroup, as well as
any parent groups.
@@ -345,28 +337,28 @@ To enable this feature, navigate to the group settings page, expand the
#### Group-level project templates **[PREMIUM]**
-Define project templates at a group-level by setting a group as a template source.
+Define project templates at a group level by setting a group as the template source.
[Learn more about group-level project templates](custom_project_templates.md).
### Advanced settings
-- **Projects**: view all projects within that group, add members to each project,
- access each project's settings, and remove any project from the same screen.
-- **Webhooks**: configure [webhooks](../project/integrations/webhooks.md) to your group.
-- **Kubernetes cluster integration**: connect your GitLab group with [Kubernetes clusters](clusters/index.md).
-- **Audit Events**: view [Audit Events](https://docs.gitlab.com/ee/administration/audit_events.html)
+- **Projects**: View all projects within that group, add members to each project,
+ access each project's settings, and remove any project, all from the same screen.
+- **Webhooks**: Configure [webhooks](../project/integrations/webhooks.md) for your group.
+- **Kubernetes cluster integration**: Connect your GitLab group with [Kubernetes clusters](clusters/index.md).
+- **Audit Events**: View [Audit Events](https://docs.gitlab.com/ee/administration/audit_events.html)
for the group. **[STARTER ONLY]**
-- **Pipelines quota**: keep track of the [pipeline quota](../admin_area/settings/continuous_integration.md) for the group.
+- **Pipelines quota**: Keep track of the [pipeline quota](../admin_area/settings/continuous_integration.md) for the group.
## User contribution analysis **[STARTER]**
-With [GitLab Contribution Analytics](contribution_analytics/index.md)
+With [GitLab Contribution Analytics](contribution_analytics/index.md),
you have an overview of the contributions (pushes, merge requests,
and issues) performed by your group members.
## Issues analytics **[PREMIUM]**
-With [GitLab Issues Analytics](issues_analytics/index.md), in groups, you can see a bar chart of the number of issues created each month.
+With [GitLab Issues Analytics](issues_analytics/index.md), you can see a bar chart of the number of issues created each month in your groups.
## Dependency Proxy **[PREMIUM]**
diff --git a/doc/user/group/saml_sso/index.md b/doc/user/group/saml_sso/index.md
index 53116606201..778dbaf7a29 100644
--- a/doc/user/group/saml_sso/index.md
+++ b/doc/user/group/saml_sso/index.md
@@ -15,7 +15,7 @@ SAML SSO for groups is used only as a convenient way to add users and does not s
## Configuring your Identity Provider
1. Navigate to the group and click **Settings > SAML SSO**.
-1. Configure your SAML server using the **Assertion consumer service URL** and **Issuer**. See [your identity provider's documentation](#providers) for more details.
+1. Configure your SAML server using the **Assertion consumer service URL** and **Issuer**. Alternatively GitLab provides [metadata XML configuration](#metadata-configuration). See [your identity provider's documentation](#providers) for more details.
1. Configure the SAML response to include a NameID that uniquely identifies each user.
1. Configure required assertions using the [table below](#assertions).
1. Once the identity provider is set up, move on to [configuring GitLab](#configuring-gitlab).
@@ -50,6 +50,14 @@ GitLab.com uses the SAML NameID to identify users. The NameID element:
| First Name | `first_name`, `firstname`, `firstName` | |
| Last Name | `last_name`, `lastname`, `lastName` | |
+## Metadata configuration
+
+GitLab provides metadata XML that can be used to configure your Identity Provider.
+
+1. Navigate to the group and click **Settings > SAML SSO**.
+1. Copy the provided **GitLab metadata URL**
+1. Follow your Identity Provider's documentation and paste the metadata URL when it is requested.
+
## Configuring GitLab
Once you've set up your identity provider to work with GitLab, you'll need to configure GitLab to use it for authentication:
diff --git a/doc/user/project/clusters/index.md b/doc/user/project/clusters/index.md
index 3bc3beb2055..bc4d732a405 100644
--- a/doc/user/project/clusters/index.md
+++ b/doc/user/project/clusters/index.md
@@ -71,7 +71,7 @@ new Kubernetes cluster to your project:
- **Number of nodes** - Enter the number of nodes you wish the cluster to have.
- **Machine type** - The [machine type](https://cloud.google.com/compute/docs/machine-types)
of the Virtual Machine instance that the cluster will be based on.
- - **RBAC-enabled cluster** - Leave this checked if using default GKE creation options, see the [RBAC section](#role-based-access-control-rbac) for more information.
+ - **RBAC-enabled cluster** - Leave this checked if using default GKE creation options, see the [RBAC section](#rbac-cluster-resources) for more information.
- **GitLab-managed cluster** - Leave this checked if you want GitLab to manage namespaces and service accounts for this cluster. See the [Managed clusters section](#gitlab-managed-clusters) for more information.
1. Finally, click the **Create Kubernetes cluster** button.
@@ -263,65 +263,66 @@ you can either:
## Access controls
-When creating a cluster in GitLab, you will be asked if you would like to create an
-[Attribute-based access control (ABAC)](https://kubernetes.io/docs/admin/authorization/abac/) cluster, or
-a [Role-based access control (RBAC)](https://kubernetes.io/docs/admin/authorization/rbac/) one.
+When creating a cluster in GitLab, you will be asked if you would like to create either:
-NOTE: **Note:**
-[RBAC](#role-based-access-control-rbac) is recommended and the GitLab default.
+- An [Attribute-based access control (ABAC)](https://kubernetes.io/docs/admin/authorization/abac/) cluster.
+- A [Role-based access control (RBAC)](https://kubernetes.io/docs/admin/authorization/rbac/) cluster.
-Whether [ABAC](#attribute-based-access-control-abac) or [RBAC](#role-based-access-control-rbac) is enabled,
-GitLab will create the necessary service accounts and privileges in order to install and run
-[GitLab managed applications](#installing-applications):
+NOTE: **Note:**
+[RBAC](#rbac-cluster-resources) is recommended and the GitLab default.
-- If GitLab is creating the cluster, a `gitlab` service account with
- `cluster-admin` privileges will be created in the `default` namespace,
- which will be used by GitLab to manage the newly created cluster.
+GitLab creates the necessary service accounts and privileges to install and run
+[GitLab managed applications](#installing-applications). When GitLab creates the cluster:
+- A `gitlab` service account with `cluster-admin` privileges is created in the `default` namespace
+ to manage the newly created cluster.
- A project service account with [`edit`
privileges](https://kubernetes.io/docs/reference/access-authn-authz/rbac/#user-facing-roles)
- will be created in the project namespace (also created by GitLab), which will
- be used in [deployment jobs](#deployment-variables).
+ is created in the GitLab-created project namespace for [deployment jobs](#deployment-variables).
NOTE: **Note:**
Restricted service account for deployment was [introduced](https://gitlab.com/gitlab-org/gitlab-ce/issues/51716) in GitLab 11.5.
-- When you install Helm into your cluster, the `tiller` service account
- will be created with `cluster-admin` privileges in the `gitlab-managed-apps`
- namespace. This service account will be added to the installed Helm Tiller and will
- be used by Helm to install and run [GitLab managed applications](#installing-applications).
- Helm will also create additional service accounts and other resources for each
- installed application. Consult the documentation of the Helm charts for each application
- for details.
+When you install Helm into your cluster, the `tiller` service account
+is created with `cluster-admin` privileges in the `gitlab-managed-apps`
+namespace. This service account will be added to the installed Helm Tiller and will
+be used by Helm to install and run [GitLab managed applications](#installing-applications).
+Helm will also create additional service accounts and other resources for each
+installed application. Consult the documentation of the Helm charts for each application
+for details.
If you are [adding an existing Kubernetes cluster](#adding-an-existing-kubernetes-cluster),
ensure the token of the account has administrator privileges for the cluster.
-The following sections summarize which resources will be created on ABAC/RBAC clusters.
+The resources created by GitLab differ depending on the type of cluster.
+
+### ABAC cluster resources
+
+GitLab creates the following resources for ABAC clusters.
-### Attribute-based access control (ABAC)
+| Name | Type | Details | Created when |
+|:------------------|:---------------------|:----------------------------------|:---------------------------|
+| `gitlab` | `ServiceAccount` | `default` namespace | Creating a new GKE Cluster |
+| `gitlab-token` | `Secret` | Token for `gitlab` ServiceAccount | Creating a new GKE Cluster |
+| `tiller` | `ServiceAccount` | `gitlab-managed-apps` namespace | Installing Helm Tiller |
+| `tiller-admin` | `ClusterRoleBinding` | `cluster-admin` roleRef | Installing Helm Tiller |
+| Project namespace | `ServiceAccount` | Uses namespace of Project | Deploying to a cluster |
+| Project namespace | `Secret` | Token for project ServiceAccount | Deploying to a cluster |
-| Name | Kind | Details | Created when |
-| --- | --- | --- | --- |
-| `gitlab` | `ServiceAccount` | `default` namespace | Creating a new GKE Cluster |
-| `gitlab-token` | `Secret` | Token for `gitlab` ServiceAccount | Creating a new GKE Cluster |
-| `tiller` | `ServiceAccount` | `gitlab-managed-apps` namespace | Installing Helm Tiller |
-| `tiller-admin` | `ClusterRoleBinding` | `cluster-admin` roleRef | Installing Helm Tiller |
-| Project namespace | `ServiceAccount` | Uses namespace of Project | Deploying to a cluster |
-| Project namespace | `Secret` | Token for project ServiceAccount | Deploying to a cluster |
+### RBAC cluster resources
-### Role-based access control (RBAC)
+GitLab creates the following resources for RBAC clusters.
-| Name | Kind | Details | Created when |
-| --- | --- | --- | --- |
-| `gitlab` | `ServiceAccount` | `default` namespace | Creating a new GKE Cluster |
-| `gitlab-admin` | `ClusterRoleBinding` | [`cluster-admin`](https://kubernetes.io/docs/reference/access-authn-authz/rbac/#user-facing-roles) roleRef | Creating a new GKE Cluster |
-| `gitlab-token` | `Secret` | Token for `gitlab` ServiceAccount | Creating a new GKE Cluster |
-| `tiller` | `ServiceAccount` | `gitlab-managed-apps` namespace | Installing Helm Tiller |
-| `tiller-admin` | `ClusterRoleBinding` | `cluster-admin` roleRef | Installing Helm Tiller |
-| Project namespace | `ServiceAccount` | Uses namespace of Project | Deploying to a cluster |
-| Project namespace | `Secret` | Token for project ServiceAccount | Deploying to a cluster |
-| Project namespace | `RoleBinding` | [`edit`](https://kubernetes.io/docs/reference/access-authn-authz/rbac/#user-facing-roles) roleRef | Deploying to a cluster |
+| Name | Type | Details | Created when |
+|:------------------|:---------------------|:-----------------------------------------------------------------------------------------------------------|:---------------------------|
+| `gitlab` | `ServiceAccount` | `default` namespace | Creating a new GKE Cluster |
+| `gitlab-admin` | `ClusterRoleBinding` | [`cluster-admin`](https://kubernetes.io/docs/reference/access-authn-authz/rbac/#user-facing-roles) roleRef | Creating a new GKE Cluster |
+| `gitlab-token` | `Secret` | Token for `gitlab` ServiceAccount | Creating a new GKE Cluster |
+| `tiller` | `ServiceAccount` | `gitlab-managed-apps` namespace | Installing Helm Tiller |
+| `tiller-admin` | `ClusterRoleBinding` | `cluster-admin` roleRef | Installing Helm Tiller |
+| Project namespace | `ServiceAccount` | Uses namespace of Project | Deploying to a cluster |
+| Project namespace | `Secret` | Token for project ServiceAccount | Deploying to a cluster |
+| Project namespace | `RoleBinding` | [`edit`](https://kubernetes.io/docs/reference/access-authn-authz/rbac/#user-facing-roles) roleRef | Deploying to a cluster |
NOTE: **Note:**
Project-specific resources are only created if your cluster is [managed by GitLab](#gitlab-managed-clusters).
@@ -375,7 +376,7 @@ by GitLab before installing any of the applications.
| [Prometheus](https://prometheus.io/docs/introduction/overview/) | 10.4+ | Prometheus is an open-source monitoring and alerting system useful to supervise your deployed applications. | [stable/prometheus](https://github.com/helm/charts/tree/master/stable/prometheus) |
| [GitLab Runner](https://docs.gitlab.com/runner/) | 10.6+ | GitLab Runner is the open source project that is used to run your jobs and send the results back to GitLab. It is used in conjunction with [GitLab CI/CD](../../../ci/README.md), the open-source continuous integration service included with GitLab that coordinates the jobs. When installing the GitLab Runner via the applications, it will run in **privileged mode** by default. Make sure you read the [security implications](#security-implications) before doing so. | [runner/gitlab-runner](https://gitlab.com/charts/gitlab-runner) |
| [JupyterHub](http://jupyter.org/) | 11.0+ | [JupyterHub](https://jupyterhub.readthedocs.io/en/stable/) is a multi-user service for managing notebooks across a team. [Jupyter Notebooks](https://jupyter-notebook.readthedocs.io/en/latest/) provide a web-based interactive programming environment used for data analysis, visualization, and machine learning. We use a [custom Jupyter image](https://gitlab.com/gitlab-org/jupyterhub-user-image/blob/master/Dockerfile) that installs additional useful packages on top of the base Jupyter. Authentication will be enabled only for [project members](../members/index.md) with [Developer or higher](../../permissions.md) access to the project. You will also see ready-to-use DevOps Runbooks built with Nurtch's [Rubix library](https://github.com/amit1rrr/rubix). More information on creating executable runbooks can be found in [our Nurtch documentation](runbooks/index.md#nurtch-executable-runbooks). Note that Ingress must be installed and have an IP address assigned before JupyterHub can be installed. | [jupyter/jupyterhub](https://jupyterhub.github.io/helm-chart/) |
-| [Knative](https://cloud.google.com/knative) | 11.5+ | Knative provides a platform to create, deploy, and manage serverless workloads from a Kubernetes cluster. It is used in conjunction with, and includes [Istio](https://istio.io) to provide an external IP address for all programs hosted by Knative. You will be prompted to enter a wildcard domain where your applications will be exposed. Configure your DNS server to use the external IP address for that domain. For any application created and installed, they will be accessible as `<program_name>.<kubernetes_namespace>.<domain_name>`. This will require your kubernetes cluster to have [RBAC enabled](#role-based-access-control-rbac). | [knative/knative](https://storage.googleapis.com/triggermesh-charts)
+| [Knative](https://cloud.google.com/knative) | 11.5+ | Knative provides a platform to create, deploy, and manage serverless workloads from a Kubernetes cluster. It is used in conjunction with, and includes [Istio](https://istio.io) to provide an external IP address for all programs hosted by Knative. You will be prompted to enter a wildcard domain where your applications will be exposed. Configure your DNS server to use the external IP address for that domain. For any application created and installed, they will be accessible as `<program_name>.<kubernetes_namespace>.<domain_name>`. This will require your kubernetes cluster to have [RBAC enabled](#rbac-cluster-resources). | [knative/knative](https://storage.googleapis.com/triggermesh-charts)
With the exception of Knative, the applications will be installed in a dedicated
namespace called `gitlab-managed-apps`.
diff --git a/doc/user/project/integrations/webhooks.md b/doc/user/project/integrations/webhooks.md
index 10eb3a4f3b7..a0f500a939f 100644
--- a/doc/user/project/integrations/webhooks.md
+++ b/doc/user/project/integrations/webhooks.md
@@ -1016,7 +1016,7 @@ X-Gitlab-Event: Pipeline Hook
"email": "user@gitlab.com"
}
},
- "jobs":[
+ "builds":[
{
"id": 380,
"stage": "deploy",
diff --git a/doc/user/project/quick_actions.md b/doc/user/project/quick_actions.md
index 15eb862b431..1d640966013 100644
--- a/doc/user/project/quick_actions.md
+++ b/doc/user/project/quick_actions.md
@@ -35,7 +35,7 @@ discussions, and descriptions:
| `/label ~label1 ~label2` | Add label(s). Label names can also start without ~ but mixed syntax is not supported. | ✓ | ✓ |
| `/unlabel ~label1 ~label2` | Remove all or specific label(s)| ✓ | ✓ |
| `/relabel ~label1 ~label2` | Replace label | ✓ | ✓ |
-| <code>/copy_metadata #issue &#124; !merge_request</code> | Copy labels and milestone from other issue or merge request | ✓ | ✓ |
+| <code>/copy_metadata #issue &#124; !merge_request</code> | Copy labels and milestone from other issue or merge request in the project | ✓ | ✓ |
| <code>/estimate &lt;1w 3d 2h 14m&gt;</code> | Set time estimate | ✓ | ✓ |
| `/remove_estimate` | Remove time estimate | ✓ | ✓ |
| <code>/spend &lt;time(1h 30m &#124; -1h 5m)&gt; &lt;date(YYYY-MM-DD)&gt;</code> | Add or subtract spent time; optionally, specify the date that time was spent on | ✓ | ✓ |
diff --git a/doc/user/project/settings/import_export.md b/doc/user/project/settings/import_export.md
index 89008fd15b9..db4f8fbd8d3 100644
--- a/doc/user/project/settings/import_export.md
+++ b/doc/user/project/settings/import_export.md
@@ -23,6 +23,7 @@
> in the import side is required to map the users, based on email or username.
> Otherwise, a supplementary comment is left to mention the original author and
> the MRs, notes or issues will be owned by the importer.
+> - Project members with owner access will get imported as maintainers.
> - Control project Import/Export with the [API](../../../api/project_import_export.md).
> - If an imported project contains merge requests originated from forks,
> then new branches associated with such merge requests will be created
diff --git a/lib/api/entities.rb b/lib/api/entities.rb
index 1a3318fe849..96a1ccefbe5 100644
--- a/lib/api/entities.rb
+++ b/lib/api/entities.rb
@@ -1303,6 +1303,7 @@ module API
class Variable < Grape::Entity
expose :variable_type, :key, :value
expose :protected?, as: :protected, if: -> (entity, _) { entity.respond_to?(:protected?) }
+ expose :masked?, as: :masked, if: -> (entity, _) { entity.respond_to?(:masked?) }
end
class Pipeline < PipelineBasic
diff --git a/lib/api/helpers/internal_helpers.rb b/lib/api/helpers/internal_helpers.rb
index 71c30ec99a5..c318f5b9127 100644
--- a/lib/api/helpers/internal_helpers.rb
+++ b/lib/api/helpers/internal_helpers.rb
@@ -46,6 +46,8 @@ module API
def process_mr_push_options(push_options, project, user, changes)
output = {}
+ Gitlab::QueryLimiting.whitelist('https://gitlab.com/gitlab-org/gitlab-ce/issues/61359')
+
service = ::MergeRequests::PushOptionsHandlerService.new(
project,
user,
diff --git a/lib/api/internal.rb b/lib/api/internal.rb
index c82fd230d7a..224aaaaf006 100644
--- a/lib/api/internal.rb
+++ b/lib/api/internal.rb
@@ -264,12 +264,8 @@ module API
PostReceive.perform_async(params[:gl_repository], params[:identifier],
params[:changes], push_options.as_json)
- if Feature.enabled?(:mr_push_options, default_enabled: true)
- Gitlab::QueryLimiting.whitelist('https://gitlab.com/gitlab-org/gitlab-ce/issues/61359')
-
- mr_options = push_options.get(:merge_request)
- output.merge!(process_mr_push_options(mr_options, project, user, params[:changes])) if mr_options.present?
- end
+ mr_options = push_options.get(:merge_request)
+ output.merge!(process_mr_push_options(mr_options, project, user, params[:changes])) if mr_options.present?
broadcast_message = BroadcastMessage.current&.last&.message
reference_counter_decreased = Gitlab::ReferenceCounter.new(params[:gl_repository]).decrease
diff --git a/lib/api/variables.rb b/lib/api/variables.rb
index a1bb21b3a06..b07dd1bab79 100644
--- a/lib/api/variables.rb
+++ b/lib/api/variables.rb
@@ -55,6 +55,7 @@ module API
requires :key, type: String, desc: 'The key of the variable'
requires :value, type: String, desc: 'The value of the variable'
optional :protected, type: String, desc: 'Whether the variable is protected'
+ optional :masked, type: String, desc: 'Whether the variable is masked'
optional :variable_type, type: String, values: Ci::Variable.variable_types.keys, desc: 'The type of variable, must be one of env_var or file. Defaults to env_var'
if Gitlab.ee?
@@ -81,6 +82,7 @@ module API
optional :key, type: String, desc: 'The key of the variable'
optional :value, type: String, desc: 'The value of the variable'
optional :protected, type: String, desc: 'Whether the variable is protected'
+ optional :masked, type: String, desc: 'Whether the variable is masked'
optional :variable_type, type: String, values: Ci::Variable.variable_types.keys, desc: 'The type of variable, must be one of env_var or file'
if Gitlab.ee?
diff --git a/lib/banzai/filter/abstract_reference_filter.rb b/lib/banzai/filter/abstract_reference_filter.rb
index 44b151d01e7..0224dd8fcd1 100644
--- a/lib/banzai/filter/abstract_reference_filter.rb
+++ b/lib/banzai/filter/abstract_reference_filter.rb
@@ -363,6 +363,14 @@ module Banzai
group_ref
end
+
+ def unescape_html_entities(text)
+ CGI.unescapeHTML(text.to_s)
+ end
+
+ def escape_html_entities(text)
+ CGI.escapeHTML(text.to_s)
+ end
end
end
end
diff --git a/lib/banzai/filter/label_reference_filter.rb b/lib/banzai/filter/label_reference_filter.rb
index 4d67140b0a1..4892668fc22 100644
--- a/lib/banzai/filter/label_reference_filter.rb
+++ b/lib/banzai/filter/label_reference_filter.rb
@@ -104,14 +104,6 @@ module Banzai
matches[:namespace] && matches[:project]
end
- def unescape_html_entities(text)
- CGI.unescapeHTML(text.to_s)
- end
-
- def escape_html_entities(text)
- CGI.escapeHTML(text.to_s)
- end
-
def object_link_title(object, matches)
# use title of wrapped element instead
nil
diff --git a/lib/banzai/filter/milestone_reference_filter.rb b/lib/banzai/filter/milestone_reference_filter.rb
index fce042e8946..08969753d75 100644
--- a/lib/banzai/filter/milestone_reference_filter.rb
+++ b/lib/banzai/filter/milestone_reference_filter.rb
@@ -51,13 +51,13 @@ module Banzai
# default implementation.
return super(text, pattern) if pattern != Milestone.reference_pattern
- text.gsub(pattern) do |match|
+ unescape_html_entities(text).gsub(pattern) do |match|
milestone = find_milestone($~[:project], $~[:namespace], $~[:milestone_iid], $~[:milestone_name])
if milestone
yield match, milestone.id, $~[:project], $~[:namespace], $~
else
- match
+ escape_html_entities(match)
end
end
end
diff --git a/lib/gitlab/auth_logger.rb b/lib/gitlab/auth_logger.rb
new file mode 100644
index 00000000000..6d3edba02b0
--- /dev/null
+++ b/lib/gitlab/auth_logger.rb
@@ -0,0 +1,9 @@
+# frozen_string_literal: true
+
+module Gitlab
+ class AuthLogger < Gitlab::JsonLogger
+ def self.file_name_noext
+ 'auth'
+ end
+ end
+end
diff --git a/lib/gitlab/ci/templates/Jobs/Deploy.gitlab-ci.yml b/lib/gitlab/ci/templates/Jobs/Deploy.gitlab-ci.yml
index 779f4b5f006..11569437cb6 100644
--- a/lib/gitlab/ci/templates/Jobs/Deploy.gitlab-ci.yml
+++ b/lib/gitlab/ci/templates/Jobs/Deploy.gitlab-ci.yml
@@ -507,23 +507,13 @@ rollout 100%:
kubectl describe namespace "$KUBE_NAMESPACE" || kubectl create namespace "$KUBE_NAMESPACE"
}
- # Function to ensure backwards compatibility with AUTO_DEVOPS_DOMAIN
- function ensure_kube_ingress_base_domain() {
- if [ -z ${KUBE_INGRESS_BASE_DOMAIN+x} ] && [ -n "$AUTO_DEVOPS_DOMAIN" ] ; then
- export KUBE_INGRESS_BASE_DOMAIN=$AUTO_DEVOPS_DOMAIN
- fi
- }
-
function check_kube_domain() {
- ensure_kube_ingress_base_domain
-
if [[ -z "$KUBE_INGRESS_BASE_DOMAIN" ]]; then
echo "In order to deploy or use Review Apps,"
- echo "AUTO_DEVOPS_DOMAIN or KUBE_INGRESS_BASE_DOMAIN variables must be set"
+ echo "KUBE_INGRESS_BASE_DOMAIN variables must be set"
echo "From 11.8, you can set KUBE_INGRESS_BASE_DOMAIN in cluster settings"
echo "or by defining a variable at group or project level."
echo "You can also manually add it in .gitlab-ci.yml"
- echo "AUTO_DEVOPS_DOMAIN support will be dropped on 12.0"
false
else
true
diff --git a/lib/gitlab/ci/templates/Security/SAST.gitlab-ci.yml b/lib/gitlab/ci/templates/Security/SAST.gitlab-ci.yml
index 706692e063b..abf16e5b2e7 100644
--- a/lib/gitlab/ci/templates/Security/SAST.gitlab-ci.yml
+++ b/lib/gitlab/ci/templates/Security/SAST.gitlab-ci.yml
@@ -40,6 +40,7 @@ sast:
SAST_BRAKEMAN_LEVEL \
SAST_GOSEC_LEVEL \
SAST_FLAWFINDER_LEVEL \
+ SAST_GITLEAKS_ENTROPY_LEVEL \
SAST_DOCKER_CLIENT_NEGOTIATION_TIMEOUT \
SAST_PULL_ANALYZER_IMAGE_TIMEOUT \
SAST_RUN_ANALYZER_TIMEOUT \
diff --git a/lib/gitlab/import_export/members_mapper.rb b/lib/gitlab/import_export/members_mapper.rb
index 6be95a16513..5ab5059165e 100644
--- a/lib/gitlab/import_export/members_mapper.rb
+++ b/lib/gitlab/import_export/members_mapper.rb
@@ -59,7 +59,11 @@ module Gitlab
end
def member_hash(member)
- parsed_hash(member).merge('source_id' => @project.id, 'importing' => true)
+ parsed_hash(member).merge(
+ 'source_id' => @project.id,
+ 'importing' => true,
+ 'access_level' => [member['access_level'], ProjectMember::MAINTAINER].min
+ )
end
def parsed_hash(member)
diff --git a/lib/gitlab/omniauth_initializer.rb b/lib/gitlab/omniauth_initializer.rb
index e0ac9eec1f2..2a2083ebae0 100644
--- a/lib/gitlab/omniauth_initializer.rb
+++ b/lib/gitlab/omniauth_initializer.rb
@@ -36,12 +36,25 @@ module Gitlab
hash_arguments = provider['args'].merge(provider_defaults(provider))
# A Hash from the configuration will be passed as is.
- provider_arguments << hash_arguments.symbolize_keys
+ provider_arguments << normalize_hash_arguments(hash_arguments)
end
provider_arguments
end
+ def normalize_hash_arguments(args)
+ args.symbolize_keys!
+
+ # Rails 5.1 deprecated the use of string names in the middleware
+ # (https://github.com/rails/rails/commit/83b767ce), so we need to
+ # pass in the actual class to Devise.
+ if args[:strategy_class].is_a?(String)
+ args[:strategy_class] = args[:strategy_class].constantize
+ end
+
+ args
+ end
+
def provider_defaults(provider)
case provider['name']
when 'cas3'
diff --git a/lib/gitlab/quick_actions/issue_and_merge_request_actions.rb b/lib/gitlab/quick_actions/issue_and_merge_request_actions.rb
index 1cd158db2b0..e1579cfddc0 100644
--- a/lib/gitlab/quick_actions/issue_and_merge_request_actions.rb
+++ b/lib/gitlab/quick_actions/issue_and_merge_request_actions.rb
@@ -102,7 +102,7 @@ module Gitlab
@updates[:milestone_id] = nil
end
- desc _('Copy labels and milestone from other issue or merge request')
+ desc _('Copy labels and milestone from other issue or merge request in this project')
explanation do |source_issuable|
_("Copy labels and milestone from %{source_issuable_reference}.") % { source_issuable_reference: source_issuable.to_reference }
end
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index 6209530deab..f16c00250a6 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -193,6 +193,18 @@ msgstr ""
msgid "%{service_title} settings saved, but not activated."
msgstr ""
+msgid "%{size} GiB"
+msgstr ""
+
+msgid "%{size} KiB"
+msgstr ""
+
+msgid "%{size} MiB"
+msgstr ""
+
+msgid "%{size} bytes"
+msgstr ""
+
msgid "%{spammable_titlecase} was submitted to Akismet successfully."
msgstr ""
@@ -823,6 +835,9 @@ msgstr ""
msgid "An error has occurred"
msgstr ""
+msgid "An error occurding while fetching folder content."
+msgstr ""
+
msgid "An error occurred creating the new branch."
msgstr ""
@@ -2891,7 +2906,7 @@ msgstr ""
msgid "Copy labels and milestone from %{source_issuable_reference}."
msgstr ""
-msgid "Copy labels and milestone from other issue or merge request"
+msgid "Copy labels and milestone from other issue or merge request in this project"
msgstr ""
msgid "Copy link"
@@ -4482,6 +4497,9 @@ msgstr ""
msgid "Found errors in your .gitlab-ci.yml:"
msgstr ""
+msgid "Friday"
+msgstr ""
+
msgid "From %{providerTitle}"
msgstr ""
@@ -5796,6 +5814,9 @@ msgstr ""
msgid "Mark as resolved"
msgstr ""
+msgid "Mark comment as resolved"
+msgstr ""
+
msgid "Mark this issue as a duplicate of another issue"
msgstr ""
@@ -8202,6 +8223,9 @@ msgstr ""
msgid "Resolved all discussions."
msgstr ""
+msgid "Resolved by %{name}"
+msgstr ""
+
msgid "Resolved by %{resolvedByName}"
msgstr ""
@@ -9984,6 +10008,9 @@ msgstr ""
msgid "This will remove the fork relationship to source project"
msgstr ""
+msgid "Thursday"
+msgstr ""
+
msgid "Time before an issue gets scheduled"
msgstr ""
@@ -10387,6 +10414,9 @@ msgstr ""
msgid "Trying to communicate with your device. Plug it in (if you haven't already) and press the button on the device now."
msgstr ""
+msgid "Tuesday"
+msgstr ""
+
msgid "Twitter"
msgstr ""
@@ -10879,6 +10909,9 @@ msgstr ""
msgid "Webhooks Help"
msgstr ""
+msgid "Wednesday"
+msgstr ""
+
msgid "Welcome to your Issue Board!"
msgstr ""
diff --git a/package.json b/package.json
index 0cbc178a923..381accff23b 100644
--- a/package.json
+++ b/package.json
@@ -23,7 +23,7 @@
"stylelint": "node node_modules/stylelint/bin/stylelint.js app/assets/stylesheets/**/*.* ee/app/assets/stylesheets/**/*.* !**/vendors/** --custom-formatter node_modules/stylelint-error-string-formatter",
"stylelint-file": "node node_modules/stylelint/bin/stylelint.js",
"stylelint-create-utility-map": "node scripts/frontend/stylelint/stylelint-utility-map.js",
- "test": "yarn jest && yarn karma",
+ "test": "node scripts/frontend/test",
"webpack": "NODE_OPTIONS=\"--max-old-space-size=3584\" webpack --config config/webpack.config.js",
"webpack-prod": "NODE_OPTIONS=\"--max-old-space-size=3584\" NODE_ENV=production webpack --config config/webpack.config.js"
},
@@ -36,7 +36,7 @@
"@babel/plugin-syntax-import-meta": "^7.2.0",
"@babel/preset-env": "^7.4.4",
"@gitlab/csslab": "^1.9.0",
- "@gitlab/svgs": "^1.60.0",
+ "@gitlab/svgs": "^1.62.0",
"@gitlab/ui": "^3.10.0",
"apollo-cache-inmemory": "^1.5.1",
"apollo-client": "^2.5.1",
diff --git a/public/visual-review-toolbar.js b/public/visual-review-toolbar.js
index dc21197bda9..6a0fdb29cc2 100644
--- a/public/visual-review-toolbar.js
+++ b/public/visual-review-toolbar.js
@@ -374,12 +374,12 @@ function clearNote (inputId) {
}
}
-function confirmAndClear (discussionId) {
+function confirmAndClear (mergeRequestId) {
const commentButton = document.getElementById('gitlab-comment-button');
const note = document.getElementById('gitlab-validation-note');
commentButton.innerText = 'Feedback sent';
- note.innerText = `Your comment was successfully posted to issue #${discussionId}`;
+ note.innerText = `Your comment was successfully posted to merge request #${mergeRequestId}`;
setTimeout(resetCommentButton, 1000);
}
@@ -412,7 +412,7 @@ function getProjectDetails () {
const browser = getBrowserId(userAgent);
const scriptEl = document.getElementById('review-app-toolbar-script')
- const { projectId, discussionId, mrUrl } = scriptEl.dataset;
+ const { projectId, mergeRequestId, mrUrl } = scriptEl.dataset;
return {
href,
@@ -422,7 +422,7 @@ function getProjectDetails () {
innerWidth,
innerHeight,
projectId,
- discussionId,
+ mergeRequestId,
mrUrl,
};
}
@@ -449,7 +449,7 @@ function postComment ({
innerWidth,
innerHeight,
projectId,
- discussionId,
+ mergeRequestId,
mrUrl,
}) {
// Clear any old errors
@@ -466,18 +466,20 @@ function postComment ({
}
const detailText = `
- <details>
- <summary>Metadata</summary>
- Posted from ${href} | ${platform} | ${browser} | ${innerWidth} x ${innerHeight}.
- <br /><br />
- *User agent: ${userAgent}*
- </details>
+ \n
+<details>
+ <summary>Metadata</summary>
+ Posted from ${href} | ${platform} | ${browser} | ${innerWidth} x ${innerHeight}.
+ <br /><br />
+ <em>User agent: ${userAgent}</em>
+</details>
`;
const url = `
- ${mrUrl}/api/v4/projects/${projectId}/issues/${discussionId}/discussions`;
+ ${mrUrl}/api/v4/projects/${projectId}/merge_requests/${mergeRequestId}/discussions`;
- const body = `${commentText}${detailText}`;
+
+ const body = `${commentText} ${detailText}`;
fetch(url, {
method: 'POST',
@@ -489,7 +491,7 @@ function postComment ({
})
.then((response) => {
if (response.ok) {
- confirmAndClear(discussionId);
+ confirmAndClear(mergeRequestId);
return;
}
diff --git a/qa/docs/WRITING_TESTS_FROM_SCRATCH.md b/qa/docs/WRITING_TESTS_FROM_SCRATCH.md
index f91286c232e..309fcc4064c 100644
--- a/qa/docs/WRITING_TESTS_FROM_SCRATCH.md
+++ b/qa/docs/WRITING_TESTS_FROM_SCRATCH.md
@@ -271,7 +271,7 @@ end
In the `before :all` block we create all the application state needed for the tests to run. We do that by fabricating resources via APIs (`project`, `@issue`, and `@labels`), by using the `Runtime::Browser.visit` method to go to the login page, and by performing a `sign_in_using_credentials` from the `Login` Page Object.
-> When creating the resources, notice that when calling the `fabricate_via_api` method, we pass some attribute:values, like `name` for the `project` resoruce, `project`, `title`, and `labels` for the the issue resource, and `project`, and `title` for `label` resources.
+> When creating the resources, notice that when calling the `fabricate_via_api` method, we pass some attribute:values, like `name` for the `project` resource; `project`, `title`, and `labels` for the `issue` resource; and `project`, and `title` for `label` resources.
> What's important to understand here is that by creating the application state mostly using the public APIs we save a lot of time in the test suite setup stage.
@@ -279,7 +279,7 @@ In the `before :all` block we create all the application state needed for the te
### 6. Optimization
-As already mentioned in the [best practices](./BEST_PRACTICES.md) document, end-to-end tests are very costly in terms of execution time, and it's our responsibility as software engineers to ensure that we optimize them as max as possible.
+As already mentioned in the [best practices](./BEST_PRACTICES.md) document, end-to-end tests are very costly in terms of execution time, and it's our responsibility as software engineers to ensure that we optimize them as much as possible.
> Differently than unit tests, that exercise every little piece of the application in isolation, usually having only one assertion per test, and being very fast to run, end-to-end tests can have more actions and assertions in a single test to help on speeding up the test's feedback since they are much slower when comparing to unit tests.
@@ -367,7 +367,7 @@ With that in mind, resources can be a project, an epic, an issue, a label, a com
As you saw in the tests' pre-conditions and the optimization sections, we're already creating some of these resources, and we are doing that by calling the `fabricate_via_api!` method.
-> We could be using the `fabricate!` method instead, which would use the `fabricate_via_api!` method if it exists, and fallback to GUI fabrication otherwise, but we recommend being explicit to make it clear what the test does. Also, we always recommend fabricating resources via API since this makes tests faster and more reliable.
+> We could be using the `fabricate!` method instead, which would use the `fabricate_via_api!` method if it exists, and fallback to GUI fabrication otherwise, but we recommend being explicit to make it clear what the test does. Also, we recommend fabricating resources via API since this makes tests faster and more reliable, unless the test is focusing on the GUI itself, or there's no GUI coverage for that specific part in any other test.
For our test suite example, the [project resource](https://gitlab.com/gitlab-org/gitlab-ee/blob/d3584e80b4236acdf393d815d604801573af72cc/qa/qa/resource/project.rb#L55) already had a `fabricate_via_api!` method available, while other resources don't have it, so we will have to create them, like for the issue and label resources. Also, we will have to make a small change in the project resource to expose its `id` attribute so that we can refer to it when fabricating the issue.
diff --git a/scripts/frontend/test.js b/scripts/frontend/test.js
new file mode 100755
index 00000000000..dab7176f8c1
--- /dev/null
+++ b/scripts/frontend/test.js
@@ -0,0 +1,114 @@
+#!/usr/bin/env node
+
+const { spawn } = require('child_process');
+const { EOL } = require('os');
+const program = require('commander');
+const chalk = require('chalk');
+
+const JEST_ROUTE = 'spec/frontend';
+const KARMA_ROUTE = 'spec/javascripts';
+const COMMON_ARGS = ['--colors'];
+const JEST_ARGS = ['--passWithNoTests'];
+const KARMA_ARGS = ['--no-fail-on-empty-test-suite'];
+const SUCCESS_CODE = 0;
+
+program
+ .version('0.1.0')
+ .usage('[options] <file ...>')
+ .option('-p, --parallel', 'Run tests suites in parallel')
+ .parse(process.argv);
+
+const isSuccess = code => code === SUCCESS_CODE;
+
+const combineExitCodes = codes => {
+ const firstFail = codes.find(x => !isSuccess(x));
+
+ return firstFail === undefined ? SUCCESS_CODE : firstFail;
+};
+
+const skipIfFail = fn => code => (isSuccess(code) ? fn() : code);
+
+const endWithEOL = str => (str[str.length - 1] === '\n' ? str : `${str}${EOL}`);
+
+const runTests = paths => {
+ if (program.parallel) {
+ return Promise.all([runJest(paths), runKarma(paths)]).then(combineExitCodes);
+ } else {
+ return runJest(paths).then(skipIfFail(() => runKarma(paths)));
+ }
+};
+
+const spawnYarnScript = (cmd, args) => {
+ return new Promise((resolve, reject) => {
+ const proc = spawn('yarn', ['run', cmd, ...args]);
+ const output = data => {
+ const text = data
+ .toString()
+ .split(/\r?\n/g)
+ .map((line, idx, { length }) =>
+ idx === length - 1 && !line ? line : `${chalk.gray(cmd)}: ${line}`,
+ )
+ .join(EOL);
+
+ return endWithEOL(text);
+ };
+
+ proc.stdout.on('data', data => {
+ process.stdout.write(output(data));
+ });
+
+ proc.stderr.on('data', data => {
+ process.stderr.write(output(data));
+ });
+
+ proc.on('close', code => {
+ process.stdout.write(output(`exited with code ${code}`));
+
+ // We resolve even on a failure code because a `reject` would cause
+ // Promise.all to reject immediately (without waiting for other promises)
+ // to finish.
+ resolve(code);
+ });
+ });
+};
+
+const runJest = args => {
+ return spawnYarnScript('jest', [...JEST_ARGS, ...COMMON_ARGS, ...toJestArgs(args)]);
+};
+
+const runKarma = args => {
+ return spawnYarnScript('karma', [...KARMA_ARGS, ...COMMON_ARGS, ...toKarmaArgs(args)]);
+};
+
+const replacePath = to => path =>
+ path
+ .replace(JEST_ROUTE, to)
+ .replace(KARMA_ROUTE, to)
+ .replace('app/assets/javascripts', to);
+
+const replacePathForJest = replacePath(JEST_ROUTE);
+
+const replacePathForKarma = replacePath(KARMA_ROUTE);
+
+const toJestArgs = paths => paths.map(replacePathForJest);
+
+const toKarmaArgs = paths =>
+ paths.reduce((acc, path) => acc.concat('-f', replacePathForKarma(path)), []);
+
+const main = paths => {
+ runTests(paths).then(code => {
+ console.log('~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~');
+ if (isSuccess(code)) {
+ console.log(chalk.bgGreen(chalk.black('All tests passed :)')));
+ } else {
+ console.log(chalk.bgRed(chalk.white(`Some tests failed :(`)));
+ }
+ console.log('~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~');
+
+ if (!isSuccess(code)) {
+ process.exit(code);
+ }
+ });
+};
+
+main(program.args);
diff --git a/spec/frontend/repository/components/table/__snapshots__/row_spec.js.snap b/spec/frontend/repository/components/table/__snapshots__/row_spec.js.snap
index f0b72343b6e..1b4564303e4 100644
--- a/spec/frontend/repository/components/table/__snapshots__/row_spec.js.snap
+++ b/spec/frontend/repository/components/table/__snapshots__/row_spec.js.snap
@@ -16,7 +16,9 @@ exports[`Repository table row component renders table row 1`] = `
<a
class="str-truncated"
>
+
test
+
</a>
<!---->
diff --git a/spec/frontend/repository/components/table/index_spec.js b/spec/frontend/repository/components/table/index_spec.js
index 6f52cffe077..827927e6d9a 100644
--- a/spec/frontend/repository/components/table/index_spec.js
+++ b/spec/frontend/repository/components/table/index_spec.js
@@ -3,18 +3,19 @@ import { GlLoadingIcon } from '@gitlab/ui';
import Table from '~/repository/components/table/index.vue';
let vm;
+let $apollo;
+
+function factory(path, data = () => ({})) {
+ $apollo = {
+ query: jest.fn().mockReturnValue(Promise.resolve({ data: data() })),
+ };
-function factory(path, loading = false) {
vm = shallowMount(Table, {
propsData: {
path,
},
mocks: {
- $apollo: {
- queries: {
- files: { loading },
- },
- },
+ $apollo,
},
});
}
@@ -39,9 +40,41 @@ describe('Repository table component', () => {
);
});
- it('renders loading icon', () => {
- factory('/', true);
+ it('shows loading icon', () => {
+ factory('/');
+
+ vm.setData({ isLoadingFiles: true });
+
+ expect(vm.find(GlLoadingIcon).isVisible()).toBe(true);
+ });
+
+ describe('normalizeData', () => {
+ it('normalizes edge nodes', () => {
+ const output = vm.vm.normalizeData('blobs', [{ node: '1' }, { node: '2' }]);
+
+ expect(output).toEqual(['1', '2']);
+ });
+ });
+
+ describe('hasNextPage', () => {
+ it('returns undefined when hasNextPage is false', () => {
+ const output = vm.vm.hasNextPage({
+ trees: { pageInfo: { hasNextPage: false } },
+ submodules: { pageInfo: { hasNextPage: false } },
+ blobs: { pageInfo: { hasNextPage: false } },
+ });
+
+ expect(output).toBe(undefined);
+ });
+
+ it('returns pageInfo object when hasNextPage is true', () => {
+ const output = vm.vm.hasNextPage({
+ trees: { pageInfo: { hasNextPage: false } },
+ submodules: { pageInfo: { hasNextPage: false } },
+ blobs: { pageInfo: { hasNextPage: true, nextCursor: 'test' } },
+ });
- expect(vm.find(GlLoadingIcon).exists()).toBe(true);
+ expect(output).toEqual({ hasNextPage: true, nextCursor: 'test' });
+ });
});
});
diff --git a/spec/frontend/repository/components/table/row_spec.js b/spec/frontend/repository/components/table/row_spec.js
index 216128dce25..6b4508c418e 100644
--- a/spec/frontend/repository/components/table/row_spec.js
+++ b/spec/frontend/repository/components/table/row_spec.js
@@ -29,9 +29,10 @@ describe('Repository table row component', () => {
it('renders table row', () => {
factory({
- id: 1,
+ id: '1',
path: 'test',
type: 'file',
+ currentPath: '/',
});
expect(vm.element).toMatchSnapshot();
@@ -39,14 +40,15 @@ describe('Repository table row component', () => {
it.each`
type | component | componentName
- ${'folder'} | ${RouterLinkStub} | ${'RouterLink'}
+ ${'tree'} | ${RouterLinkStub} | ${'RouterLink'}
${'file'} | ${'a'} | ${'hyperlink'}
${'commit'} | ${'a'} | ${'hyperlink'}
`('renders a $componentName for type $type', ({ type, component }) => {
factory({
- id: 1,
+ id: '1',
path: 'test',
type,
+ currentPath: '/',
});
expect(vm.find(component).exists()).toBe(true);
@@ -54,14 +56,15 @@ describe('Repository table row component', () => {
it.each`
type | pushes
- ${'folder'} | ${true}
+ ${'tree'} | ${true}
${'file'} | ${false}
${'commit'} | ${false}
- `('pushes new router if type $type is folder', ({ type, pushes }) => {
+ `('pushes new router if type $type is tree', ({ type, pushes }) => {
factory({
- id: 1,
+ id: '1',
path: 'test',
type,
+ currentPath: '/',
});
vm.trigger('click');
@@ -75,9 +78,10 @@ describe('Repository table row component', () => {
it('renders commit ID for submodule', () => {
factory({
- id: 1,
+ id: '1',
path: 'test',
type: 'commit',
+ currentPath: '/',
});
expect(vm.find('.commit-sha').text()).toContain('1');
diff --git a/spec/frontend/repository/utils/icon_spec.js b/spec/frontend/repository/utils/icon_spec.js
index 52787327bef..3d84705f7ea 100644
--- a/spec/frontend/repository/utils/icon_spec.js
+++ b/spec/frontend/repository/utils/icon_spec.js
@@ -6,7 +6,7 @@ describe('getIconName', () => {
// file types
it.each`
type | path | icon
- ${'folder'} | ${''} | ${'folder'}
+ ${'tree'} | ${''} | ${'folder'}
${'commit'} | ${''} | ${'archive'}
${'file'} | ${'test.pdf'} | ${'file-pdf-o'}
${'file'} | ${'test.jpg'} | ${'file-image-o'}
diff --git a/spec/javascripts/jobs/components/job_app_spec.js b/spec/javascripts/jobs/components/job_app_spec.js
index cef40117304..f28d2c2a882 100644
--- a/spec/javascripts/jobs/components/job_app_spec.js
+++ b/spec/javascripts/jobs/components/job_app_spec.js
@@ -90,9 +90,12 @@ describe('Job App ', () => {
describe('triggered job', () => {
beforeEach(() => {
+ const aYearAgo = new Date();
+ aYearAgo.setFullYear(aYearAgo.getFullYear() - 1);
+
mock
.onGet(props.endpoint)
- .replyOnce(200, Object.assign({}, job, { started: '2017-05-24T10:59:52.000+01:00' }));
+ .replyOnce(200, Object.assign({}, job, { started: aYearAgo.toISOString() }));
vm = mountComponentWithStore(Component, { props, store });
});
diff --git a/spec/lib/banzai/filter/milestone_reference_filter_spec.rb b/spec/lib/banzai/filter/milestone_reference_filter_spec.rb
index 4c94e4fdae0..f0a5dc8d0d7 100644
--- a/spec/lib/banzai/filter/milestone_reference_filter_spec.rb
+++ b/spec/lib/banzai/filter/milestone_reference_filter_spec.rb
@@ -295,6 +295,25 @@ describe Banzai::Filter::MilestoneReferenceFilter do
end
end
+ shared_examples 'references with HTML entities' do
+ before do
+ milestone.update!(title: '&lt;html&gt;')
+ end
+
+ it 'links to a valid reference' do
+ doc = reference_filter('See %"&lt;html&gt;"')
+
+ expect(doc.css('a').first.attr('href')).to eq urls.milestone_url(milestone)
+ expect(doc.text).to eq 'See %<html>'
+ end
+
+ it 'ignores invalid milestone names and escapes entities' do
+ act = %(Milestone %"&lt;non valid&gt;")
+
+ expect(reference_filter(act).to_html).to eq act
+ end
+ end
+
shared_context 'project milestones' do
let(:reference) { milestone.to_reference(format: :iid) }
@@ -307,6 +326,7 @@ describe Banzai::Filter::MilestoneReferenceFilter do
it_behaves_like 'cross-project / cross-namespace complete reference'
it_behaves_like 'cross-project / same-namespace complete reference'
it_behaves_like 'cross project shorthand reference'
+ it_behaves_like 'references with HTML entities'
end
shared_context 'group milestones' do
@@ -317,6 +337,7 @@ describe Banzai::Filter::MilestoneReferenceFilter do
it_behaves_like 'String-based single-word references'
it_behaves_like 'String-based multi-word references in quotes'
it_behaves_like 'referencing a milestone in a link href'
+ it_behaves_like 'references with HTML entities'
it 'does not support references by IID' do
doc = reference_filter("See #{Milestone.reference_prefix}#{milestone.iid}")
diff --git a/spec/lib/gitlab/ci/config_spec.rb b/spec/lib/gitlab/ci/config_spec.rb
index fd2a29e4ddb..092e9f242b7 100644
--- a/spec/lib/gitlab/ci/config_spec.rb
+++ b/spec/lib/gitlab/ci/config_spec.rb
@@ -190,7 +190,6 @@ describe Gitlab::Ci::Config do
let(:remote_file_content) do
<<~HEREDOC
variables:
- AUTO_DEVOPS_DOMAIN: domain.example.com
POSTGRES_USER: user
POSTGRES_PASSWORD: testing-password
POSTGRES_ENABLED: "true"
@@ -232,7 +231,6 @@ describe Gitlab::Ci::Config do
"bundle install --jobs $(nproc) \"${FLAGS[@]}\""
]
variables = {
- AUTO_DEVOPS_DOMAIN: "domain.example.com",
POSTGRES_USER: "user",
POSTGRES_PASSWORD: "testing-password",
POSTGRES_ENABLED: "true",
diff --git a/spec/lib/gitlab/import_export/members_mapper_spec.rb b/spec/lib/gitlab/import_export/members_mapper_spec.rb
index 67e4c289906..c663cf42a83 100644
--- a/spec/lib/gitlab/import_export/members_mapper_spec.rb
+++ b/spec/lib/gitlab/import_export/members_mapper_spec.rb
@@ -73,6 +73,13 @@ describe Gitlab::ImportExport::MembersMapper do
expect(user2.authorized_project?(project)).to be true
end
+ it 'maps an owner as a maintainer' do
+ exported_members.first['access_level'] = ProjectMember::OWNER
+
+ expect(members_mapper.map[exported_user_id]).to eq(user2.id)
+ expect(ProjectMember.find_by_user_id(user2.id).access_level).to eq(ProjectMember::MAINTAINER)
+ end
+
context 'user is not an admin' do
let(:user) { create(:user) }
diff --git a/spec/lib/gitlab/omniauth_initializer_spec.rb b/spec/lib/gitlab/omniauth_initializer_spec.rb
index d808b4d49e0..f9c0daf1ef1 100644
--- a/spec/lib/gitlab/omniauth_initializer_spec.rb
+++ b/spec/lib/gitlab/omniauth_initializer_spec.rb
@@ -38,6 +38,28 @@ describe Gitlab::OmniauthInitializer do
subject.execute([hash_config])
end
+ it 'normalizes a String strategy_class' do
+ hash_config = { 'name' => 'hash', 'args' => { strategy_class: 'OmniAuth::Strategies::OAuth2Generic' } }
+
+ expect(devise_config).to receive(:omniauth).with(:hash, strategy_class: OmniAuth::Strategies::OAuth2Generic)
+
+ subject.execute([hash_config])
+ end
+
+ it 'allows a class to be specified in strategy_class' do
+ hash_config = { 'name' => 'hash', 'args' => { strategy_class: OmniAuth::Strategies::OAuth2Generic } }
+
+ expect(devise_config).to receive(:omniauth).with(:hash, strategy_class: OmniAuth::Strategies::OAuth2Generic)
+
+ subject.execute([hash_config])
+ end
+
+ it 'throws an error for an invalid strategy_class' do
+ hash_config = { 'name' => 'hash', 'args' => { strategy_class: 'OmniAuth::Strategies::Bogus' } }
+
+ expect { subject.execute([hash_config]) }.to raise_error(NameError)
+ end
+
it 'configures fail_with_empty_uid for shibboleth' do
shibboleth_config = { 'name' => 'shibboleth', 'args' => {} }
diff --git a/spec/models/ci/build_spec.rb b/spec/models/ci/build_spec.rb
index 5f2e8aa0baa..bc81c34f7ab 100644
--- a/spec/models/ci/build_spec.rb
+++ b/spec/models/ci/build_spec.rb
@@ -2604,30 +2604,6 @@ describe Ci::Build do
it { is_expected.to include(ci_config_path) }
end
- context 'when using auto devops' do
- context 'and is enabled' do
- before do
- project.create_auto_devops!(enabled: true, domain: 'example.com')
- end
-
- it "includes AUTO_DEVOPS_DOMAIN" do
- is_expected.to include(
- { key: 'AUTO_DEVOPS_DOMAIN', value: 'example.com', public: true, masked: false })
- end
- end
-
- context 'and is disabled' do
- before do
- project.create_auto_devops!(enabled: false, domain: 'example.com')
- end
-
- it "includes AUTO_DEVOPS_DOMAIN" do
- is_expected.not_to include(
- { key: 'AUTO_DEVOPS_DOMAIN', value: 'example.com', public: true, masked: false })
- end
- end
- end
-
context 'when pipeline variable overrides build variable' do
before do
build.yaml_variables = [{ key: 'MYVAR', value: 'myvar', public: true }]
diff --git a/spec/models/clusters/cluster_spec.rb b/spec/models/clusters/cluster_spec.rb
index 3ee8c340bfe..f066ed6b620 100644
--- a/spec/models/clusters/cluster_spec.rb
+++ b/spec/models/clusters/cluster_spec.rb
@@ -557,62 +557,15 @@ describe Clusters::Cluster do
end
context 'with no domain on cluster' do
- context 'with a project cluster' do
- let(:cluster) { create(:cluster, :project, :provided_by_gcp) }
- let(:project) { cluster.project }
+ let(:cluster) { create(:cluster, :project, :provided_by_gcp) }
+ let(:project) { cluster.project }
- context 'with domain set at instance level' do
- before do
- stub_application_setting(auto_devops_domain: 'global_domain.com')
-
- it { is_expected.to eq('global_domain.com') }
- end
- end
-
- context 'with domain set on ProjectAutoDevops' do
- before do
- auto_devops = project.build_auto_devops(domain: 'legacy-ado-domain.com')
- auto_devops.save
- end
-
- it { is_expected.to eq('legacy-ado-domain.com') }
- end
-
- context 'with domain set as environment variable on project' do
- before do
- variable = project.variables.build(key: 'AUTO_DEVOPS_DOMAIN', value: 'project-ado-domain.com')
- variable.save
- end
-
- it { is_expected.to eq('project-ado-domain.com') }
+ context 'with domain set at instance level' do
+ before do
+ stub_application_setting(auto_devops_domain: 'global_domain.com')
end
- context 'with domain set as environment variable on the group project' do
- let(:group) { create(:group) }
-
- before do
- project.update(parent_id: group.id)
- variable = group.variables.build(key: 'AUTO_DEVOPS_DOMAIN', value: 'group-ado-domain.com')
- variable.save
- end
-
- it { is_expected.to eq('group-ado-domain.com') }
- end
- end
-
- context 'with a group cluster' do
- let(:cluster) { create(:cluster, :group, :provided_by_gcp) }
-
- context 'with domain set as environment variable for the group' do
- let(:group) { cluster.group }
-
- before do
- variable = group.variables.build(key: 'AUTO_DEVOPS_DOMAIN', value: 'group-ado-domain.com')
- variable.save
- end
-
- it { is_expected.to eq('group-ado-domain.com') }
- end
+ it { is_expected.to eq('global_domain.com') }
end
end
end
diff --git a/spec/models/project_auto_devops_spec.rb b/spec/models/project_auto_devops_spec.rb
index b81e5610e2c..7bdd2367a68 100644
--- a/spec/models/project_auto_devops_spec.rb
+++ b/spec/models/project_auto_devops_spec.rb
@@ -14,65 +14,9 @@ describe ProjectAutoDevops do
it { is_expected.to respond_to(:created_at) }
it { is_expected.to respond_to(:updated_at) }
- describe '#has_domain?' do
- context 'when domain is defined' do
- let(:auto_devops) { build_stubbed(:project_auto_devops, project: project, domain: 'domain.com') }
-
- it { expect(auto_devops).to have_domain }
- end
-
- context 'when domain is empty' do
- let(:auto_devops) { build_stubbed(:project_auto_devops, project: project, domain: '') }
-
- context 'when there is an instance domain specified' do
- before do
- allow(Gitlab::CurrentSettings).to receive(:auto_devops_domain).and_return('example.com')
- end
-
- it { expect(auto_devops).to have_domain }
- end
-
- context 'when there is no instance domain specified' do
- before do
- allow(Gitlab::CurrentSettings).to receive(:auto_devops_domain).and_return(nil)
- end
-
- it { expect(auto_devops).not_to have_domain }
- end
- end
- end
-
describe '#predefined_variables' do
let(:auto_devops) { build_stubbed(:project_auto_devops, project: project, domain: domain) }
- context 'when domain is defined' do
- let(:domain) { 'example.com' }
-
- it 'returns AUTO_DEVOPS_DOMAIN' do
- expect(auto_devops.predefined_variables).to include(domain_variable)
- end
- end
-
- context 'when domain is not defined' do
- let(:domain) { nil }
-
- context 'when there is an instance domain specified' do
- before do
- allow(Gitlab::CurrentSettings).to receive(:auto_devops_domain).and_return('example.com')
- end
-
- it { expect(auto_devops.predefined_variables).to include(domain_variable) }
- end
-
- context 'when there is no instance domain specified' do
- before do
- allow(Gitlab::CurrentSettings).to receive(:auto_devops_domain).and_return(nil)
- end
-
- it { expect(auto_devops.predefined_variables).not_to include(domain_variable) }
- end
- end
-
context 'when deploy_strategy is manual' do
let(:auto_devops) { build_stubbed(:project_auto_devops, :manual_deployment, project: project) }
let(:expected_variables) do
@@ -105,10 +49,6 @@ describe ProjectAutoDevops do
.not_to include("STAGING_ENABLED", "INCREMENTAL_ROLLOUT_ENABLED")
end
end
-
- def domain_variable
- { key: 'AUTO_DEVOPS_DOMAIN', value: 'example.com', public: true }
- end
end
describe '#create_gitlab_deploy_token' do
diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb
index 425096d7e80..08662231fdf 100644
--- a/spec/models/project_spec.rb
+++ b/spec/models/project_spec.rb
@@ -3975,64 +3975,6 @@ describe Project do
end
end
- describe '#auto_devops_variables' do
- set(:project) { create(:project) }
-
- subject { project.auto_devops_variables }
-
- context 'when enabled in instance settings' do
- before do
- stub_application_setting(auto_devops_enabled: true)
- end
-
- context 'when domain is empty' do
- before do
- stub_application_setting(auto_devops_domain: nil)
- end
-
- it 'variables does not include AUTO_DEVOPS_DOMAIN' do
- is_expected.not_to include(domain_variable)
- end
- end
-
- context 'when domain is configured' do
- before do
- stub_application_setting(auto_devops_domain: 'example.com')
- end
-
- it 'variables includes AUTO_DEVOPS_DOMAIN' do
- is_expected.to include(domain_variable)
- end
- end
- end
-
- context 'when explicitly enabled' do
- context 'when domain is empty' do
- before do
- create(:project_auto_devops, project: project, domain: nil)
- end
-
- it 'variables does not include AUTO_DEVOPS_DOMAIN' do
- is_expected.not_to include(domain_variable)
- end
- end
-
- context 'when domain is configured' do
- before do
- create(:project_auto_devops, project: project, domain: 'example.com')
- end
-
- it 'variables includes AUTO_DEVOPS_DOMAIN' do
- is_expected.to include(domain_variable)
- end
- end
- end
-
- def domain_variable
- { key: 'AUTO_DEVOPS_DOMAIN', value: 'example.com', public: true }
- end
- end
-
describe '#latest_successful_builds_for' do
let(:project) { build(:project) }
diff --git a/spec/requests/api/internal_spec.rb b/spec/requests/api/internal_spec.rb
index bae0302f3ff..fcbff19bd61 100644
--- a/spec/requests/api/internal_spec.rb
+++ b/spec/requests/api/internal_spec.rb
@@ -997,18 +997,6 @@ describe API::Internal do
expect(json_response['warnings']).to eq('Error encountered with push options \'merge_request.create\': my error')
end
-
- context 'when the feature is disabled' do
- it 'does not invoke MergeRequests::PushOptionsHandlerService' do
- stub_feature_flags(mr_push_options: false)
-
- expect(MergeRequests::PushOptionsHandlerService).not_to receive(:new)
-
- expect do
- post api('/internal/post_receive'), params: valid_params
- end.not_to change { MergeRequest.count }
- end
- end
end
context 'broadcast message exists' do
diff --git a/spec/requests/api/variables_spec.rb b/spec/requests/api/variables_spec.rb
index cc07869a744..55b1419a004 100644
--- a/spec/requests/api/variables_spec.rb
+++ b/spec/requests/api/variables_spec.rb
@@ -43,6 +43,7 @@ describe API::Variables do
expect(response).to have_gitlab_http_status(200)
expect(json_response['value']).to eq(variable.value)
expect(json_response['protected']).to eq(variable.protected?)
+ expect(json_response['masked']).to eq(variable.masked?)
expect(json_response['variable_type']).to eq('env_var')
end
@@ -74,13 +75,14 @@ describe API::Variables do
context 'authorized user with proper permissions' do
it 'creates variable' do
expect do
- post api("/projects/#{project.id}/variables", user), params: { key: 'TEST_VARIABLE_2', value: 'PROTECTED_VALUE_2', protected: true }
+ post api("/projects/#{project.id}/variables", user), params: { key: 'TEST_VARIABLE_2', value: 'PROTECTED_VALUE_2', protected: true, masked: true }
end.to change {project.variables.count}.by(1)
expect(response).to have_gitlab_http_status(201)
expect(json_response['key']).to eq('TEST_VARIABLE_2')
expect(json_response['value']).to eq('PROTECTED_VALUE_2')
expect(json_response['protected']).to be_truthy
+ expect(json_response['masked']).to be_truthy
expect(json_response['variable_type']).to eq('env_var')
end
@@ -93,6 +95,7 @@ describe API::Variables do
expect(json_response['key']).to eq('TEST_VARIABLE_2')
expect(json_response['value']).to eq('VALUE_2')
expect(json_response['protected']).to be_falsey
+ expect(json_response['masked']).to be_falsey
expect(json_response['variable_type']).to eq('file')
end
diff --git a/spec/requests/rack_attack_global_spec.rb b/spec/requests/rack_attack_global_spec.rb
index a12646ea222..89adbc77a7f 100644
--- a/spec/requests/rack_attack_global_spec.rb
+++ b/spec/requests/rack_attack_global_spec.rb
@@ -182,6 +182,17 @@ describe 'Rack Attack global throttles' do
end
end
end
+
+ it 'logs RackAttack info into structured logs' do
+ requests_per_period.times do
+ get url_that_does_not_require_authentication
+ expect(response).to have_http_status 200
+ end
+
+ expect(Gitlab::AuthLogger).to receive(:error).once
+
+ get url_that_does_not_require_authentication
+ end
end
context 'when the throttle is disabled' do
@@ -327,6 +338,17 @@ describe 'Rack Attack global throttles' do
expect_rejection { get url_that_requires_authentication }
end
+
+ it 'logs RackAttack info into structured logs' do
+ requests_per_period.times do
+ get url_that_requires_authentication
+ expect(response).to have_http_status 200
+ end
+
+ expect(Gitlab::AuthLogger).to receive(:error).once
+
+ get url_that_requires_authentication
+ end
end
context 'when the throttle is disabled' do
diff --git a/spec/services/system_note_service_spec.rb b/spec/services/system_note_service_spec.rb
index 4d33c6f4094..2420817e1f7 100644
--- a/spec/services/system_note_service_spec.rb
+++ b/spec/services/system_note_service_spec.rb
@@ -132,7 +132,7 @@ describe SystemNoteService do
end
it 'sets the note text' do
- link = "http://localhost/#{project.full_path}/-/tags/#{tag_name}"
+ link = "/#{project.full_path}/-/tags/#{tag_name}"
expect(subject.note).to eq "tagged commit #{noteable.sha} to [`#{tag_name}`](#{link})"
end
@@ -1139,7 +1139,7 @@ describe SystemNoteService do
diff_id = merge_request.merge_request_diff.id
line_code = change_position.line_code(project.repository)
- expect(subject.note).to include(diffs_project_merge_request_url(project, merge_request, diff_id: diff_id, anchor: line_code))
+ expect(subject.note).to include(diffs_project_merge_request_path(project, merge_request, diff_id: diff_id, anchor: line_code))
end
end
diff --git a/vendor/jupyter/values.yaml b/vendor/jupyter/values.yaml
index 781d6e3042f..a5e13fdc104 100644
--- a/vendor/jupyter/values.yaml
+++ b/vendor/jupyter/values.yaml
@@ -8,8 +8,28 @@ hub:
extraConfig: |
c.KubeSpawner.cmd = ['jupyter-labhub']
+ async def add_auth_env(spawner):
+ '''
+ We set user's id, login and access token on single user image to
+ enable repository integration for JupyterHub.
+ See: https://gitlab.com/gitlab-org/gitlab-ce/issues/47138#note_154294790
+ '''
+ auth_state = await spawner.user.get_auth_state()
+
+ if not auth_state:
+ spawner.log.warning("No auth state for %s", spawner.user)
+ return
+
+ spawner.environment['GITLAB_ACCESS_TOKEN'] = auth_state['access_token']
+ spawner.environment['GITLAB_USER_LOGIN'] = auth_state['gitlab_user']['username']
+ spawner.environment['GITLAB_USER_ID'] = str(auth_state['gitlab_user']['id'])
+
+ c.KubeSpawner.pre_spawn_hook = add_auth_env
+
auth:
type: gitlab
+ state:
+ enabled: true
singleuser:
defaultUrl: "/lab"
diff --git a/yarn.lock b/yarn.lock
index 898159975fa..80178b04ba8 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -9,27 +9,7 @@
dependencies:
"@babel/highlight" "^7.0.0"
-"@babel/core@>=7.1.0", "@babel/core@^7.1.0":
- version "7.3.4"
- resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.3.4.tgz#921a5a13746c21e32445bf0798680e9d11a6530b"
- integrity sha512-jRsuseXBo9pN197KnDwhhaaBzyZr2oIcLHHTt2oDdQrej5Qp57dCCJafWx5ivU8/alEYDpssYqv1MUqcxwQlrA==
- dependencies:
- "@babel/code-frame" "^7.0.0"
- "@babel/generator" "^7.3.4"
- "@babel/helpers" "^7.2.0"
- "@babel/parser" "^7.3.4"
- "@babel/template" "^7.2.2"
- "@babel/traverse" "^7.3.4"
- "@babel/types" "^7.3.4"
- convert-source-map "^1.1.0"
- debug "^4.1.0"
- json5 "^2.1.0"
- lodash "^4.17.11"
- resolve "^1.3.2"
- semver "^5.4.1"
- source-map "^0.5.0"
-
-"@babel/core@^7.4.4":
+"@babel/core@>=7.1.0", "@babel/core@^7.1.0", "@babel/core@^7.4.4":
version "7.4.4"
resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.4.4.tgz#84055750b05fcd50f9915a826b44fa347a825250"
integrity sha512-lQgGX3FPRgbz2SKmhMtYgJvVzGZrmjaF4apZ2bLwofAKiSjxU0drPh4S/VasyYXwaTs+A1gvQ45BN8SQJzHsQQ==
@@ -49,18 +29,7 @@
semver "^5.4.1"
source-map "^0.5.0"
-"@babel/generator@^7.0.0":
- version "7.3.4"
- resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.3.4.tgz#9aa48c1989257877a9d971296e5b73bfe72e446e"
- integrity sha512-8EXhHRFqlVVWXPezBW5keTiQi/rJMQTg/Y9uVCEZ0CAF3PKtCCaVRnp64Ii1ujhkoDhhF1fVsImoN4yJ2uz4Wg==
- dependencies:
- "@babel/types" "^7.3.4"
- jsesc "^2.5.1"
- lodash "^4.17.11"
- source-map "^0.5.0"
- trim-right "^1.0.1"
-
-"@babel/generator@^7.3.4", "@babel/generator@^7.4.4":
+"@babel/generator@^7.0.0", "@babel/generator@^7.4.4":
version "7.4.4"
resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.4.4.tgz#174a215eb843fc392c7edcaabeaa873de6e8f041"
integrity sha512-53UOLK6TVNqKxf7RUh8NE851EHRxOOeVXKbK2bivdb+iziMyk03Sr4eaE9OELCbyZAAafAKPDwF2TPUES5QbxQ==
@@ -161,19 +130,7 @@
dependencies:
"@babel/types" "^7.0.0"
-"@babel/helper-module-transforms@^7.1.0":
- version "7.1.0"
- resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.1.0.tgz#470d4f9676d9fad50b324cdcce5fbabbc3da5787"
- integrity sha512-0JZRd2yhawo79Rcm4w0LwSMILFmFXjugG3yqf+P/UsKsRS1mJCmMwwlHDlMg7Avr9LrvSpp4ZSULO9r8jpCzcw==
- dependencies:
- "@babel/helper-module-imports" "^7.0.0"
- "@babel/helper-simple-access" "^7.1.0"
- "@babel/helper-split-export-declaration" "^7.0.0"
- "@babel/template" "^7.1.0"
- "@babel/types" "^7.0.0"
- lodash "^4.17.10"
-
-"@babel/helper-module-transforms@^7.4.4":
+"@babel/helper-module-transforms@^7.1.0", "@babel/helper-module-transforms@^7.4.4":
version "7.4.4"
resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.4.4.tgz#96115ea42a2f139e619e98ed46df6019b94414b8"
integrity sha512-3Z1yp8TVQf+B4ynN7WoHPKS8EkdTbgAEy0nU0rs/1Kw4pDgmvYH3rz3aI11KgxKCba2cn7N+tqzV1mY2HMN96w==
@@ -197,14 +154,7 @@
resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.0.0.tgz#bbb3fbee98661c569034237cc03967ba99b4f250"
integrity sha512-CYAOUCARwExnEixLdB6sDm2dIJ/YgEAKDM1MOeMeZu9Ld/bDgVo8aiWrXwcY7OBh+1Ea2uUcVRcxKk0GJvW7QA==
-"@babel/helper-regex@^7.0.0":
- version "7.0.0"
- resolved "https://registry.yarnpkg.com/@babel/helper-regex/-/helper-regex-7.0.0.tgz#2c1718923b57f9bbe64705ffe5640ac64d9bdb27"
- integrity sha512-TR0/N0NDCcUIUEbqV6dCO+LptmmSQFQ7q70lfcEB4URsjD0E1HzicrwUH+ap6BAQ2jhCX9Q4UqZy4wilujWlkg==
- dependencies:
- lodash "^4.17.10"
-
-"@babel/helper-regex@^7.4.4":
+"@babel/helper-regex@^7.0.0", "@babel/helper-regex@^7.4.4":
version "7.4.4"
resolved "https://registry.yarnpkg.com/@babel/helper-regex/-/helper-regex-7.4.4.tgz#a47e02bc91fb259d2e6727c2a30013e3ac13c4a2"
integrity sha512-Y5nuB/kESmR3tKjU8Nkn1wMGEx1tjJX076HBMeL3XLQCu6vA/YRzuTW0bbb+qRnXvQGn+d6Rx953yffl8vEy7Q==
@@ -222,17 +172,7 @@
"@babel/traverse" "^7.1.0"
"@babel/types" "^7.0.0"
-"@babel/helper-replace-supers@^7.1.0":
- version "7.2.3"
- resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.2.3.tgz#19970020cf22677d62b3a689561dbd9644d8c5e5"
- integrity sha512-GyieIznGUfPXPWu0yLS6U55Mz67AZD9cUk0BfirOWlPrXlBcan9Gz+vHGz+cPfuoweZSnPzPIm67VtQM0OWZbA==
- dependencies:
- "@babel/helper-member-expression-to-functions" "^7.0.0"
- "@babel/helper-optimise-call-expression" "^7.0.0"
- "@babel/traverse" "^7.2.3"
- "@babel/types" "^7.0.0"
-
-"@babel/helper-replace-supers@^7.4.4":
+"@babel/helper-replace-supers@^7.1.0", "@babel/helper-replace-supers@^7.4.4":
version "7.4.4"
resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.4.4.tgz#aee41783ebe4f2d3ab3ae775e1cc6f1a90cefa27"
integrity sha512-04xGEnd+s01nY1l15EuMS1rfKktNF+1CkKmHoErDppjAAZL+IUBZpzT748x262HF7fibaQPhbvWUl5HeSt1EXg==
@@ -250,7 +190,7 @@
"@babel/template" "^7.1.0"
"@babel/types" "^7.0.0"
-"@babel/helper-split-export-declaration@^7.0.0", "@babel/helper-split-export-declaration@^7.4.4":
+"@babel/helper-split-export-declaration@^7.4.4":
version "7.4.4"
resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.4.4.tgz#ff94894a340be78f53f06af038b205c49d993677"
integrity sha512-Ro/XkzLf3JFITkW6b+hNxzZ1n5OQ80NvIUdmHspih1XAhtN3vPTuUFT4eQnela+2MaZ5ulH+iyP513KJrxbN7Q==
@@ -267,7 +207,7 @@
"@babel/traverse" "^7.1.0"
"@babel/types" "^7.0.0"
-"@babel/helpers@^7.2.0", "@babel/helpers@^7.4.4":
+"@babel/helpers@^7.4.4":
version "7.4.4"
resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.4.4.tgz#868b0ef59c1dd4e78744562d5ce1b59c89f2f2a5"
integrity sha512-igczbR/0SeuPR8RFfC7tGrbdTbFL3QTvH6D+Z6zNxnTe//GyqmtHmDkzrqDmyZ3eSwPqB/LhyKoU5DXsp+Vp2A==
@@ -285,12 +225,7 @@
esutils "^2.0.2"
js-tokens "^4.0.0"
-"@babel/parser@^7.0.0":
- version "7.3.4"
- resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.3.4.tgz#a43357e4bbf4b92a437fb9e465c192848287f27c"
- integrity sha512-tXZCqWtlOOP4wgCp6RjRvLmfuhnqTLy9VHwRochJBCP2nDm27JnnuFEnXFASVyQNHk36jD1tAammsCEEqgscIQ==
-
-"@babel/parser@^7.2.2", "@babel/parser@^7.3.4", "@babel/parser@^7.4.4":
+"@babel/parser@^7.0.0", "@babel/parser@^7.4.4":
version "7.4.4"
resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.4.4.tgz#5977129431b8fe33471730d255ce8654ae1250b6"
integrity sha512-5pCS4mOsL+ANsFZGdvNLybx4wtqAZJ0MJjMHxvzI3bvIsz6sQvzW8XX92EYIkiPtIvcfG3Aj+Ir5VNyjnZhP7w==
@@ -515,16 +450,7 @@
"@babel/helper-module-transforms" "^7.1.0"
"@babel/helper-plugin-utils" "^7.0.0"
-"@babel/plugin-transform-modules-commonjs@^7.2.0":
- version "7.2.0"
- resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.2.0.tgz#c4f1933f5991d5145e9cfad1dfd848ea1727f404"
- integrity sha512-V6y0uaUQrQPXUrmj+hgnks8va2L0zcZymeU7TtWEgdRLNkceafKXEduv7QzgQAE4lT+suwooG9dC7LFhdRAbVQ==
- dependencies:
- "@babel/helper-module-transforms" "^7.1.0"
- "@babel/helper-plugin-utils" "^7.0.0"
- "@babel/helper-simple-access" "^7.1.0"
-
-"@babel/plugin-transform-modules-commonjs@^7.4.4":
+"@babel/plugin-transform-modules-commonjs@^7.2.0", "@babel/plugin-transform-modules-commonjs@^7.4.4":
version "7.4.4"
resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.4.4.tgz#0bef4713d30f1d78c2e59b3d6db40e60192cac1e"
integrity sha512-4sfBOJt58sEo9a2BQXnZq+Q3ZTSAUXyK3E30o36BOGnJ+tvJ6YSxF0PG6kERvbeISgProodWuI9UVG3/FMY6iw==
@@ -706,16 +632,7 @@
resolved "https://registry.yarnpkg.com/@babel/standalone/-/standalone-7.3.4.tgz#b622c1e522acef91b2a14f22bdcdd4f935a1a474"
integrity sha512-4L9c5i4WlGqbrjOVX0Yp8TIR5cEiw1/tPYYZENW/iuO2uI6viY38U7zALidzNfGdZIwNc+A/AWqMEWKeScWkBg==
-"@babel/template@^7.0.0":
- version "7.2.2"
- resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.2.2.tgz#005b3fdf0ed96e88041330379e0da9a708eb2907"
- integrity sha512-zRL0IMM02AUDwghf5LMSSDEz7sBCO2YnNmpg3uWTZj/v1rcG2BmQUvaGU8GhU8BvfMh1k2KIAYZ7Ji9KXPUg7g==
- dependencies:
- "@babel/code-frame" "^7.0.0"
- "@babel/parser" "^7.2.2"
- "@babel/types" "^7.2.2"
-
-"@babel/template@^7.1.0", "@babel/template@^7.2.2", "@babel/template@^7.4.4":
+"@babel/template@^7.0.0", "@babel/template@^7.1.0", "@babel/template@^7.4.4":
version "7.4.4"
resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.4.4.tgz#f4b88d1225689a08f5bc3a17483545be9e4ed237"
integrity sha512-CiGzLN9KgAvgZsnivND7rkA+AeJ9JB0ciPOD4U59GKbQP2iQl+olF1l76kJOupqidozfZ32ghwBEJDhnk9MEcw==
@@ -724,22 +641,7 @@
"@babel/parser" "^7.4.4"
"@babel/types" "^7.4.4"
-"@babel/traverse@^7.0.0", "@babel/traverse@^7.1.0", "@babel/traverse@^7.2.3":
- version "7.3.4"
- resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.3.4.tgz#1330aab72234f8dea091b08c4f8b9d05c7119e06"
- integrity sha512-TvTHKp6471OYEcE/91uWmhR6PrrYywQntCHSaZ8CM8Vmp+pjAusal4nGB2WCCQd0rvI7nOMKn9GnbcvTUz3/ZQ==
- dependencies:
- "@babel/code-frame" "^7.0.0"
- "@babel/generator" "^7.3.4"
- "@babel/helper-function-name" "^7.1.0"
- "@babel/helper-split-export-declaration" "^7.0.0"
- "@babel/parser" "^7.3.4"
- "@babel/types" "^7.3.4"
- debug "^4.1.0"
- globals "^11.1.0"
- lodash "^4.17.11"
-
-"@babel/traverse@^7.3.4", "@babel/traverse@^7.4.4":
+"@babel/traverse@^7.0.0", "@babel/traverse@^7.1.0", "@babel/traverse@^7.4.4":
version "7.4.4"
resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.4.4.tgz#0776f038f6d78361860b6823887d4f3937133fe8"
integrity sha512-Gw6qqkw/e6AGzlyj9KnkabJX7VcubqPtkUQVAwkc0wUMldr3A/hezNB3Rc5eIvId95iSGkGIOe5hh1kMKf951A==
@@ -754,7 +656,7 @@
globals "^11.1.0"
lodash "^4.17.11"
-"@babel/types@^7.0.0", "@babel/types@^7.2.2", "@babel/types@^7.3.4", "@babel/types@^7.4.4":
+"@babel/types@^7.0.0", "@babel/types@^7.4.4":
version "7.4.4"
resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.4.4.tgz#8db9e9a629bb7c29370009b4b779ed93fe57d5f0"
integrity sha512-dOllgYdnEFOebhkKCjzSVFqw/PmmB8pH6RGOWkY4GsboQNd47b1fBThBSwlHAq9alF9vc1M3+6oqR47R50L0tQ==
@@ -783,10 +685,10 @@
eslint-plugin-promise "^4.1.1"
eslint-plugin-vue "^5.0.0"
-"@gitlab/svgs@^1.60.0":
- version "1.60.0"
- resolved "https://registry.yarnpkg.com/@gitlab/svgs/-/svgs-1.60.0.tgz#c24fe0d40193f4b722e858c2f766b1c80f961cb7"
- integrity sha512-Io13vB7LMmPHwUXOoHI+dBYRKDoL0E1dw0b+kJOjesFo+uogaggXJJ4WNEGbWTueYyLckv1YhePACG2xgoLWow==
+"@gitlab/svgs@^1.62.0":
+ version "1.62.0"
+ resolved "https://registry.yarnpkg.com/@gitlab/svgs/-/svgs-1.62.0.tgz#7072220b7c3aeb31d49b770888ff923b31e44e39"
+ integrity sha512-xBmIidLfJZ3N9OJTsrtphsCbmenGm25AJe6s9Hsm9ikuSJ9FLBbwDJBORw95CSmajB0GdgbkPoTOWbIh1V9KgA==
"@gitlab/ui@^3.10.0":
version "3.10.0"
@@ -1921,16 +1823,7 @@ browserify-zlib@^0.2.0:
dependencies:
pako "~1.0.5"
-browserslist@^4.4.1:
- version "4.4.1"
- resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.4.1.tgz#42e828954b6b29a7a53e352277be429478a69062"
- integrity sha512-pEBxEXg7JwaakBXjATYw/D1YZh4QUSCX/Mnd/wnqSRPPSi1U39iDhDoKGoBUcraKdxDlrYqJxSI5nNvD+dWP2A==
- dependencies:
- caniuse-lite "^1.0.30000929"
- electron-to-chromium "^1.3.103"
- node-releases "^1.1.3"
-
-browserslist@^4.5.2, browserslist@^4.5.4:
+browserslist@^4.4.1, browserslist@^4.5.2, browserslist@^4.5.4:
version "4.6.0"
resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.6.0.tgz#5274028c26f4d933d5b1323307c1d1da5084c9ff"
integrity sha512-Jk0YFwXBuMOOol8n6FhgkDzn3mY9PYLYGk29zybF05SbRTsMgPqmTNeQQhOghCxq5oFqAXE3u4sYddr4C0uRhg==
@@ -2129,12 +2022,7 @@ camelcase@^5.0.0:
resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.0.0.tgz#03295527d58bd3cd4aa75363f35b2e8d97be2f42"
integrity sha512-faqwZqnWxbxn+F1d399ygeamQNy3lPp/H9H6rNrqYh4FSVCtcY+3cub1MxA8o9mDd55mM8Aghuu/kuyYA6VTsA==
-caniuse-lite@^1.0.30000929, caniuse-lite@^1.0.30000932:
- version "1.0.30000936"
- resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30000936.tgz#5d33b118763988bf721b9b8ad436d0400e4a116b"
- integrity sha512-orX4IdpbFhdNO7bTBhSbahp1EBpqzBc+qrvTRVUFfZgA4zta7TdM6PN5ZxkEUgDnz36m+PfWGcdX7AVfFWItJw==
-
-caniuse-lite@^1.0.30000967:
+caniuse-lite@^1.0.30000932, caniuse-lite@^1.0.30000967:
version "1.0.30000969"
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30000969.tgz#7664f571f2072657bde70b00a1fc1ba41f1942a9"
integrity sha512-Kus0yxkoAJgVc0bax7S4gLSlFifCa7MnSZL9p9VuS/HIKEL4seaqh28KIQAAO50cD/rJ5CiJkJFapkdDAlhFxQ==
@@ -3678,11 +3566,6 @@ ejs@^2.6.1:
resolved "https://registry.yarnpkg.com/ejs/-/ejs-2.6.1.tgz#498ec0d495655abc6f23cd61868d926464071aa0"
integrity sha512-0xy4A/twfrRCnkhfk8ErDi5DqdAsAqeGxht4xkCUrsvhhbQNs7E+4jV0CN7+NKIY0aHE72+XvqtBIXzD31ZbXQ==
-electron-to-chromium@^1.3.103:
- version "1.3.113"
- resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.113.tgz#b1ccf619df7295aea17bc6951dc689632629e4a9"
- integrity sha512-De+lPAxEcpxvqPTyZAXELNpRZXABRxf+uL/rSykstQhzj/B0l1150G/ExIIxKc16lI89Hgz81J0BHAcbTqK49g==
-
electron-to-chromium@^1.3.133:
version "1.3.135"
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.135.tgz#f5799b95f2bcd8de17cde47d63392d83a4477041"
@@ -4886,16 +4769,11 @@ global-prefix@^3.0.0:
kind-of "^6.0.2"
which "^1.3.1"
-globals@^11.1.0:
+globals@^11.1.0, globals@^11.7.0:
version "11.12.0"
resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e"
integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==
-globals@^11.7.0:
- version "11.7.0"
- resolved "https://registry.yarnpkg.com/globals/-/globals-11.7.0.tgz#a583faa43055b1aca771914bf68258e2fc125673"
- integrity sha512-K8BNSPySfeShBQXsahYB/AbbWruVOTyVpgoIDnl8odPpeSfP2J5QO2oLFFdl2j7GfDCtZj2bMKar2T49itTPCg==
-
globby@^5.0.0:
version "5.0.0"
resolved "https://registry.yarnpkg.com/globby/-/globby-5.0.0.tgz#ebd84667ca0dbb330b99bcfc68eac2bc54370e0d"
@@ -7474,16 +7352,11 @@ mute-stream@0.0.7:
resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.7.tgz#3075ce93bc21b8fab43e1bc4da7e8115ed1e7bab"
integrity sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s=
-nan@^2.12.1:
+nan@^2.12.1, nan@^2.13.2:
version "2.14.0"
resolved "https://registry.yarnpkg.com/nan/-/nan-2.14.0.tgz#7818f722027b2459a86f0295d434d1fc2336c52c"
integrity sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg==
-nan@^2.13.2:
- version "2.13.2"
- resolved "https://registry.yarnpkg.com/nan/-/nan-2.13.2.tgz#f51dc7ae66ba7d5d55e1e6d4d8092e802c9aefe7"
- integrity sha512-TghvYc72wlMGMVMluVo9WRJc0mB8KxxF/gZ4YYFy7V2ZQX9l7rgbPg7vjS9mt6U5HXODVFVI2bOduCzwOMv/lw==
-
nanomatch@^1.2.9:
version "1.2.9"
resolved "https://registry.yarnpkg.com/nanomatch/-/nanomatch-1.2.9.tgz#879f7150cb2dab7a471259066c104eee6e0fa7c2"
@@ -7639,13 +7512,6 @@ node-releases@^1.1.19:
dependencies:
semver "^5.3.0"
-node-releases@^1.1.3:
- version "1.1.3"
- resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.1.3.tgz#aad9ce0dcb98129c753f772c0aa01360fb90fbd2"
- integrity sha512-6VrvH7z6jqqNFY200kdB6HdzkgM96Oaj9v3dqGfgp6mF+cHmU4wyQKZ2/WPDRVoR0Jz9KqbamaBN0ZhdUaysUQ==
- dependencies:
- semver "^5.3.0"
-
node-sass@^4.12.0:
version "4.12.0"
resolved "https://registry.yarnpkg.com/node-sass/-/node-sass-4.12.0.tgz#0914f531932380114a30cc5fa4fa63233a25f017"
@@ -9358,14 +9224,7 @@ resolve@1.1.7, resolve@1.1.x:
resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.1.7.tgz#203114d82ad2c5ed9e8e0411b3932875e889e97b"
integrity sha1-IDEU2CrSxe2ejgQRs5ModeiJ6Xs=
-resolve@1.x, resolve@^1.10.0, resolve@^1.4.0, resolve@^1.5.0, resolve@^1.9.0:
- version "1.10.0"
- resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.10.0.tgz#3bdaaeaf45cc07f375656dfd2e54ed0810b101ba"
- integrity sha512-3sUr9aq5OfSg2S9pNtPA9hL1FVEAjvfOC4leW0SNf/mpnaakz2a9femSd6LqAww2RaFctwyf1lCqnTHuF1rxDg==
- dependencies:
- path-parse "^1.0.6"
-
-resolve@^1.3.2:
+resolve@1.x, resolve@^1.10.0, resolve@^1.3.2, resolve@^1.4.0, resolve@^1.5.0, resolve@^1.9.0:
version "1.11.0"
resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.11.0.tgz#4014870ba296176b86343d50b60f3b50609ce232"
integrity sha512-WL2pBDjqT6pGUNSUzMw00o4T7If+z4H2x3Gz893WoUQ5KW8Vr9txp00ykiP16VBaZF5+j/OcXJHZ9+PCvdiDKw==
@@ -9583,12 +9442,7 @@ semver-diff@^2.0.0:
dependencies:
semver "^5.0.3"
-"semver@2 || 3 || 4 || 5", semver@^5.0.3, semver@^5.1.0, semver@^5.3.0, semver@^5.5, semver@^5.5.0, semver@^5.5.1, semver@^5.6.0:
- version "5.6.0"
- resolved "https://registry.yarnpkg.com/semver/-/semver-5.6.0.tgz#7e74256fbaa49c75aa7c7a205cc22799cac80004"
- integrity sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg==
-
-semver@^5.4.1:
+"semver@2 || 3 || 4 || 5", semver@^5.0.3, semver@^5.1.0, semver@^5.3.0, semver@^5.4.1, semver@^5.5, semver@^5.5.0, semver@^5.5.1, semver@^5.6.0:
version "5.7.0"
resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.0.tgz#790a7cf6fea5459bac96110b29b60412dc8ff96b"
integrity sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==