summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--GITLAB_SHELL_VERSION2
-rw-r--r--app/assets/javascripts/boards/components/new_list_dropdown.js7
-rw-r--r--app/assets/javascripts/ci_variable_list/ci_variable_list.js2
-rw-r--r--app/assets/javascripts/commit/image_file.js1
-rw-r--r--app/assets/javascripts/commons/jquery.js2
-rw-r--r--app/assets/javascripts/diff.js7
-rw-r--r--app/assets/javascripts/dispatcher.js21
-rw-r--r--app/assets/javascripts/environments/components/environment_item.vue31
-rw-r--r--app/assets/javascripts/gl_form.js3
-rw-r--r--app/assets/javascripts/gpg_badges.js17
-rw-r--r--app/assets/javascripts/importer_status.js68
-rw-r--r--app/assets/javascripts/issue.js1
-rw-r--r--app/assets/javascripts/merge_request.js2
-rw-r--r--app/assets/javascripts/pages/ci/lints/ci_lint_editor.js7
-rw-r--r--app/assets/javascripts/pages/projects/merge_requests/show/index.js24
-rw-r--r--app/assets/javascripts/render_mermaid.js3
-rw-r--r--app/assets/javascripts/sidebar/components/time_tracking/sidebar_time_tracking.js4
-rw-r--r--app/assets/javascripts/sidebar/components/time_tracking/time_tracker.vue (renamed from app/assets/javascripts/sidebar/components/time_tracking/time_tracker.js)149
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_missing_branch.js43
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_missing_branch.vue62
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/dependencies.js2
-rw-r--r--app/assets/javascripts/vue_shared/components/confirmation_input.vue62
-rw-r--r--app/assets/stylesheets/framework.scss14
-rw-r--r--app/assets/stylesheets/framework/broadcast_messages.scss (renamed from app/assets/stylesheets/framework/broadcast-messages.scss)0
-rw-r--r--app/assets/stylesheets/framework/contextual_sidebar.scss (renamed from app/assets/stylesheets/framework/contextual-sidebar.scss)0
-rw-r--r--app/assets/stylesheets/framework/emoji_sprites.scss (renamed from app/assets/stylesheets/framework/emoji-sprites.scss)0
-rw-r--r--app/assets/stylesheets/framework/gitlab_theme.scss (renamed from app/assets/stylesheets/framework/gitlab-theme.scss)0
-rw-r--r--app/assets/stylesheets/framework/page_header.scss (renamed from app/assets/stylesheets/framework/page-header.scss)0
-rw-r--r--app/assets/stylesheets/framework/secondary_navigation_elements.scss (renamed from app/assets/stylesheets/framework/secondary-navigation-elements.scss)0
-rw-r--r--app/assets/stylesheets/framework/stacked_progress_bar.scss (renamed from app/assets/stylesheets/framework/stacked-progress-bar.scss)0
-rw-r--r--app/assets/stylesheets/pages/environments.scss4
-rw-r--r--app/controllers/import/base_controller.rb24
-rw-r--r--app/controllers/import/bitbucket_controller.rb22
-rw-r--r--app/controllers/import/fogbugz_controller.rb16
-rw-r--r--app/controllers/import/github_controller.rb19
-rw-r--r--app/controllers/import/gitlab_controller.rb18
-rw-r--r--app/controllers/import/google_code_controller.rb16
-rw-r--r--app/controllers/root_controller.rb5
-rw-r--r--app/finders/snippets_finder.rb67
-rw-r--r--app/models/ci/build.rb1
-rw-r--r--app/models/merge_request.rb8
-rw-r--r--app/models/namespace.rb4
-rw-r--r--app/models/project.rb5
-rw-r--r--app/models/snippet.rb21
-rw-r--r--app/models/user.rb7
-rw-r--r--app/policies/project_policy.rb1
-rw-r--r--app/serializers/project_serializer.rb3
-rw-r--r--app/services/groups/nested_create_service.rb10
-rw-r--r--app/views/ci/lints/show.html.haml2
-rw-r--r--app/views/ci/variables/_variable_row.html.haml2
-rw-r--r--app/views/import/base/create.js.haml13
-rw-r--r--app/views/import/base/unauthorized.js.haml14
-rw-r--r--app/views/projects/graphs/charts.html.haml31
-rw-r--r--changelogs/unreleased/40994-expose-features-as-ci-cd-variable.yml5
-rw-r--r--changelogs/unreleased/42922-environment-name.yml5
-rw-r--r--changelogs/unreleased/bvl-fix-concurrent-fork-network-migrations.yml5
-rw-r--r--changelogs/unreleased/docs-update-vue-naming-guidelines.yml5
-rw-r--r--changelogs/unreleased/feature-26598-clear-button-ci-lint.yml4
-rw-r--r--changelogs/unreleased/feature-oidc-groups-claim.yml4
-rw-r--r--changelogs/unreleased/internationalize-charts-page.yml5
-rw-r--r--changelogs/unreleased/refactor-move-issuable-time-tracker-vue-component.yml5
-rw-r--r--config/application.rb1
-rw-r--r--config/initializers/doorkeeper_openid_connect.rb1
-rw-r--r--config/locales/doorkeeper.en.yml2
-rw-r--r--db/migrate/20170929131201_populate_fork_networks.rb16
-rw-r--r--db/post_migrate/20171124150326_reschedule_fork_network_creation.rb16
-rw-r--r--doc/administration/high_availability/gitlab.md10
-rw-r--r--doc/administration/repository_storage_types.md91
-rw-r--r--doc/development/background_migrations.md12
-rw-r--r--doc/development/fe_guide/style_guide_js.md43
-rw-r--r--doc/development/fe_guide/style_guide_scss.md2
-rw-r--r--doc/development/i18n/externalization.md3
-rw-r--r--doc/install/installation.md4
-rw-r--r--doc/integration/openid_connect_provider.md1
-rw-r--r--doc/update/10.4-to-10.5.md361
-rw-r--r--doc/user/project/img/label_priority_sort_order.pngbin101667 -> 0 bytes
-rw-r--r--doc/user/project/img/labels_assign_label_sidebar.pngbin11767 -> 0 bytes
-rw-r--r--doc/user/project/img/labels_assign_label_sidebar_saved.pngbin9741 -> 0 bytes
-rw-r--r--doc/user/project/img/labels_default.pngbin24404 -> 22975 bytes
-rw-r--r--doc/user/project/img/labels_description_tooltip.pngbin8538 -> 0 bytes
-rw-r--r--doc/user/project/img/labels_filter.pngbin19071 -> 0 bytes
-rw-r--r--doc/user/project/img/labels_generate.pngbin13628 -> 0 bytes
-rw-r--r--doc/user/project/img/labels_generate_default.pngbin0 -> 65549 bytes
-rw-r--r--doc/user/project/img/labels_group_issues.pngbin0 -> 264573 bytes
-rw-r--r--doc/user/project/img/labels_list.pngbin0 -> 207736 bytes
-rw-r--r--doc/user/project/img/labels_new_label.pngbin10720 -> 0 bytes
-rw-r--r--doc/user/project/img/labels_new_label_on_the_fly.pngbin4625 -> 0 bytes
-rw-r--r--doc/user/project/img/labels_new_label_on_the_fly_create.pngbin6389 -> 0 bytes
-rw-r--r--doc/user/project/img/labels_prioritize.pngbin24194 -> 0 bytes
-rw-r--r--doc/user/project/img/labels_prioritized.pngbin0 -> 156020 bytes
-rw-r--r--doc/user/project/img/labels_promotion.pngbin0 -> 121824 bytes
-rw-r--r--doc/user/project/img/labels_sidebar.pngbin0 -> 31123 bytes
-rw-r--r--doc/user/project/img/labels_sidebar_assign.pngbin0 -> 28033 bytes
-rw-r--r--doc/user/project/img/labels_sidebar_inline.pngbin0 -> 28423 bytes
-rw-r--r--doc/user/project/img/labels_sort_label_priority.pngbin0 -> 110154 bytes
-rw-r--r--doc/user/project/img/labels_sort_priority.pngbin0 -> 108780 bytes
-rw-r--r--doc/user/project/img/labels_subscribe.pngbin5336 -> 0 bytes
-rw-r--r--doc/user/project/img/labels_subscriptions.pngbin0 -> 87502 bytes
-rw-r--r--doc/user/project/img/new_label_from_sidebar.gifbin0 -> 759243 bytes
-rw-r--r--doc/user/project/issues/index.md4
-rw-r--r--doc/user/project/labels.md189
-rw-r--r--doc/user/project/merge_requests/index.md21
-rw-r--r--doc/user/project/merge_requests/work_in_progress_merge_requests.md3
-rw-r--r--doc/user/project/pages/getting_started_part_three.md33
-rw-r--r--doc/user/project/pages/index.md1
-rw-r--r--lib/api/internal.rb2
-rw-r--r--lib/api/search.rb8
-rw-r--r--lib/api/todos.rb2
-rw-r--r--lib/api/v3/todos.rb2
-rw-r--r--lib/banzai/filter/syntax_highlight_filter.rb34
-rw-r--r--lib/gitlab/background_migration/create_fork_network_memberships_range.rb15
-rw-r--r--lib/gitlab/encoding_helper.rb6
-rw-r--r--lib/gitlab/git/repository.rb19
-rw-r--r--lib/gitlab/shell.rb12
-rw-r--r--lib/tasks/gemojione.rake2
-rw-r--r--locale/gitlab.pot27
-rw-r--r--package.json1
-rw-r--r--qa/README.md24
-rw-r--r--qa/qa/page/main/login.rb35
-rw-r--r--qa/qa/runtime/env.rb22
-rw-r--r--qa/qa/runtime/namespace.rb2
-rw-r--r--qa/qa/runtime/user.rb8
-rw-r--r--qa/qa/service/runner.rb10
-rw-r--r--qa/qa/service/shellout.rb4
-rw-r--r--qa/qa/specs/features/api/users_spec.rb4
-rw-r--r--qa/spec/runtime/env_spec.rb21
-rw-r--r--spec/controllers/import/bitbucket_controller_spec.rb98
-rw-r--r--spec/controllers/import/gitlab_controller_spec.rb95
-rw-r--r--spec/controllers/profiles_controller_spec.rb40
-rw-r--r--spec/controllers/projects_controller_spec.rb96
-rw-r--r--spec/factories/projects.rb6
-rw-r--r--spec/features/ci_lint_spec.rb34
-rw-r--r--spec/features/markdown/copy_as_gfm_spec.rb (renamed from spec/features/copy_as_gfm_spec.rb)0
-rw-r--r--spec/features/markdown/gitlab_flavored_markdown_spec.rb (renamed from spec/features/gitlab_flavored_markdown_spec.rb)0
-rw-r--r--spec/features/markdown/markdown_spec.rb (renamed from spec/features/markdown_spec.rb)0
-rw-r--r--spec/features/markdown/math_spec.rb22
-rw-r--r--spec/features/markdown/mermaid_spec.rb24
-rw-r--r--spec/features/projects/import_export/namespace_export_file_spec.rb6
-rw-r--r--spec/finders/snippets_finder_spec.rb67
-rw-r--r--spec/javascripts/ci_variable_list/ci_variable_list_spec.js2
-rw-r--r--spec/javascripts/gl_form_spec.js20
-rw-r--r--spec/javascripts/gpg_badges_spec.js50
-rw-r--r--spec/javascripts/importer_status_spec.js47
-rw-r--r--spec/javascripts/issuable_time_tracker_spec.js2
-rw-r--r--spec/javascripts/vue_mr_widget/components/states/mr_widget_missing_branch_spec.js34
-rw-r--r--spec/javascripts/vue_shared/components/confirmation_input_spec.js63
-rw-r--r--spec/lib/backup/repository_spec.rb18
-rw-r--r--spec/lib/banzai/filter/syntax_highlight_filter_spec.rb57
-rw-r--r--spec/lib/gitlab/background_migration/populate_untracked_uploads_spec.rb22
-rw-r--r--spec/lib/gitlab/background_migration/prepare_untracked_uploads_spec.rb4
-rw-r--r--spec/lib/gitlab/bare_repository_import/importer_spec.rb6
-rw-r--r--spec/lib/gitlab/database/rename_reserved_paths_migration/v1/rename_namespaces_spec.rb14
-rw-r--r--spec/lib/gitlab/database/rename_reserved_paths_migration/v1/rename_projects_spec.rb11
-rw-r--r--spec/lib/gitlab/email/attachment_uploader_spec.rb2
-rw-r--r--spec/lib/gitlab/encoding_helper_spec.rb5
-rw-r--r--spec/lib/gitlab/gfm/uploads_rewriter_spec.rb4
-rw-r--r--spec/lib/gitlab/import_export/uploads_restorer_spec.rb4
-rw-r--r--spec/lib/gitlab/import_export/uploads_saver_spec.rb4
-rw-r--r--spec/lib/gitlab/repo_path_spec.rb4
-rw-r--r--spec/lib/gitlab/shell_spec.rb2
-rw-r--r--spec/lib/gitlab/workhorse_spec.rb2
-rw-r--r--spec/migrations/migrate_process_commit_worker_jobs_spec.rb2
-rw-r--r--spec/migrations/turn_nested_groups_into_regular_groups_for_mysql_spec.rb2
-rw-r--r--spec/models/ci/build_spec.rb9
-rw-r--r--spec/models/group_spec.rb8
-rw-r--r--spec/models/namespace_spec.rb206
-rw-r--r--spec/models/project_spec.rb39
-rw-r--r--spec/models/user_spec.rb25
-rw-r--r--spec/policies/personal_snippet_policy_spec.rb1
-rw-r--r--spec/policies/project_snippet_policy_spec.rb1
-rw-r--r--spec/requests/api/internal_spec.rb66
-rw-r--r--spec/requests/api/projects_spec.rb11
-rw-r--r--spec/requests/api/search_spec.rb20
-rw-r--r--spec/requests/api/snippets_spec.rb21
-rw-r--r--spec/requests/api/todos_spec.rb6
-rw-r--r--spec/requests/api/v3/projects_spec.rb4
-rw-r--r--spec/requests/api/v3/todos_spec.rb6
-rw-r--r--spec/requests/git_http_spec.rb2
-rw-r--r--spec/requests/openid_connect_spec.rb24
-rw-r--r--spec/services/groups/destroy_service_spec.rb6
-rw-r--r--spec/services/projects/hashed_storage/migrate_attachments_service_spec.rb2
-rw-r--r--spec/services/projects/hashed_storage/migrate_repository_service_spec.rb2
-rw-r--r--spec/services/projects/hashed_storage_migration_service_spec.rb2
-rw-r--r--spec/services/projects/transfer_service_spec.rb4
-rw-r--r--spec/services/projects/update_service_spec.rb2
-rw-r--r--spec/services/search/snippet_service_spec.rb2
-rw-r--r--spec/services/users/destroy_service_spec.rb4
-rw-r--r--spec/support/controllers/githubish_import_controller_shared_examples.rb152
-rw-r--r--spec/support/features/variable_list_shared_examples.rb8
-rw-r--r--spec/support/migrations_helpers.rb9
-rw-r--r--spec/support/snippet_visibility.rb304
-rw-r--r--spec/uploaders/file_uploader_spec.rb6
-rw-r--r--spec/workers/repository_fork_worker_spec.rb2
-rw-r--r--spec/workers/storage_migrator_worker_spec.rb2
-rw-r--r--vendor/assets/javascripts/jquery.waitforimages.js144
-rw-r--r--vendor/gitignore/Android.gitignore7
-rw-r--r--vendor/gitignore/Dart.gitignore1
-rw-r--r--vendor/gitignore/Global/JetBrains.gitignore3
-rw-r--r--vendor/gitignore/Python.gitignore1
-rw-r--r--vendor/gitignore/ROS.gitignore2
-rw-r--r--vendor/gitignore/TeX.gitignore1
-rw-r--r--vendor/gitignore/VisualStudio.gitignore1
-rw-r--r--vendor/gitlab-ci-yml/Auto-DevOps.gitlab-ci.yml32
-rw-r--r--vendor/licenses.csv1268
-rw-r--r--yarn.lock4
205 files changed, 3869 insertions, 1379 deletions
diff --git a/GITLAB_SHELL_VERSION b/GITLAB_SHELL_VERSION
index 9b9a244206f..090ea9dad19 100644
--- a/GITLAB_SHELL_VERSION
+++ b/GITLAB_SHELL_VERSION
@@ -1 +1 @@
-6.0.2
+6.0.3
diff --git a/app/assets/javascripts/boards/components/new_list_dropdown.js b/app/assets/javascripts/boards/components/new_list_dropdown.js
index c19c989680d..cf0bb5f5376 100644
--- a/app/assets/javascripts/boards/components/new_list_dropdown.js
+++ b/app/assets/javascripts/boards/components/new_list_dropdown.js
@@ -1,5 +1,6 @@
/* eslint-disable func-names, no-new, space-before-function-paren, one-var,
promise/catch-or-return */
+import axios from '~/lib/utils/axios_utils';
import _ from 'underscore';
import CreateLabelDropdown from '../../create_label';
@@ -28,9 +29,9 @@ gl.issueBoards.newListDropdownInit = () => {
$this.glDropdown({
data(term, callback) {
- $.get($this.attr('data-list-labels-path'))
- .then((resp) => {
- callback(resp);
+ axios.get($this.attr('data-list-labels-path'))
+ .then(({ data }) => {
+ callback(data);
});
},
renderRow (label) {
diff --git a/app/assets/javascripts/ci_variable_list/ci_variable_list.js b/app/assets/javascripts/ci_variable_list/ci_variable_list.js
index d91789c2192..3467e88119b 100644
--- a/app/assets/javascripts/ci_variable_list/ci_variable_list.js
+++ b/app/assets/javascripts/ci_variable_list/ci_variable_list.js
@@ -39,7 +39,7 @@ export default class VariableList {
},
protected: {
selector: '.js-ci-variable-input-protected',
- default: 'true',
+ default: 'false',
},
environment_scope: {
// We can't use a `.js-` class here because
diff --git a/app/assets/javascripts/commit/image_file.js b/app/assets/javascripts/commit/image_file.js
index 525fbf9dac9..6504a0bbbfc 100644
--- a/app/assets/javascripts/commit/image_file.js
+++ b/app/assets/javascripts/commit/image_file.js
@@ -1,5 +1,4 @@
/* eslint-disable func-names, space-before-function-paren, wrap-iife, no-var, no-use-before-define, prefer-arrow-callback, no-else-return, consistent-return, prefer-template, quotes, one-var, one-var-declaration-per-line, no-unused-vars, no-return-assign, comma-dangle, quote-props, no-unused-expressions, no-sequences, object-shorthand, max-len */
-import 'vendor/jquery.waitforimages';
// Width where images must fits in, for 2-up this gets divided by 2
const availWidth = 900;
diff --git a/app/assets/javascripts/commons/jquery.js b/app/assets/javascripts/commons/jquery.js
index b93e94a3c97..a7ed175f7a4 100644
--- a/app/assets/javascripts/commons/jquery.js
+++ b/app/assets/javascripts/commons/jquery.js
@@ -6,5 +6,5 @@ import 'vendor/jquery.endless-scroll';
import 'vendor/jquery.caret';
import 'vendor/jquery.atwho';
import 'vendor/jquery.scrollTo';
-import 'vendor/jquery.waitforimages';
+import 'jquery.waitforimages';
import 'select2/select2';
diff --git a/app/assets/javascripts/diff.js b/app/assets/javascripts/diff.js
index a162424b3cf..3ab8f3ab7ad 100644
--- a/app/assets/javascripts/diff.js
+++ b/app/assets/javascripts/diff.js
@@ -1,3 +1,6 @@
+import axios from '~/lib/utils/axios_utils';
+import flash from '~/flash';
+import { __ } from '~/locale';
import { getLocationHash } from './lib/utils/url_utility';
import FilesCommentButton from './files_comment_button';
import SingleFileDiff from './single_file_diff';
@@ -69,7 +72,9 @@ export default class Diff {
const view = file.data('view');
const params = { since, to, bottom, offset, unfold, view };
- $.get(link, params, response => $target.parent().replaceWith(response));
+ axios.get(link, { params })
+ .then(({ data }) => $target.parent().replaceWith(data))
+ .catch(() => flash(__('An error occurred while loading diff')));
}
openAnchoredDiff(cb) {
diff --git a/app/assets/javascripts/dispatcher.js b/app/assets/javascripts/dispatcher.js
index aceaffdfcb9..f8082c74943 100644
--- a/app/assets/javascripts/dispatcher.js
+++ b/app/assets/javascripts/dispatcher.js
@@ -1,15 +1,9 @@
/* eslint-disable func-names, space-before-function-paren, no-var, prefer-arrow-callback, wrap-iife, no-shadow, consistent-return, one-var, one-var-declaration-per-line, camelcase, default-case, no-new, quotes, no-duplicate-case, no-case-declarations, no-fallthrough, max-len */
-import MergeRequest from './merge_request';
import Flash from './flash';
import GfmAutoComplete from './gfm_auto_complete';
-import ZenMode from './zen_mode';
-import initNotes from './init_notes';
-import initIssuableSidebar from './init_issuable_sidebar';
import { convertPermissionToBoolean } from './lib/utils/common_utils';
import GlFieldErrors from './gl_field_errors';
import Shortcuts from './shortcuts';
-import ShortcutsIssuable from './shortcuts_issuable';
-import Diff from './diff';
import SearchAutocomplete from './search_autocomplete';
var Dispatcher;
@@ -262,17 +256,10 @@ var Dispatcher;
.catch(fail);
break;
case 'projects:merge_requests:show':
- new Diff();
- new ZenMode();
-
- initIssuableSidebar();
- initNotes();
-
- const mrShowNode = document.querySelector('.merge-request');
- window.mergeRequest = new MergeRequest({
- action: mrShowNode.dataset.mrAction,
- });
- shortcut_handler = new ShortcutsIssuable(true);
+ import('./pages/projects/merge_requests/show')
+ .then(callDefault)
+ .catch(fail);
+ shortcut_handler = true;
break;
case 'dashboard:activity':
import('./pages/dashboard/activity')
diff --git a/app/assets/javascripts/environments/components/environment_item.vue b/app/assets/javascripts/environments/components/environment_item.vue
index a9d554e549e..79326ca3487 100644
--- a/app/assets/javascripts/environments/components/environment_item.vue
+++ b/app/assets/javascripts/environments/components/environment_item.vue
@@ -1,8 +1,9 @@
<script>
import Timeago from 'timeago.js';
import _ from 'underscore';
- import userAvatarLink from '../../vue_shared/components/user_avatar/user_avatar_link.vue';
- import { humanize } from '../../lib/utils/text_utility';
+ import tooltip from '~/vue_shared/directives/tooltip';
+ import UserAvatarLink from '~/vue_shared/components/user_avatar/user_avatar_link.vue';
+ import { humanize } from '~/lib/utils/text_utility';
import ActionsComponent from './environment_actions.vue';
import ExternalUrlComponent from './environment_external_url.vue';
import StopComponent from './environment_stop.vue';
@@ -21,14 +22,18 @@
export default {
components: {
- userAvatarLink,
- 'commit-component': CommitComponent,
- 'actions-component': ActionsComponent,
- 'external-url-component': ExternalUrlComponent,
- 'stop-component': StopComponent,
- 'rollback-component': RollbackComponent,
- 'terminal-button-component': TerminalButtonComponent,
- 'monitoring-button-component': MonitoringButtonComponent,
+ UserAvatarLink,
+ CommitComponent,
+ ActionsComponent,
+ ExternalUrlComponent,
+ StopComponent,
+ RollbackComponent,
+ TerminalButtonComponent,
+ MonitoringButtonComponent,
+ },
+
+ directives: {
+ tooltip,
},
props: {
@@ -443,7 +448,11 @@
v-if="!model.isFolder"
class="environment-name flex-truncate-parent table-mobile-content"
:href="environmentPath">
- <span class="flex-truncate-child">{{ model.name }}</span>
+ <span
+ class="flex-truncate-child"
+ v-tooltip
+ :title="model.name"
+ >{{ model.name }}</span>
</a>
<span
v-else
diff --git a/app/assets/javascripts/gl_form.js b/app/assets/javascripts/gl_form.js
index d0f9e6af0f8..d200044b79f 100644
--- a/app/assets/javascripts/gl_form.js
+++ b/app/assets/javascripts/gl_form.js
@@ -1,5 +1,4 @@
-/* global autosize */
-
+import autosize from 'autosize';
import GfmAutoComplete from './gfm_auto_complete';
import dropzoneInput from './dropzone_input';
import textUtils from './lib/utils/text_markdown';
diff --git a/app/assets/javascripts/gpg_badges.js b/app/assets/javascripts/gpg_badges.js
index 7ac9dcd1112..b33165f9402 100644
--- a/app/assets/javascripts/gpg_badges.js
+++ b/app/assets/javascripts/gpg_badges.js
@@ -1,3 +1,8 @@
+import { parseQueryStringIntoObject } from '~/lib/utils/common_utils';
+import axios from '~/lib/utils/axios_utils';
+import flash from '~/flash';
+import { __ } from '~/locale';
+
export default class GpgBadges {
static fetch() {
const badges = $('.js-loading-gpg-badge');
@@ -5,13 +10,13 @@ export default class GpgBadges {
badges.html('<i class="fa fa-spinner fa-spin"></i>');
- $.get({
- url: form.data('signatures-path'),
- data: form.serialize(),
- }).done((response) => {
- response.signatures.forEach((signature) => {
+ const params = parseQueryStringIntoObject(form.serialize());
+ return axios.get(form.data('signatures-path'), { params })
+ .then(({ data }) => {
+ data.signatures.forEach((signature) => {
badges.filter(`[data-commit-sha="${signature.commit_sha}"]`).replaceWith(signature.html);
});
- });
+ })
+ .catch(() => flash(__('An error occurred while loading commits')));
}
}
diff --git a/app/assets/javascripts/importer_status.js b/app/assets/javascripts/importer_status.js
index 1dc70872d92..134a503864e 100644
--- a/app/assets/javascripts/importer_status.js
+++ b/app/assets/javascripts/importer_status.js
@@ -1,3 +1,7 @@
+import { __ } from './locale';
+import axios from './lib/utils/axios_utils';
+import flash from './flash';
+
class ImporterStatus {
constructor(jobsUrl, importUrl) {
this.jobsUrl = jobsUrl;
@@ -9,29 +13,7 @@ class ImporterStatus {
initStatusPage() {
$('.js-add-to-import')
.off('click')
- .on('click', (event) => {
- const $btn = $(event.currentTarget);
- const $tr = $btn.closest('tr');
- const $targetField = $tr.find('.import-target');
- const $namespaceInput = $targetField.find('.js-select-namespace option:selected');
- const id = $tr.attr('id').replace('repo_', '');
- let targetNamespace;
- let newName;
- if ($namespaceInput.length > 0) {
- targetNamespace = $namespaceInput[0].innerHTML;
- newName = $targetField.find('#path').prop('value');
- $targetField.empty().append(`${targetNamespace}/${newName}`);
- }
- $btn.disable().addClass('is-loading');
-
- return $.post(this.importUrl, {
- repo_id: id,
- target_namespace: targetNamespace,
- new_name: newName,
- }, {
- dataType: 'script',
- });
- });
+ .on('click', this.addToImport.bind(this));
$('.js-import-all')
.off('click')
@@ -44,6 +26,39 @@ class ImporterStatus {
});
}
+ addToImport(event) {
+ const $btn = $(event.currentTarget);
+ const $tr = $btn.closest('tr');
+ const $targetField = $tr.find('.import-target');
+ const $namespaceInput = $targetField.find('.js-select-namespace option:selected');
+ const id = $tr.attr('id').replace('repo_', '');
+ let targetNamespace;
+ let newName;
+ if ($namespaceInput.length > 0) {
+ targetNamespace = $namespaceInput[0].innerHTML;
+ newName = $targetField.find('#path').prop('value');
+ $targetField.empty().append(`${targetNamespace}/${newName}`);
+ }
+ $btn.disable().addClass('is-loading');
+
+ return axios.post(this.importUrl, {
+ repo_id: id,
+ target_namespace: targetNamespace,
+ new_name: newName,
+ })
+ .then(({ data }) => {
+ const job = $(`tr#repo_${id}`);
+ job.attr('id', `project_${data.id}`);
+
+ job.find('.import-target').html(`<a href="${data.full_path}">${data.full_path}</a>`);
+ $('table.import-jobs tbody').prepend(job);
+
+ job.addClass('active');
+ job.find('.import-actions').html('<i class="fa fa-spinner fa-spin" aria-label="importing"></i> started');
+ })
+ .catch(() => flash(__('An error occurred while importing project')));
+ }
+
setAutoUpdate() {
return setInterval(() => $.get(this.jobsUrl, data => $.each(data, (i, job) => {
const jobItem = $(`#project_${job.id}`);
@@ -71,7 +86,7 @@ class ImporterStatus {
}
// eslint-disable-next-line consistent-return
-export default function initImporterStatus() {
+function initImporterStatus() {
const importerStatus = document.querySelector('.js-importer-status');
if (importerStatus) {
@@ -79,3 +94,8 @@ export default function initImporterStatus() {
return new ImporterStatus(data.jobsImportPath, data.importPath);
}
}
+
+export {
+ initImporterStatus as default,
+ ImporterStatus,
+};
diff --git a/app/assets/javascripts/issue.js b/app/assets/javascripts/issue.js
index ff65ea99e9a..e3d90a24185 100644
--- a/app/assets/javascripts/issue.js
+++ b/app/assets/javascripts/issue.js
@@ -1,5 +1,4 @@
/* eslint-disable func-names, space-before-function-paren, no-var, prefer-rest-params, wrap-iife, one-var, no-underscore-dangle, one-var-declaration-per-line, object-shorthand, no-unused-vars, no-new, comma-dangle, consistent-return, quotes, dot-notation, quote-props, prefer-arrow-callback, max-len */
-import 'vendor/jquery.waitforimages';
import axios from './lib/utils/axios_utils';
import { addDelimiter } from './lib/utils/text_utility';
import flash from './flash';
diff --git a/app/assets/javascripts/merge_request.js b/app/assets/javascripts/merge_request.js
index bedd50de1bb..a64093afcf4 100644
--- a/app/assets/javascripts/merge_request.js
+++ b/app/assets/javascripts/merge_request.js
@@ -1,6 +1,4 @@
/* eslint-disable func-names, space-before-function-paren, no-var, prefer-rest-params, wrap-iife, quotes, no-underscore-dangle, one-var, one-var-declaration-per-line, consistent-return, dot-notation, quote-props, comma-dangle, object-shorthand, max-len, prefer-arrow-callback */
-
-import 'vendor/jquery.waitforimages';
import { __ } from '~/locale';
import TaskList from './task_list';
import MergeRequestTabs from './merge_request_tabs';
diff --git a/app/assets/javascripts/pages/ci/lints/ci_lint_editor.js b/app/assets/javascripts/pages/ci/lints/ci_lint_editor.js
index b9469e5b7cb..9ab73be80a0 100644
--- a/app/assets/javascripts/pages/ci/lints/ci_lint_editor.js
+++ b/app/assets/javascripts/pages/ci/lints/ci_lint_editor.js
@@ -2,11 +2,18 @@ export default class CILintEditor {
constructor() {
this.editor = window.ace.edit('ci-editor');
this.textarea = document.querySelector('#content');
+ this.clearYml = document.querySelector('.clear-yml');
this.editor.getSession().setMode('ace/mode/yaml');
this.editor.on('input', () => {
const content = this.editor.getSession().getValue();
this.textarea.value = content;
});
+
+ this.clearYml.addEventListener('click', this.clear.bind(this));
+ }
+
+ clear() {
+ this.editor.setValue('');
}
}
diff --git a/app/assets/javascripts/pages/projects/merge_requests/show/index.js b/app/assets/javascripts/pages/projects/merge_requests/show/index.js
new file mode 100644
index 00000000000..c3463c266e3
--- /dev/null
+++ b/app/assets/javascripts/pages/projects/merge_requests/show/index.js
@@ -0,0 +1,24 @@
+import MergeRequest from '~/merge_request';
+import ZenMode from '~/zen_mode';
+import initNotes from '~/init_notes';
+import initIssuableSidebar from '~/init_issuable_sidebar';
+import ShortcutsIssuable from '~/shortcuts_issuable';
+import Diff from '~/diff';
+import { handleLocationHash } from '~/lib/utils/common_utils';
+
+export default () => {
+ new Diff(); // eslint-disable-line no-new
+ new ZenMode(); // eslint-disable-line no-new
+
+ initIssuableSidebar(); // eslint-disable-line no-new
+ initNotes(); // eslint-disable-line no-new
+
+ const mrShowNode = document.querySelector('.merge-request');
+
+ window.mergeRequest = new MergeRequest({
+ action: mrShowNode.dataset.mrAction,
+ });
+
+ new ShortcutsIssuable(true); // eslint-disable-line no-new
+ handleLocationHash();
+};
diff --git a/app/assets/javascripts/render_mermaid.js b/app/assets/javascripts/render_mermaid.js
index 31c7a772cf4..d4f18955bd2 100644
--- a/app/assets/javascripts/render_mermaid.js
+++ b/app/assets/javascripts/render_mermaid.js
@@ -30,6 +30,9 @@ export default function renderMermaid($els) {
$els.each((i, el) => {
const source = el.textContent;
+ // Remove any extra spans added by the backend syntax highlighting.
+ Object.assign(el, { textContent: source });
+
mermaid.init(undefined, el, (id) => {
const svg = document.getElementById(id);
diff --git a/app/assets/javascripts/sidebar/components/time_tracking/sidebar_time_tracking.js b/app/assets/javascripts/sidebar/components/time_tracking/sidebar_time_tracking.js
index d32fe4abc7d..782e4ba4fad 100644
--- a/app/assets/javascripts/sidebar/components/time_tracking/sidebar_time_tracking.js
+++ b/app/assets/javascripts/sidebar/components/time_tracking/sidebar_time_tracking.js
@@ -2,7 +2,7 @@ import _ from 'underscore';
import '~/smart_interval';
-import timeTracker from './time_tracker';
+import IssuableTimeTracker from './time_tracker.vue';
import Store from '../../stores/sidebar_store';
import Mediator from '../../sidebar_mediator';
@@ -16,7 +16,7 @@ export default {
};
},
components: {
- 'issuable-time-tracker': timeTracker,
+ IssuableTimeTracker,
},
methods: {
listenForQuickActions() {
diff --git a/app/assets/javascripts/sidebar/components/time_tracking/time_tracker.js b/app/assets/javascripts/sidebar/components/time_tracking/time_tracker.vue
index 866178e2b23..230736a56b8 100644
--- a/app/assets/javascripts/sidebar/components/time_tracking/time_tracker.js
+++ b/app/assets/javascripts/sidebar/components/time_tracking/time_tracker.vue
@@ -1,3 +1,4 @@
+<script>
import timeTrackingHelpState from './help_state';
import timeTrackingCollapsedState from './collapsed_state';
import timeTrackingSpentOnlyPane from './spent_only_pane';
@@ -8,7 +9,15 @@ import timeTrackingComparisonPane from './comparison_pane';
import eventHub from '../../event_hub';
export default {
- name: 'issuable-time-tracker',
+ name: 'IssuableTimeTracker',
+ components: {
+ 'time-tracking-collapsed-state': timeTrackingCollapsedState,
+ 'time-tracking-estimate-only-pane': timeTrackingEstimateOnlyPane,
+ 'time-tracking-spent-only-pane': timeTrackingSpentOnlyPane,
+ 'time-tracking-no-tracking-pane': timeTrackingNoTrackingPane,
+ 'time-tracking-comparison-pane': timeTrackingComparisonPane,
+ 'time-tracking-help-state': timeTrackingHelpState,
+ },
props: {
time_estimate: {
type: Number,
@@ -38,14 +47,6 @@ export default {
showHelp: false,
};
},
- components: {
- 'time-tracking-collapsed-state': timeTrackingCollapsedState,
- 'time-tracking-estimate-only-pane': timeTrackingEstimateOnlyPane,
- 'time-tracking-spent-only-pane': timeTrackingSpentOnlyPane,
- 'time-tracking-no-tracking-pane': timeTrackingNoTrackingPane,
- 'time-tracking-comparison-pane': timeTrackingComparisonPane,
- 'time-tracking-help-state': timeTrackingHelpState,
- },
computed: {
timeSpent() {
return this.time_spent;
@@ -81,6 +82,9 @@ export default {
return !!this.showHelp;
},
},
+ created() {
+ eventHub.$on('timeTracker:updateData', this.update);
+ },
methods: {
toggleHelpState(show) {
this.showHelp = show;
@@ -92,72 +96,73 @@ export default {
this.human_time_spent = data.human_time_spent;
},
},
- created() {
- eventHub.$on('timeTracker:updateData', this.update);
- },
- template: `
- <div
- class="time_tracker time-tracking-component-wrap"
- v-cloak
- >
- <time-tracking-collapsed-state
- :show-comparison-state="showComparisonState"
- :show-no-time-tracking-state="showNoTimeTrackingState"
- :show-help-state="showHelpState"
- :show-spent-only-state="showSpentOnlyState"
- :show-estimate-only-state="showEstimateOnlyState"
+};
+</script>
+
+<template>
+ <div
+ class="time_tracker time-tracking-component-wrap"
+ v-cloak
+ >
+ <time-tracking-collapsed-state
+ :show-comparison-state="showComparisonState"
+ :show-no-time-tracking-state="showNoTimeTrackingState"
+ :show-help-state="showHelpState"
+ :show-spent-only-state="showSpentOnlyState"
+ :show-estimate-only-state="showEstimateOnlyState"
+ :time-spent-human-readable="timeSpentHumanReadable"
+ :time-estimate-human-readable="timeEstimateHumanReadable"
+ />
+ <div class="title hide-collapsed">
+ {{ __('Time tracking') }}
+ <div
+ class="help-button pull-right"
+ v-if="!showHelpState"
+ @click="toggleHelpState(true)"
+ >
+ <i
+ class="fa fa-question-circle"
+ aria-hidden="true"
+ >
+ </i>
+ </div>
+ <div
+ class="close-help-button pull-right"
+ v-if="showHelpState"
+ @click="toggleHelpState(false)"
+ >
+ <i
+ class="fa fa-close"
+ aria-hidden="true"
+ >
+ </i>
+ </div>
+ </div>
+ <div class="time-tracking-content hide-collapsed">
+ <time-tracking-estimate-only-pane
+ v-if="showEstimateOnlyState"
+ :time-estimate-human-readable="timeEstimateHumanReadable"
+ />
+ <time-tracking-spent-only-pane
+ v-if="showSpentOnlyState"
+ :time-spent-human-readable="timeSpentHumanReadable"
+ />
+ <time-tracking-no-tracking-pane
+ v-if="showNoTimeTrackingState"
+ />
+ <time-tracking-comparison-pane
+ v-if="showComparisonState"
+ :time-estimate="timeEstimate"
+ :time-spent="timeSpent"
:time-spent-human-readable="timeSpentHumanReadable"
:time-estimate-human-readable="timeEstimateHumanReadable"
/>
- <div class="title hide-collapsed">
- {{ __('Time tracking') }}
- <div
- class="help-button pull-right"
- v-if="!showHelpState"
- @click="toggleHelpState(true)"
- >
- <i
- class="fa fa-question-circle"
- aria-hidden="true"
- />
- </div>
- <div
- class="close-help-button pull-right"
+ <transition name="help-state-toggle">
+ <time-tracking-help-state
v-if="showHelpState"
- @click="toggleHelpState(false)"
- >
- <i
- class="fa fa-close"
- aria-hidden="true"
- />
- </div>
- </div>
- <div class="time-tracking-content hide-collapsed">
- <time-tracking-estimate-only-pane
- v-if="showEstimateOnlyState"
- :time-estimate-human-readable="timeEstimateHumanReadable"
+ :root-path="rootPath"
/>
- <time-tracking-spent-only-pane
- v-if="showSpentOnlyState"
- :time-spent-human-readable="timeSpentHumanReadable"
- />
- <time-tracking-no-tracking-pane
- v-if="showNoTimeTrackingState"
- />
- <time-tracking-comparison-pane
- v-if="showComparisonState"
- :time-estimate="timeEstimate"
- :time-spent="timeSpent"
- :time-spent-human-readable="timeSpentHumanReadable"
- :time-estimate-human-readable="timeEstimateHumanReadable"
- />
- <transition name="help-state-toggle">
- <time-tracking-help-state
- v-if="showHelpState"
- :rootPath="rootPath"
- />
- </transition>
- </div>
+ </transition>
</div>
- `,
-};
+ </div>
+</template>
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_missing_branch.js b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_missing_branch.js
deleted file mode 100644
index 7733fb74afe..00000000000
--- a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_missing_branch.js
+++ /dev/null
@@ -1,43 +0,0 @@
-import statusIcon from '../mr_widget_status_icon.vue';
-import tooltip from '../../../vue_shared/directives/tooltip';
-import mrWidgetMergeHelp from '../../components/mr_widget_merge_help.vue';
-
-export default {
- name: 'MRWidgetMissingBranch',
- props: {
- mr: { type: Object, required: true },
- },
- directives: {
- tooltip,
- },
- components: {
- 'mr-widget-merge-help': mrWidgetMergeHelp,
- statusIcon,
- },
- computed: {
- missingBranchName() {
- return this.mr.sourceBranchRemoved ? 'source' : 'target';
- },
- message() {
- return `If the ${this.missingBranchName} branch exists in your local repository, you can merge this merge request manually using the command line`;
- },
- },
- template: `
- <div class="mr-widget-body media">
- <status-icon status="warning" :show-disabled-button="true" />
- <div class="media-body space-children">
- <span class="bold js-branch-text">
- <span class="capitalize">
- {{missingBranchName}}
- </span> branch does not exist.
- Please restore it or use a different {{missingBranchName}} branch
- <i
- v-tooltip
- class="fa fa-question-circle"
- :title="message"
- :aria-label="message"></i>
- </span>
- </div>
- </div>
- `,
-};
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_missing_branch.vue b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_missing_branch.vue
new file mode 100644
index 00000000000..718c0e4b3c6
--- /dev/null
+++ b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_missing_branch.vue
@@ -0,0 +1,62 @@
+<script>
+ import { sprintf, s__ } from '~/locale';
+ import tooltip from '~/vue_shared/directives/tooltip';
+ import statusIcon from '../mr_widget_status_icon.vue';
+ import mrWidgetMergeHelp from '../../components/mr_widget_merge_help.vue';
+
+ export default {
+ name: 'MRWidgetMissingBranch',
+ directives: {
+ tooltip,
+ },
+ components: {
+ mrWidgetMergeHelp,
+ statusIcon,
+ },
+ props: {
+ mr: {
+ type: Object,
+ required: true,
+ },
+ },
+ computed: {
+ missingBranchName() {
+ return this.mr.sourceBranchRemoved ? 'source' : 'target';
+ },
+ missingBranchNameMessage() {
+ return sprintf(s__('mrWidget| Please restore it or use a different %{missingBranchName} branch'), {
+ missingBranchName: this.missingBranchName,
+ });
+ },
+ message() {
+ return sprintf(s__('mrWidget|If the %{missingBranchName} branch exists in your local repository, you can merge this merge request manually using the command line'), {
+ missingBranchName: this.missingBranchName,
+ });
+ },
+ },
+ };
+</script>
+<template>
+ <div class="mr-widget-body media">
+ <status-icon
+ status="warning"
+ :show-disabled-button="true"
+ />
+
+ <div class="media-body space-children">
+ <span class="bold js-branch-text">
+ <span class="capitalize">
+ {{ missingBranchName }}
+ </span> {{ s__("mrWidget|branch does not exist.") }}
+ {{ missingBranchNameMessage }}
+ <i
+ v-tooltip
+ class="fa fa-question-circle"
+ :title="message"
+ :aria-label="message"
+ >
+ </i>
+ </span>
+ </div>
+ </div>
+</template>
diff --git a/app/assets/javascripts/vue_merge_request_widget/dependencies.js b/app/assets/javascripts/vue_merge_request_widget/dependencies.js
index 7ca15537719..5517888c3b1 100644
--- a/app/assets/javascripts/vue_merge_request_widget/dependencies.js
+++ b/app/assets/javascripts/vue_merge_request_widget/dependencies.js
@@ -24,7 +24,7 @@ export { default as WipState } from './components/states/mr_widget_wip';
export { default as ArchivedState } from './components/states/mr_widget_archived.vue';
export { default as ConflictsState } from './components/states/mr_widget_conflicts.vue';
export { default as NothingToMergeState } from './components/states/mr_widget_nothing_to_merge';
-export { default as MissingBranchState } from './components/states/mr_widget_missing_branch';
+export { default as MissingBranchState } from './components/states/mr_widget_missing_branch.vue';
export { default as NotAllowedState } from './components/states/mr_widget_not_allowed';
export { default as ReadyToMergeState } from './components/states/mr_widget_ready_to_merge';
export { default as SHAMismatchState } from './components/states/mr_widget_sha_mismatch';
diff --git a/app/assets/javascripts/vue_shared/components/confirmation_input.vue b/app/assets/javascripts/vue_shared/components/confirmation_input.vue
deleted file mode 100644
index 1aa03ea6317..00000000000
--- a/app/assets/javascripts/vue_shared/components/confirmation_input.vue
+++ /dev/null
@@ -1,62 +0,0 @@
-<script>
- import _ from 'underscore';
- import { __, sprintf } from '~/locale';
-
- export default {
- props: {
- inputId: {
- type: String,
- required: true,
- },
- confirmationKey: {
- type: String,
- required: true,
- },
- confirmationValue: {
- type: String,
- required: true,
- },
- shouldEscapeConfirmationValue: {
- type: Boolean,
- required: false,
- default: true,
- },
- },
- computed: {
- inputLabel() {
- let value = this.confirmationValue;
- if (this.shouldEscapeConfirmationValue) {
- value = _.escape(value);
- }
-
- return sprintf(
- __('Type %{value} to confirm:'),
- { value: `<code>${value}</code>` },
- false,
- );
- },
- },
- methods: {
- hasCorrectValue() {
- return this.$refs.enteredValue.value === this.confirmationValue;
- },
- },
- };
-</script>
-
-<template>
- <div>
- <label
- v-html="inputLabel"
- :for="inputId"
- >
- </label>
- <input
- :id="inputId"
- :name="confirmationKey"
- type="text"
- ref="enteredValue"
- class="form-control"
- />
- </div>
-</template>
diff --git a/app/assets/stylesheets/framework.scss b/app/assets/stylesheets/framework.scss
index 887879ab715..2fccfa4011c 100644
--- a/app/assets/stylesheets/framework.scss
+++ b/app/assets/stylesheets/framework.scss
@@ -21,7 +21,7 @@
@import "framework/flash";
@import "framework/forms";
@import "framework/gfm";
-@import "framework/gitlab-theme";
+@import "framework/gitlab_theme";
@import "framework/header";
@import "framework/highlight";
@import "framework/issue_box";
@@ -35,10 +35,10 @@
@import "framework/pagination";
@import "framework/panels";
@import "framework/popup";
-@import "framework/secondary-navigation-elements";
+@import "framework/secondary_navigation_elements";
@import "framework/selects";
@import "framework/sidebar";
-@import "framework/contextual-sidebar";
+@import "framework/contextual_sidebar";
@import "framework/tables";
@import "framework/notes";
@import "framework/tabs";
@@ -49,16 +49,16 @@
@import "framework/zen";
@import "framework/blank";
@import "framework/wells";
-@import "framework/page-header";
+@import "framework/page_header";
@import "framework/awards";
@import "framework/images";
-@import "framework/broadcast-messages";
+@import "framework/broadcast_messages";
@import "framework/emojis";
-@import "framework/emoji-sprites";
+@import "framework/emoji_sprites";
@import "framework/icons";
@import "framework/snippets";
@import "framework/memory_graph";
@import "framework/responsive_tables";
-@import "framework/stacked-progress-bar";
+@import "framework/stacked_progress_bar";
@import "framework/ci_variable_list";
@import "framework/feature_highlight";
diff --git a/app/assets/stylesheets/framework/broadcast-messages.scss b/app/assets/stylesheets/framework/broadcast_messages.scss
index 9b54fb94cdc..9b54fb94cdc 100644
--- a/app/assets/stylesheets/framework/broadcast-messages.scss
+++ b/app/assets/stylesheets/framework/broadcast_messages.scss
diff --git a/app/assets/stylesheets/framework/contextual-sidebar.scss b/app/assets/stylesheets/framework/contextual_sidebar.scss
index 1acde98c3ae..1acde98c3ae 100644
--- a/app/assets/stylesheets/framework/contextual-sidebar.scss
+++ b/app/assets/stylesheets/framework/contextual_sidebar.scss
diff --git a/app/assets/stylesheets/framework/emoji-sprites.scss b/app/assets/stylesheets/framework/emoji_sprites.scss
index 0174e17b660..0174e17b660 100644
--- a/app/assets/stylesheets/framework/emoji-sprites.scss
+++ b/app/assets/stylesheets/framework/emoji_sprites.scss
diff --git a/app/assets/stylesheets/framework/gitlab-theme.scss b/app/assets/stylesheets/framework/gitlab_theme.scss
index db36e27fa74..db36e27fa74 100644
--- a/app/assets/stylesheets/framework/gitlab-theme.scss
+++ b/app/assets/stylesheets/framework/gitlab_theme.scss
diff --git a/app/assets/stylesheets/framework/page-header.scss b/app/assets/stylesheets/framework/page_header.scss
index 0c879f40930..0c879f40930 100644
--- a/app/assets/stylesheets/framework/page-header.scss
+++ b/app/assets/stylesheets/framework/page_header.scss
diff --git a/app/assets/stylesheets/framework/secondary-navigation-elements.scss b/app/assets/stylesheets/framework/secondary_navigation_elements.scss
index 17c31d6b184..17c31d6b184 100644
--- a/app/assets/stylesheets/framework/secondary-navigation-elements.scss
+++ b/app/assets/stylesheets/framework/secondary_navigation_elements.scss
diff --git a/app/assets/stylesheets/framework/stacked-progress-bar.scss b/app/assets/stylesheets/framework/stacked_progress_bar.scss
index 4869cda73e5..4869cda73e5 100644
--- a/app/assets/stylesheets/framework/stacked-progress-bar.scss
+++ b/app/assets/stylesheets/framework/stacked_progress_bar.scss
diff --git a/app/assets/stylesheets/pages/environments.scss b/app/assets/stylesheets/pages/environments.scss
index 4eba05a492d..884665d35c7 100644
--- a/app/assets/stylesheets/pages/environments.scss
+++ b/app/assets/stylesheets/pages/environments.scss
@@ -121,6 +121,10 @@
width: 100%;
text-align: left;
}
+
+ .environment-child-row {
+ padding-left: 20px;
+ }
}
}
diff --git a/app/controllers/import/base_controller.rb b/app/controllers/import/base_controller.rb
index 9de0297ecfd..c84fc2d305d 100644
--- a/app/controllers/import/base_controller.rb
+++ b/app/controllers/import/base_controller.rb
@@ -2,26 +2,16 @@ class Import::BaseController < ApplicationController
private
def find_or_create_namespace(names, owner)
- return current_user.namespace if names == owner
- return current_user.namespace unless current_user.can_create_group?
-
names = params[:target_namespace].presence || names
- full_path_namespace = Namespace.find_by_full_path(names)
- return full_path_namespace if full_path_namespace
+ return current_user.namespace if names == owner
+
+ group = Groups::NestedCreateService.new(current_user, group_path: names).execute
- names.split('/').inject(nil) do |parent, name|
- begin
- namespace = Group.create!(name: name,
- path: name,
- owner: current_user,
- parent: parent)
- namespace.add_owner(current_user)
+ group.errors.any? ? current_user.namespace : group
+ rescue => e
+ Gitlab::AppLogger.error(e)
- namespace
- rescue ActiveRecord::RecordNotUnique, ActiveRecord::RecordInvalid
- Namespace.where(parent: parent).find_by_path_or_name(name)
- end
- end
+ current_user.namespace
end
end
diff --git a/app/controllers/import/bitbucket_controller.rb b/app/controllers/import/bitbucket_controller.rb
index 5ad1e116e4e..13ea736688d 100644
--- a/app/controllers/import/bitbucket_controller.rb
+++ b/app/controllers/import/bitbucket_controller.rb
@@ -37,24 +37,30 @@ class Import::BitbucketController < Import::BaseController
def create
bitbucket_client = Bitbucket::Client.new(credentials)
- @repo_id = params[:repo_id].to_s
- name = @repo_id.gsub('___', '/')
+ repo_id = params[:repo_id].to_s
+ name = repo_id.gsub('___', '/')
repo = bitbucket_client.repo(name)
- @project_name = params[:new_name].presence || repo.name
+ project_name = params[:new_name].presence || repo.name
repo_owner = repo.owner
repo_owner = current_user.username if repo_owner == bitbucket_client.user.username
namespace_path = params[:new_namespace].presence || repo_owner
+ target_namespace = find_or_create_namespace(namespace_path, current_user)
- @target_namespace = find_or_create_namespace(namespace_path, current_user)
-
- if current_user.can?(:create_projects, @target_namespace)
+ if current_user.can?(:create_projects, target_namespace)
# The token in a session can be expired, we need to get most recent one because
# Bitbucket::Connection class refreshes it.
session[:bitbucket_token] = bitbucket_client.connection.token
- @project = Gitlab::BitbucketImport::ProjectCreator.new(repo, @project_name, @target_namespace, current_user, credentials).execute
+
+ project = Gitlab::BitbucketImport::ProjectCreator.new(repo, project_name, target_namespace, current_user, credentials).execute
+
+ if project.persisted?
+ render json: ProjectSerializer.new.represent(project)
+ else
+ render json: { errors: project.errors.full_messages }, status: :unprocessable_entity
+ end
else
- render 'unauthorized'
+ render json: { errors: 'This namespace has already been taken! Please choose another one.' }, status: :unprocessable_entity
end
end
diff --git a/app/controllers/import/fogbugz_controller.rb b/app/controllers/import/fogbugz_controller.rb
index 5df6bd34185..669eb31a995 100644
--- a/app/controllers/import/fogbugz_controller.rb
+++ b/app/controllers/import/fogbugz_controller.rb
@@ -58,17 +58,17 @@ class Import::FogbugzController < Import::BaseController
end
def create
- @repo_id = params[:repo_id]
- repo = client.repo(@repo_id)
+ repo = client.repo(params[:repo_id])
fb_session = { uri: session[:fogbugz_uri], token: session[:fogbugz_token] }
- @target_namespace = current_user.namespace
- @project_name = repo.name
-
- namespace = @target_namespace
-
umap = session[:fogbugz_user_map] || client.user_map
- @project = Gitlab::FogbugzImport::ProjectCreator.new(repo, fb_session, namespace, current_user, umap).execute
+ project = Gitlab::FogbugzImport::ProjectCreator.new(repo, fb_session, current_user.namespace, current_user, umap).execute
+
+ if project.persisted?
+ render json: ProjectSerializer.new.represent(project)
+ else
+ render json: { errors: project.errors.full_messages }, status: :unprocessable_entity
+ end
end
private
diff --git a/app/controllers/import/github_controller.rb b/app/controllers/import/github_controller.rb
index b8ba7921613..69fb8121ded 100644
--- a/app/controllers/import/github_controller.rb
+++ b/app/controllers/import/github_controller.rb
@@ -36,16 +36,21 @@ class Import::GithubController < Import::BaseController
end
def create
- @repo_id = params[:repo_id].to_i
- repo = client.repo(@repo_id)
- @project_name = params[:new_name].presence || repo.name
+ repo = client.repo(params[:repo_id].to_i)
+ project_name = params[:new_name].presence || repo.name
namespace_path = params[:target_namespace].presence || current_user.namespace_path
- @target_namespace = find_or_create_namespace(namespace_path, current_user.namespace_path)
+ target_namespace = find_or_create_namespace(namespace_path, current_user.namespace_path)
- if can?(current_user, :create_projects, @target_namespace)
- @project = Gitlab::LegacyGithubImport::ProjectCreator.new(repo, @project_name, @target_namespace, current_user, access_params, type: provider).execute
+ if can?(current_user, :create_projects, target_namespace)
+ project = Gitlab::LegacyGithubImport::ProjectCreator.new(repo, project_name, target_namespace, current_user, access_params, type: provider).execute
+
+ if project.persisted?
+ render json: ProjectSerializer.new.represent(project)
+ else
+ render json: { errors: project.errors.full_messages }, status: :unprocessable_entity
+ end
else
- render 'unauthorized'
+ render json: { errors: 'This namespace has already been taken! Please choose another one.' }, status: :unprocessable_entity
end
end
diff --git a/app/controllers/import/gitlab_controller.rb b/app/controllers/import/gitlab_controller.rb
index 407154e59a0..18f1d20f5a9 100644
--- a/app/controllers/import/gitlab_controller.rb
+++ b/app/controllers/import/gitlab_controller.rb
@@ -24,15 +24,19 @@ class Import::GitlabController < Import::BaseController
end
def create
- @repo_id = params[:repo_id].to_i
- repo = client.project(@repo_id)
- @project_name = repo['name']
- @target_namespace = find_or_create_namespace(repo['namespace']['path'], client.user['username'])
+ repo = client.project(params[:repo_id].to_i)
+ target_namespace = find_or_create_namespace(repo['namespace']['path'], client.user['username'])
- if current_user.can?(:create_projects, @target_namespace)
- @project = Gitlab::GitlabImport::ProjectCreator.new(repo, @target_namespace, current_user, access_params).execute
+ if current_user.can?(:create_projects, target_namespace)
+ project = Gitlab::GitlabImport::ProjectCreator.new(repo, target_namespace, current_user, access_params).execute
+
+ if project.persisted?
+ render json: ProjectSerializer.new.represent(project)
+ else
+ render json: { errors: project.errors.full_messages }, status: :unprocessable_entity
+ end
else
- render 'unauthorized'
+ render json: { errors: 'This namespace has already been taken! Please choose another one.' }, status: :unprocessable_entity
end
end
diff --git a/app/controllers/import/google_code_controller.rb b/app/controllers/import/google_code_controller.rb
index 7d7f13ce5d5..baa19fb383d 100644
--- a/app/controllers/import/google_code_controller.rb
+++ b/app/controllers/import/google_code_controller.rb
@@ -85,16 +85,16 @@ class Import::GoogleCodeController < Import::BaseController
end
def create
- @repo_id = params[:repo_id]
- repo = client.repo(@repo_id)
- @target_namespace = current_user.namespace
- @project_name = repo.name
-
- namespace = @target_namespace
-
+ repo = client.repo(params[:repo_id])
user_map = session[:google_code_user_map]
- @project = Gitlab::GoogleCodeImport::ProjectCreator.new(repo, namespace, current_user, user_map).execute
+ project = Gitlab::GoogleCodeImport::ProjectCreator.new(repo, current_user.namespace, current_user, user_map).execute
+
+ if project.persisted?
+ render json: ProjectSerializer.new.represent(project)
+ else
+ render json: { errors: project.errors.full_messages }, status: :unprocessable_entity
+ end
end
private
diff --git a/app/controllers/root_controller.rb b/app/controllers/root_controller.rb
index 8acefd58e77..63e5fdb1da5 100644
--- a/app/controllers/root_controller.rb
+++ b/app/controllers/root_controller.rb
@@ -13,10 +13,7 @@ class RootController < Dashboard::ProjectsController
before_action :redirect_logged_user, if: -> { current_user.present? }
def index
- # n+1: https://gitlab.com/gitlab-org/gitlab-ce/issues/37434
- Gitlab::GitalyClient.allow_n_plus_1_calls do
- super
- end
+ super
end
private
diff --git a/app/finders/snippets_finder.rb b/app/finders/snippets_finder.rb
index 4450766485f..33359fa1efb 100644
--- a/app/finders/snippets_finder.rb
+++ b/app/finders/snippets_finder.rb
@@ -1,14 +1,28 @@
+# Snippets Finder
+#
+# Used to filter Snippets collections by a set of params
+#
+# Arguments.
+#
+# current_user - The current user, nil also can be used.
+# params:
+# visibility (integer) - Individual snippet visibility: Public(20), internal(10) or private(0).
+# project (Project) - Project related.
+# author (User) - Author related.
+#
+# params are optional
class SnippetsFinder < UnionFinder
- attr_accessor :current_user, :params
+ include Gitlab::Allowable
+ attr_accessor :current_user, :params, :project
def initialize(current_user, params = {})
@current_user = current_user
@params = params
+ @project = params[:project]
end
def execute
items = init_collection
- items = by_project(items)
items = by_author(items)
items = by_visibility(items)
@@ -18,25 +32,42 @@ class SnippetsFinder < UnionFinder
private
def init_collection
- items = Snippet.all
+ if project.present?
+ authorized_snippets_from_project
+ else
+ authorized_snippets
+ end
+ end
- accessible(items)
+ def authorized_snippets_from_project
+ if can?(current_user, :read_project_snippet, project)
+ if project.team.member?(current_user)
+ project.snippets
+ else
+ project.snippets.public_to_user(current_user)
+ end
+ else
+ Snippet.none
+ end
end
- def accessible(items)
- segments = []
- segments << items.public_to_user(current_user)
- segments << authorized_to_user(items) if current_user
+ def authorized_snippets
+ Snippet.where(feature_available_projects.or(not_project_related)).public_or_visible_to_user(current_user)
+ end
- find_union(segments, Snippet.includes(:author))
+ def feature_available_projects
+ projects = Project.public_or_visible_to_user(current_user)
+ .with_feature_available_for_user(:snippets, current_user).select(:id)
+ arel_query = Arel::Nodes::SqlLiteral.new(projects.to_sql)
+ table[:project_id].in(arel_query)
end
- def authorized_to_user(items)
- items.where(
- 'author_id = :author_id
- OR project_id IN (:project_ids)',
- author_id: current_user.id,
- project_ids: current_user.authorized_projects.select(:id))
+ def not_project_related
+ table[:project_id].eq(nil)
+ end
+
+ def table
+ Snippet.arel_table
end
def by_visibility(items)
@@ -53,12 +84,6 @@ class SnippetsFinder < UnionFinder
items.where(author_id: params[:author].id)
end
- def by_project(items)
- return items unless params[:project]
-
- items.where(project_id: params[:project].id)
- end
-
def visibility_from_scope
case params[:scope].to_s
when 'are_private'
diff --git a/app/models/ci/build.rb b/app/models/ci/build.rb
index 20534b8eed0..ee987949080 100644
--- a/app/models/ci/build.rb
+++ b/app/models/ci/build.rb
@@ -543,6 +543,7 @@ module Ci
variables = [
{ key: 'CI', value: 'true', public: true },
{ key: 'GITLAB_CI', value: 'true', public: true },
+ { key: 'GITLAB_FEATURES', value: project.namespace.features.join(','), public: true },
{ key: 'CI_SERVER_NAME', value: 'GitLab', public: true },
{ key: 'CI_SERVER_VERSION', value: Gitlab::VERSION, public: true },
{ key: 'CI_SERVER_REVISION', value: Gitlab::REVISION, public: true },
diff --git a/app/models/merge_request.rb b/app/models/merge_request.rb
index d025062f562..5bec68ce4f6 100644
--- a/app/models/merge_request.rb
+++ b/app/models/merge_request.rb
@@ -158,10 +158,12 @@ class MergeRequest < ActiveRecord::Base
end
def rebase_in_progress?
- # The source project can be deleted
- return false unless source_project
+ strong_memoize(:rebase_in_progress) do
+ # The source project can be deleted
+ next false unless source_project
- source_project.repository.rebase_in_progress?(id)
+ source_project.repository.rebase_in_progress?(id)
+ end
end
# Use this method whenever you need to make sure the head_pipeline is synced with the
diff --git a/app/models/namespace.rb b/app/models/namespace.rb
index d95489ee9f2..db274ea8172 100644
--- a/app/models/namespace.rb
+++ b/app/models/namespace.rb
@@ -243,6 +243,10 @@ class Namespace < ActiveRecord::Base
all_projects.with_storage_feature(:repository).find_each(&:remove_exports)
end
+ def features
+ []
+ end
+
private
def path_or_parent_changed?
diff --git a/app/models/project.rb b/app/models/project.rb
index 0590cc1c720..3893b1818f3 100644
--- a/app/models/project.rb
+++ b/app/models/project.rb
@@ -1589,8 +1589,11 @@ class Project < ActiveRecord::Base
end
def protected_for?(ref)
- ProtectedBranch.protected?(self, ref) ||
+ if repository.branch_exists?(ref)
+ ProtectedBranch.protected?(self, ref)
+ elsif repository.tag_exists?(ref)
ProtectedTag.protected?(self, ref)
+ end
end
def deployment_variables
diff --git a/app/models/snippet.rb b/app/models/snippet.rb
index 7c8716f8c18..a58c208279e 100644
--- a/app/models/snippet.rb
+++ b/app/models/snippet.rb
@@ -74,6 +74,27 @@ class Snippet < ActiveRecord::Base
@link_reference_pattern ||= super("snippets", /(?<snippet>\d+)/)
end
+ # Returns a collection of snippets that are either public or visible to the
+ # logged in user.
+ #
+ # This method does not verify the user actually has the access to the project
+ # the snippet is in, so it should be only used on a relation that's already scoped
+ # for project access
+ def self.public_or_visible_to_user(user = nil)
+ if user
+ authorized = user
+ .project_authorizations
+ .select(1)
+ .where('project_authorizations.project_id = snippets.project_id')
+
+ levels = Gitlab::VisibilityLevel.levels_for_user(user)
+
+ where('EXISTS (?) OR snippets.visibility_level IN (?) or snippets.author_id = (?)', authorized, levels, user.id)
+ else
+ public_to_user
+ end
+ end
+
def to_reference(from = nil, full: false)
reference = "#{self.class.reference_prefix}#{id}"
diff --git a/app/models/user.rb b/app/models/user.rb
index 05c93d3cb17..4097fe2b5dc 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -551,7 +551,7 @@ class User < ActiveRecord::Base
gpg_keys.each(&:update_invalid_gpg_signatures)
end
- # Returns the groups a user has access to
+ # Returns the groups a user has access to, either through a membership or a project authorization
def authorized_groups
union = Gitlab::SQL::Union
.new([groups.select(:id), authorized_projects.select(:namespace_id)])
@@ -559,6 +559,11 @@ class User < ActiveRecord::Base
Group.where("namespaces.id IN (#{union.to_sql})") # rubocop:disable GitlabSecurity/SqlInjection
end
+ # Returns the groups a user is a member of, either directly or through a parent group
+ def membership_groups
+ Gitlab::GroupHierarchy.new(groups).base_and_descendants
+ end
+
# Returns a relation of groups the user has access to, including their parent
# and child groups (recursively).
def all_expanded_groups
diff --git a/app/policies/project_policy.rb b/app/policies/project_policy.rb
index 1dd8f0a25a9..61a7bf02675 100644
--- a/app/policies/project_policy.rb
+++ b/app/policies/project_policy.rb
@@ -119,7 +119,6 @@ class ProjectPolicy < BasePolicy
enable :create_note
enable :upload_file
enable :read_cycle_analytics
- enable :read_project_snippet
end
rule { can?(:reporter_access) }.policy do
diff --git a/app/serializers/project_serializer.rb b/app/serializers/project_serializer.rb
new file mode 100644
index 00000000000..74de1e79a8f
--- /dev/null
+++ b/app/serializers/project_serializer.rb
@@ -0,0 +1,3 @@
+class ProjectSerializer < BaseSerializer
+ entity ProjectEntity
+end
diff --git a/app/services/groups/nested_create_service.rb b/app/services/groups/nested_create_service.rb
index d6f08fc3cce..5c337a9faa5 100644
--- a/app/services/groups/nested_create_service.rb
+++ b/app/services/groups/nested_create_service.rb
@@ -11,8 +11,8 @@ module Groups
def execute
return nil unless group_path
- if group = Group.find_by_full_path(group_path)
- return group
+ if namespace = namespace_or_group(group_path)
+ return namespace
end
if group_path.include?('/') && !Group.supports_nested_groups?
@@ -40,10 +40,14 @@ module Groups
)
new_params[:visibility_level] ||= Gitlab::CurrentSettings.current_application_settings.default_group_visibility
- last_group = Group.find_by_full_path(partial_path) || Groups::CreateService.new(current_user, new_params).execute
+ last_group = namespace_or_group(partial_path) || Groups::CreateService.new(current_user, new_params).execute
end
last_group
end
+
+ def namespace_or_group(group_path)
+ Namespace.find_by_full_path(group_path)
+ end
end
end
diff --git a/app/views/ci/lints/show.html.haml b/app/views/ci/lints/show.html.haml
index e6408f35201..3c0881caa06 100644
--- a/app/views/ci/lints/show.html.haml
+++ b/app/views/ci/lints/show.html.haml
@@ -18,6 +18,8 @@
.col-sm-12
.pull-left.prepend-top-10
= submit_tag('Validate', class: 'btn btn-success submit-yml')
+ .pull-right.prepend-top-10
+ = button_tag('Clear', type: 'button', class: 'btn btn-default clear-yml')
.row.prepend-top-20
.col-sm-12
diff --git a/app/views/ci/variables/_variable_row.html.haml b/app/views/ci/variables/_variable_row.html.haml
index 495a55660cb..15201780451 100644
--- a/app/views/ci/variables/_variable_row.html.haml
+++ b/app/views/ci/variables/_variable_row.html.haml
@@ -5,7 +5,7 @@
- id = variable&.id
- key = variable&.key
- value = variable&.value
-- is_protected = variable && !only_key_value ? variable.protected : true
+- is_protected = variable && !only_key_value ? variable.protected : false
- id_input_name = "#{form_field}[variables_attributes][][id]"
- destroy_input_name = "#{form_field}[variables_attributes][][_destroy]"
diff --git a/app/views/import/base/create.js.haml b/app/views/import/base/create.js.haml
deleted file mode 100644
index 4dc3a4a0acf..00000000000
--- a/app/views/import/base/create.js.haml
+++ /dev/null
@@ -1,13 +0,0 @@
-- if @project.persisted?
- :plain
- job = $("tr#repo_#{@repo_id}")
- job.attr("id", "project_#{@project.id}")
- target_field = job.find(".import-target")
- target_field.empty()
- target_field.append('#{link_to @project.full_path, project_path(@project)}')
- $("table.import-jobs tbody").prepend(job)
- job.addClass("active").find(".import-actions").html("<i class='fa fa-spinner fa-spin'></i> started")
-- else
- :plain
- job = $("tr#repo_#{@repo_id}")
- job.find(".import-actions").html("<i class='fa fa-exclamation-circle'></i> Error saving project: #{escape_javascript(h(@project.errors.full_messages.join(',')))}")
diff --git a/app/views/import/base/unauthorized.js.haml b/app/views/import/base/unauthorized.js.haml
deleted file mode 100644
index ada5f99f4e2..00000000000
--- a/app/views/import/base/unauthorized.js.haml
+++ /dev/null
@@ -1,14 +0,0 @@
-:plain
- tr = $("tr#repo_#{@repo_id}")
- target_field = tr.find(".import-target")
- import_button = tr.find(".btn-import")
- origin_target = target_field.text()
- project_name = "#{@project_name}"
- origin_namespace = "#{@target_namespace.full_path}"
- target_field.empty()
- target_field.append("<p class='alert alert-danger'>This namespace has already been taken! Please choose another one.</p>")
- target_field.append("<input type='text' name='target_namespace' />")
- target_field.append("/" + project_name)
- target_field.data("project_name", project_name)
- target_field.find('input').prop("value", origin_namespace)
- import_button.enable().removeClass('is-loading')
diff --git a/app/views/projects/graphs/charts.html.haml b/app/views/projects/graphs/charts.html.haml
index ffb9238a65a..300a39fe257 100644
--- a/app/views/projects/graphs/charts.html.haml
+++ b/app/views/projects/graphs/charts.html.haml
@@ -7,7 +7,7 @@
.repo-charts{ class: container_class }
%h4.sub-header
- Programming languages used in this repository
+ = _("Programming languages used in this repository")
.row
.col-md-4
@@ -30,9 +30,11 @@
.row.tree-ref-header
.col-md-6
%h4
- Commit statistics for
- %strong= @ref
- #{@commits_graph.start_date.strftime('%b %d')} - #{@commits_graph.end_date.strftime('%b %d')}
+ - start_time = capture do
+ #{@commits_graph.start_date.strftime('%b %d')}
+ - end_time = capture do
+ #{@commits_graph.end_date.strftime('%b %d')}
+ = (_("Commit statistics for %{ref} %{start_time} - %{end_time}") % { ref: "<strong>#{@ref}</strong>", start_time: start_time, end_time: end_time }).html_safe
.col-md-6
.tree-ref-container
@@ -45,32 +47,35 @@
.col-md-6
%ul.commit-stats
%li
- Total:
- %strong #{@commits_graph.commits.size} commits
+ - total = capture do
+ #{@commits_graph.commits.size}
+ = (_("Total: %{total}") % { total: "<strong>#{total} commits</strong>" }).html_safe
%li
- Average per day:
- %strong #{@commits_graph.commit_per_day} commits
+ - average = capture do
+ #{@commits_graph.commit_per_day}
+ = (_("Average per day: %{average}") % { average: "<strong>#{average} commits</strong>" }).html_safe
%li
- Authors:
- %strong= @commits_graph.authors
+ - authors = capture do
+ #{@commits_graph.authors}
+ = (_("Authors: %{authors}") % { authors: "<strong>#{authors}</strong>" }).html_safe
.col-md-6
%div
%p.slead
- Commits per day of month
+ = _("Commits per day of month")
%canvas#month-chart
.row
.col-md-6
.col-md-6
%div
%p.slead
- Commits per weekday
+ = _("Commits per weekday")
%canvas#weekday-chart
.row
.col-md-6
.col-md-6
%div
%p.slead
- Commits per day hour (UTC)
+ = _("Commits per day hour (UTC)")
%canvas#hour-chart
%script#projectChartData{ type: "application/json" }
diff --git a/changelogs/unreleased/40994-expose-features-as-ci-cd-variable.yml b/changelogs/unreleased/40994-expose-features-as-ci-cd-variable.yml
new file mode 100644
index 00000000000..1e377094791
--- /dev/null
+++ b/changelogs/unreleased/40994-expose-features-as-ci-cd-variable.yml
@@ -0,0 +1,5 @@
+---
+title: 'Expose GITLAB_FEATURES as CI/CD variable (fixes #40994)'
+merge_request:
+author:
+type: added
diff --git a/changelogs/unreleased/42922-environment-name.yml b/changelogs/unreleased/42922-environment-name.yml
new file mode 100644
index 00000000000..0e9544245f6
--- /dev/null
+++ b/changelogs/unreleased/42922-environment-name.yml
@@ -0,0 +1,5 @@
+---
+title: Adds tooltip in environment names to increase readability
+merge_request:
+author:
+type: fixed
diff --git a/changelogs/unreleased/bvl-fix-concurrent-fork-network-migrations.yml b/changelogs/unreleased/bvl-fix-concurrent-fork-network-migrations.yml
new file mode 100644
index 00000000000..b2a77f75e55
--- /dev/null
+++ b/changelogs/unreleased/bvl-fix-concurrent-fork-network-migrations.yml
@@ -0,0 +1,5 @@
+---
+title: Avoid running `PopulateForkNetworksRange`-migration multiple times
+merge_request: 16988
+author:
+type: fixed
diff --git a/changelogs/unreleased/docs-update-vue-naming-guidelines.yml b/changelogs/unreleased/docs-update-vue-naming-guidelines.yml
new file mode 100644
index 00000000000..95bfd212370
--- /dev/null
+++ b/changelogs/unreleased/docs-update-vue-naming-guidelines.yml
@@ -0,0 +1,5 @@
+---
+title: Update vue component naming guidelines
+merge_request: 17018
+author: George Tsiolis
+type: other
diff --git a/changelogs/unreleased/feature-26598-clear-button-ci-lint.yml b/changelogs/unreleased/feature-26598-clear-button-ci-lint.yml
new file mode 100644
index 00000000000..fcf237f20f0
--- /dev/null
+++ b/changelogs/unreleased/feature-26598-clear-button-ci-lint.yml
@@ -0,0 +1,4 @@
+---
+title: Added clear button to ci lint editor
+merge_request:
+author: Michael Robinson
diff --git a/changelogs/unreleased/feature-oidc-groups-claim.yml b/changelogs/unreleased/feature-oidc-groups-claim.yml
new file mode 100644
index 00000000000..bde19130114
--- /dev/null
+++ b/changelogs/unreleased/feature-oidc-groups-claim.yml
@@ -0,0 +1,4 @@
+---
+title: Add groups to OpenID Connect claims
+merge_request: 16929
+author: Hassan Zamani
diff --git a/changelogs/unreleased/internationalize-charts-page.yml b/changelogs/unreleased/internationalize-charts-page.yml
new file mode 100644
index 00000000000..481b83fb059
--- /dev/null
+++ b/changelogs/unreleased/internationalize-charts-page.yml
@@ -0,0 +1,5 @@
+---
+title: Internationalize charts page
+merge_request: 16687
+author: selrahman
+type: changed
diff --git a/changelogs/unreleased/refactor-move-issuable-time-tracker-vue-component.yml b/changelogs/unreleased/refactor-move-issuable-time-tracker-vue-component.yml
new file mode 100644
index 00000000000..5ed06c61817
--- /dev/null
+++ b/changelogs/unreleased/refactor-move-issuable-time-tracker-vue-component.yml
@@ -0,0 +1,5 @@
+---
+title: Move IssuableTimeTracker vue component
+merge_request: 16948
+author: George Tsiolis
+type: performance
diff --git a/config/application.rb b/config/application.rb
index 751307de975..9eb6cf4b824 100644
--- a/config/application.rb
+++ b/config/application.rb
@@ -11,6 +11,7 @@ module Gitlab
require_dependency Rails.root.join('lib/gitlab/redis/queues')
require_dependency Rails.root.join('lib/gitlab/redis/shared_state')
require_dependency Rails.root.join('lib/gitlab/request_context')
+ require_dependency Rails.root.join('lib/gitlab/current_settings')
# Settings in config/environments/* take precedence over those specified here.
# Application configuration should go into files in config/initializers
diff --git a/config/initializers/doorkeeper_openid_connect.rb b/config/initializers/doorkeeper_openid_connect.rb
index af174def047..98e1f6e830f 100644
--- a/config/initializers/doorkeeper_openid_connect.rb
+++ b/config/initializers/doorkeeper_openid_connect.rb
@@ -31,6 +31,7 @@ Doorkeeper::OpenidConnect.configure do
o.claim(:website) { |user| user.full_website_url if user.website_url? }
o.claim(:profile) { |user| Gitlab::Routing.url_helpers.user_url user }
o.claim(:picture) { |user| user.avatar_url(only_path: false) }
+ o.claim(:groups) { |user| user.membership_groups.map(&:full_path) }
end
end
end
diff --git a/config/locales/doorkeeper.en.yml b/config/locales/doorkeeper.en.yml
index b1c71095d4f..889111282ef 100644
--- a/config/locales/doorkeeper.en.yml
+++ b/config/locales/doorkeeper.en.yml
@@ -68,7 +68,7 @@ en:
read_user:
Read-only access to the user's profile information, like username, public email and full name
openid:
- The ability to authenticate using GitLab, and read-only access to the user's profile information
+ The ability to authenticate using GitLab, and read-only access to the user's profile information and group memberships
sudo:
Access to the Sudo feature, to perform API actions as any user in the system (only available for admins)
flash:
diff --git a/db/migrate/20170929131201_populate_fork_networks.rb b/db/migrate/20170929131201_populate_fork_networks.rb
index 1214962770f..ddbf27e1852 100644
--- a/db/migrate/20170929131201_populate_fork_networks.rb
+++ b/db/migrate/20170929131201_populate_fork_networks.rb
@@ -6,22 +6,8 @@ class PopulateForkNetworks < ActiveRecord::Migration
DOWNTIME = false
- MIGRATION = 'PopulateForkNetworksRange'.freeze
- BATCH_SIZE = 100
- DELAY_INTERVAL = 15.seconds
-
- disable_ddl_transaction!
-
- class ForkedProjectLink < ActiveRecord::Base
- include EachBatch
-
- self.table_name = 'forked_project_links'
- end
-
def up
- say 'Populating the `fork_networks` based on existing `forked_project_links`'
-
- queue_background_migration_jobs_by_range_at_intervals(ForkedProjectLink, MIGRATION, DELAY_INTERVAL, batch_size: BATCH_SIZE)
+ say 'Fork networks will be populated in 20171205190711 - RescheduleForkNetworkCreationCaller'
end
def down
diff --git a/db/post_migrate/20171124150326_reschedule_fork_network_creation.rb b/db/post_migrate/20171124150326_reschedule_fork_network_creation.rb
index 05430efe1f6..26f917d5a1e 100644
--- a/db/post_migrate/20171124150326_reschedule_fork_network_creation.rb
+++ b/db/post_migrate/20171124150326_reschedule_fork_network_creation.rb
@@ -3,22 +3,8 @@ class RescheduleForkNetworkCreation < ActiveRecord::Migration
DOWNTIME = false
- MIGRATION = 'PopulateForkNetworksRange'.freeze
- BATCH_SIZE = 100
- DELAY_INTERVAL = 15.seconds
-
- disable_ddl_transaction!
-
- class ForkedProjectLink < ActiveRecord::Base
- include EachBatch
-
- self.table_name = 'forked_project_links'
- end
-
def up
- say 'Populating the `fork_networks` based on existing `forked_project_links`'
-
- queue_background_migration_jobs_by_range_at_intervals(ForkedProjectLink, MIGRATION, DELAY_INTERVAL, batch_size: BATCH_SIZE)
+ say 'Fork networks will be populated in 20171205190711 - RescheduleForkNetworkCreationCaller'
end
def down
diff --git a/doc/administration/high_availability/gitlab.md b/doc/administration/high_availability/gitlab.md
index b85a166089d..e201848791c 100644
--- a/doc/administration/high_availability/gitlab.md
+++ b/doc/administration/high_availability/gitlab.md
@@ -25,11 +25,11 @@ for each GitLab application server in your environment.
options. Here is an example snippet to add to `/etc/fstab`:
```
- 10.1.0.1:/var/opt/gitlab/.ssh /var/opt/gitlab/.ssh nfs defaults,soft,rsize=1048576,wsize=1048576,noatime,nobootwait,lookupcache=positive 0 2
- 10.1.0.1:/var/opt/gitlab/gitlab-rails/uploads /var/opt/gitlab/gitlab-rails/uploads nfs defaults,soft,rsize=1048576,wsize=1048576,noatime,nobootwait,lookupcache=positive 0 2
- 10.1.0.1:/var/opt/gitlab/gitlab-rails/shared /var/opt/gitlab/gitlab-rails/shared nfs defaults,soft,rsize=1048576,wsize=1048576,noatime,nobootwait,lookupcache=positive 0 2
- 10.1.0.1:/var/opt/gitlab/gitlab-ci/builds /var/opt/gitlab/gitlab-ci/builds nfs defaults,soft,rsize=1048576,wsize=1048576,noatime,nobootwait,lookupcache=positive 0 2
- 10.1.1.1:/var/opt/gitlab/git-data /var/opt/gitlab/git-data nfs defaults,soft,rsize=1048576,wsize=1048576,noatime,nobootwait,lookupcache=positive 0 2
+ 10.1.0.1:/var/opt/gitlab/.ssh /var/opt/gitlab/.ssh nfs defaults,soft,rsize=1048576,wsize=1048576,noatime,nofail,lookupcache=positive 0 2
+ 10.1.0.1:/var/opt/gitlab/gitlab-rails/uploads /var/opt/gitlab/gitlab-rails/uploads nfs defaults,soft,rsize=1048576,wsize=1048576,noatime,nofail,lookupcache=positive 0 2
+ 10.1.0.1:/var/opt/gitlab/gitlab-rails/shared /var/opt/gitlab/gitlab-rails/shared nfs defaults,soft,rsize=1048576,wsize=1048576,noatime,nofail,lookupcache=positive 0 2
+ 10.1.0.1:/var/opt/gitlab/gitlab-ci/builds /var/opt/gitlab/gitlab-ci/builds nfs defaults,soft,rsize=1048576,wsize=1048576,noatime,nofail,lookupcache=positive 0 2
+ 10.1.0.1:/var/opt/gitlab/git-data /var/opt/gitlab/git-data nfs defaults,soft,rsize=1048576,wsize=1048576,noatime,nofail,lookupcache=positive 0 2
```
1. Create the shared directories. These may be different depending on your NFS
diff --git a/doc/administration/repository_storage_types.md b/doc/administration/repository_storage_types.md
index c5b286f6804..39bd19ac851 100644
--- a/doc/administration/repository_storage_types.md
+++ b/doc/administration/repository_storage_types.md
@@ -4,50 +4,63 @@
## Legacy Storage
-Legacy Storage is the storage behavior prior to version 10.0. For historical reasons, GitLab replicated the same
-mapping structure from the projects URLs:
+Legacy Storage is the storage behavior prior to version 10.0. For historical
+reasons, GitLab replicated the same mapping structure from the projects URLs:
- * Project's repository: `#{namespace}/#{project_name}.git`
- * Project's wiki: `#{namespace}/#{project_name}.wiki.git`
+* Project's repository: `#{namespace}/#{project_name}.git`
+* Project's wiki: `#{namespace}/#{project_name}.wiki.git`
-This structure made simple to migrate from existing solutions to GitLab and easy for Administrators to find where the
-repository is stored.
+This structure made it simple to migrate from existing solutions to GitLab and
+easy for Administrators to find where the repository is stored.
On the other hand this has some drawbacks:
-Storage location will concentrate huge amount of top-level namespaces. The impact can be reduced by the introduction of [multiple storage paths][storage-paths].
+Storage location will concentrate huge amount of top-level namespaces. The
+impact can be reduced by the introduction of [multiple storage
+paths][storage-paths].
-Because Backups are a snapshot of the same URL mapping, if you try to recover a very old backup, you need to verify
-if any project has taken the place of an old removed project sharing the same URL. This means that `mygroup/myproject`
-from your backup may not be the same original project that is today in the same URL.
+Because backups are a snapshot of the same URL mapping, if you try to recover a
+very old backup, you need to verify whether any project has taken the place of
+an old removed or renamed project sharing the same URL. This means that
+`mygroup/myproject` from your backup may not be the same original project that
+is at that same URL today.
-Any change in the URL will need to be reflected on disk (when groups / users or projects are renamed). This can add a lot
-of load in big installations, and can be even worst if they are using any type of network based filesystem.
+Any change in the URL will need to be reflected on disk (when groups / users or
+projects are renamed). This can add a lot of load in big installations,
+especially if using any type of network based filesystem.
-Last, for GitLab Geo, this storage type means we have to synchronize the disk state, replicate renames in the correct
-order or we may end-up with wrong repository or missing data temporarily.
+For GitLab Geo in particular: Geo does work with legacy storage, but in some
+edge cases due to race conditions it can lead to errors when a project is
+renamed multiple times in short succession, or a project is deleted and
+recreated under the same name very quickly. We expect these race events to be
+rare, and we have not observed a race condition side-effect happening yet.
-This pattern also exists in other objects stored in GitLab, like issue Attachments, GitLab Pages artifacts,
-Docker Containers for the integrated Registry, etc.
+This pattern also exists in other objects stored in GitLab, like issue
+Attachments, GitLab Pages artifacts, Docker Containers for the integrated
+Registry, etc.
## Hashed Storage
-Hashed Storage is the new storage behavior we are rolling out with 10.0. It's not enabled by default yet, but we
-encourage everyone to try-it and take the time to fix any script you may have that depends on the old behavior.
+> **Warning:** Hashed storage is in **Beta**. For the latest updates, check the
+> associated [issue](https://gitlab.com/gitlab-com/infrastructure/issues/2821)
+> and please report any problems you encounter.
-Instead of coupling project URL and the folder structure where the repository will be stored on disk, we are coupling
-a hash, based on the project's ID.
+Hashed Storage is the new storage behavior we are rolling out with 10.0. Instead
+of coupling project URL and the folder structure where the repository will be
+stored on disk, we are coupling a hash, based on the project's ID. This makes
+the folder structure immutable, and therefore eliminates any requirement to
+synchronize state from URLs to disk structure. This means that renaming a group,
+user, or project will cost only the database transaction, and will take effect
+immediately.
-This makes the folder structure immutable, and therefore eliminates any requirement to synchronize state from URLs to
-disk structure. This means that renaming a group, user or project will cost only the database transaction, and will take
-effect immediately.
+The hash also helps to spread the repositories more evenly on the disk, so the
+top-level directory will contain less folders than the total amount of top-level
+namespaces.
-The hash also helps to spread the repositories more evenly on the disk, so the top-level directory will contain less
-folders than the total amount of top-level namespaces.
-
-Hash format is based on hexadecimal representation of SHA256: `SHA256(project.id)`.
-Top-level folder uses first 2 characters, followed by another folder with the next 2 characters. They are both stored in
-a special folder `@hashed`, to co-exist with existing Legacy projects:
+The hash format is based on the hexadecimal representation of SHA256:
+`SHA256(project.id)`. The top-level folder uses the first 2 characters, followed
+by another folder with the next 2 characters. They are both stored in a special
+`@hashed` folder, to be able to co-exist with existing Legacy Storage projects:
```ruby
# Project's repository:
@@ -57,15 +70,13 @@ a special folder `@hashed`, to co-exist with existing Legacy projects:
"@hashed/#{hash[0..1]}/#{hash[2..3]}/#{hash}.wiki.git"
```
-This new format also makes possible to restore backups with confidence, as when restoring a repository from the backup,
-you will never mistakenly restore a repository in the wrong project (considering the backup is made after the migration).
-
### How to migrate to Hashed Storage
-In GitLab, go to **Admin > Settings**, find the **Repository Storage** section and select
-"_Create new projects using hashed storage paths_".
+In GitLab, go to **Admin > Settings**, find the **Repository Storage** section
+and select "_Create new projects using hashed storage paths_".
-To migrate your existing projects to the new storage type, check the specific [rake tasks].
+To migrate your existing projects to the new storage type, check the specific
+[rake tasks].
[ce-28283]: https://gitlab.com/gitlab-org/gitlab-ce/issues/28283
[rake tasks]: raketasks/storage.md#migrate-existing-projects-to-hashed-storage
@@ -73,11 +84,13 @@ To migrate your existing projects to the new storage type, check the specific [r
### Hashed Storage coverage
-We are incrementally moving every storable object in GitLab to the Hashed Storage pattern. You can check the current
-coverage status below.
+We are incrementally moving every storable object in GitLab to the Hashed
+Storage pattern. You can check the current coverage status below (and also see
+the [issue](https://gitlab.com/gitlab-com/infrastructure/issues/2821)).
-Note that things stored in an S3 compatible endpoint will not have the downsides mentioned earlier, if they are not
-prefixed with `#{namespace}/#{project_name}`, which is true for CI Cache and LFS Objects.
+Note that things stored in an S3 compatible endpoint will not have the downsides
+mentioned earlier, if they are not prefixed with `#{namespace}/#{project_name}`,
+which is true for CI Cache and LFS Objects.
| Storable Object | Legacy Storage | Hashed Storage | S3 Compatible | GitLab Version |
| --------------- | -------------- | -------------- | ------------- | -------------- |
diff --git a/doc/development/background_migrations.md b/doc/development/background_migrations.md
index af2026c483e..fc1b202b5eb 100644
--- a/doc/development/background_migrations.md
+++ b/doc/development/background_migrations.md
@@ -94,6 +94,18 @@ jobs = [['BackgroundMigrationClassName', [1]],
BackgroundMigrationWorker.bulk_perform_in(5.minutes, jobs)
```
+### Rescheduling background migrations
+
+If one of the background migrations contains a bug that is fixed in a patch
+release, the background migration needs to be rescheduled so the migration would
+be repeated on systems that already performed the initial migration.
+
+When you reschedule the background migration, make sure to turn the original
+scheduling into a no-op by clearing up the `#up` and `#down` methods of the
+migration performing the scheduling. Otherwise the background migration would be
+scheduled multiple times on systems that are upgrading multiple patch releases at
+once.
+
## Cleaning Up
>**Note:**
diff --git a/doc/development/fe_guide/style_guide_js.md b/doc/development/fe_guide/style_guide_js.md
index 02773162801..917d28b48ee 100644
--- a/doc/development/fe_guide/style_guide_js.md
+++ b/doc/development/fe_guide/style_guide_js.md
@@ -207,10 +207,39 @@ Do not use them anymore and feel free to remove them when refactoring legacy cod
var c = pureFunction(values.foo);
```
-1. Avoid constructors with side-effects
+1. Avoid constructors with side-effects.
+Although we aim for code without side-effects we need some side-effects for our code to run.
+
+If the class won't do anything if we only instantiate it, it's ok to add side effects into the constructor (_Note:_ The following is just an example. If the only purpose of the class is to add an event listener and handle the callback a function will be more suitable.)
+
+```javascript
+// Bad
+export class Foo {
+ constructor() {
+ this.init();
+ }
+ init() {
+ document.addEventListener('click', this.handleCallback)
+ },
+ handleCallback() {
+
+ }
+}
+
+// Good
+export class Foo {
+ constructor() {
+ document.addEventListener()
+ }
+ handleCallback() {
+ }
+}
+```
+
+On the other hand, if a class only needs to extend a third party/add event listeners in some specific cases, they should be initialized oustside of the constructor.
1. Prefer `.map`, `.reduce` or `.filter` over `.forEach`
-A forEach will cause side effects, it will be mutating the array being iterated. Prefer using `.map`,
+A forEach will most likely cause side effects, it will be mutating the array being iterated. Prefer using `.map`,
`.reduce` or `.filter`
```javascript
const users = [ { name: 'Foo' }, { name: 'Bar' } ];
@@ -302,20 +331,20 @@ Please check this [rules][eslint-plugin-vue-rules] for more documentation.
#### Naming
1. **Extensions**: Use `.vue` extension for Vue components.
-1. **Reference Naming**: Use camelCase for their instances:
+1. **Reference Naming**: Use PascalCase for their instances:
```javascript
// bad
- import CardBoard from 'cardBoard'
+ import cardBoard from 'cardBoard.vue'
components: {
- CardBoard:
+ cardBoard,
};
// good
- import cardBoard from 'cardBoard'
+ import CardBoard from 'cardBoard.vue'
components: {
- cardBoard:
+ CardBoard,
};
```
diff --git a/doc/development/fe_guide/style_guide_scss.md b/doc/development/fe_guide/style_guide_scss.md
index 86a8b4135af..655d94793dd 100644
--- a/doc/development/fe_guide/style_guide_scss.md
+++ b/doc/development/fe_guide/style_guide_scss.md
@@ -7,6 +7,8 @@ easy to maintain, and performant for the end-user.
### Naming
+Filenames should use `snake_case`.
+
CSS classes should use the `lowercase-hyphenated` format rather than
`snake_case` or `camelCase`.
diff --git a/doc/development/i18n/externalization.md b/doc/development/i18n/externalization.md
index f4542932295..c0a325a83e9 100644
--- a/doc/development/i18n/externalization.md
+++ b/doc/development/i18n/externalization.md
@@ -126,6 +126,9 @@ strings and remove any strings that aren't used anymore. You should check this
file in. Once the changes are on master, they will be picked up by
[Crowdin](http://translate.gitlab.com) and be presented for translation.
+If there are merge conflicts in the `gitlab.pot` file, you can delete the file
+and regenerate it using the same command. Confirm that you are not deleting any strings accidentally by looking over the diff.
+
The command also updates the translation files for each language: `locale/*/gitlab.po`
These changes can be discarded, the languange files will be updated by Crowdin
automatically.
diff --git a/doc/install/installation.md b/doc/install/installation.md
index 6eb8890cc4f..4dfc03d0fe0 100644
--- a/doc/install/installation.md
+++ b/doc/install/installation.md
@@ -299,9 +299,9 @@ sudo usermod -aG redis git
### Clone the Source
# Clone GitLab repository
- sudo -u git -H git clone https://gitlab.com/gitlab-org/gitlab-ce.git -b 10-4-stable gitlab
+ sudo -u git -H git clone https://gitlab.com/gitlab-org/gitlab-ce.git -b 10-5-stable gitlab
-**Note:** You can change `10-4-stable` to `master` if you want the *bleeding edge* version, but never install master on a production server!
+**Note:** You can change `10-5-stable` to `master` if you want the *bleeding edge* version, but never install master on a production server!
### Configure It
diff --git a/doc/integration/openid_connect_provider.md b/doc/integration/openid_connect_provider.md
index 56f367d841e..ad41be52045 100644
--- a/doc/integration/openid_connect_provider.md
+++ b/doc/integration/openid_connect_provider.md
@@ -39,6 +39,7 @@ Currently the following user information is shared with clients:
| `website` | `string` | URL for the user's website
| `profile` | `string` | URL for the user's GitLab profile
| `picture` | `string` | URL for the user's GitLab avatar
+| `groups` | `array` | Names of the groups the user is a member of
[OpenID Connect]: http://openid.net/connect/ "OpenID Connect website"
[doorkeeper-openid_connect]: https://github.com/doorkeeper-gem/doorkeeper-openid_connect "Doorkeeper::OpenidConnect website"
diff --git a/doc/update/10.4-to-10.5.md b/doc/update/10.4-to-10.5.md
new file mode 100644
index 00000000000..313419ed13d
--- /dev/null
+++ b/doc/update/10.4-to-10.5.md
@@ -0,0 +1,361 @@
+---
+comments: false
+---
+
+# From 10.4 to 10.5
+
+Make sure you view this update guide from the tag (version) of GitLab you would
+like to install. In most cases this should be the highest numbered production
+tag (without rc in it). You can select the tag in the version dropdown at the
+top left corner of GitLab (below the menu bar).
+
+If the highest number stable branch is unclear please check the
+[GitLab Blog](https://about.gitlab.com/blog/archives.html) for installation
+guide links by version.
+
+### 1. Stop server
+
+```bash
+sudo service gitlab stop
+```
+
+### 2. Backup
+
+NOTE: If you installed GitLab from source, make sure `rsync` is installed.
+
+```bash
+cd /home/git/gitlab
+
+sudo -u git -H bundle exec rake gitlab:backup:create RAILS_ENV=production
+```
+
+### 3. Update Ruby
+
+NOTE: GitLab 9.0 and higher only support Ruby 2.3.x and dropped support for Ruby 2.1.x. Be
+sure to upgrade your interpreter if necessary.
+
+You can check which version you are running with `ruby -v`.
+
+Download and compile Ruby:
+
+```bash
+mkdir /tmp/ruby && cd /tmp/ruby
+curl --remote-name --progress https://cache.ruby-lang.org/pub/ruby/2.3/ruby-2.3.6.tar.gz
+echo '4e6a0f828819e15d274ae58485585fc8b7caace0 ruby-2.3.6.tar.gz' | shasum -c - && tar xzf ruby-2.3.6.tar.gz
+cd ruby-2.3.6
+./configure --disable-install-rdoc
+make
+sudo make install
+```
+
+Install Bundler:
+
+```bash
+sudo gem install bundler --no-ri --no-rdoc
+```
+
+### 4. Update Node
+
+GitLab now runs [webpack](http://webpack.js.org) to compile frontend assets.
+We require a minimum version of node v6.0.0.
+
+You can check which version you are running with `node -v`. If you are running
+a version older than `v6.0.0` you will need to update to a newer version. You
+can find instructions to install from community maintained packages or compile
+from source at the nodejs.org website.
+
+<https://nodejs.org/en/download/>
+
+Since 8.17, GitLab requires the use of yarn `>= v0.17.0` to manage
+JavaScript dependencies.
+
+```bash
+curl --silent --show-error https://dl.yarnpkg.com/debian/pubkey.gpg | sudo apt-key add -
+echo "deb https://dl.yarnpkg.com/debian/ stable main" | sudo tee /etc/apt/sources.list.d/yarn.list
+sudo apt-get update
+sudo apt-get install yarn
+```
+
+More information can be found on the [yarn website](https://yarnpkg.com/en/docs/install).
+
+### 5. Update Go
+
+NOTE: GitLab 9.2 and higher only supports Go 1.8.3 and dropped support for Go
+1.5.x through 1.7.x. Be sure to upgrade your installation if necessary.
+
+You can check which version you are running with `go version`.
+
+Download and install Go:
+
+```bash
+# Remove former Go installation folder
+sudo rm -rf /usr/local/go
+
+curl --remote-name --progress https://storage.googleapis.com/golang/go1.8.3.linux-amd64.tar.gz
+echo '1862f4c3d3907e59b04a757cfda0ea7aa9ef39274af99a784f5be843c80c6772 go1.8.3.linux-amd64.tar.gz' | shasum -a256 -c - && \
+ sudo tar -C /usr/local -xzf go1.8.3.linux-amd64.tar.gz
+sudo ln -sf /usr/local/go/bin/{go,godoc,gofmt} /usr/local/bin/
+rm go1.8.3.linux-amd64.tar.gz
+```
+
+### 6. Get latest code
+
+```bash
+cd /home/git/gitlab
+
+sudo -u git -H git fetch --all
+sudo -u git -H git checkout -- db/schema.rb # local changes will be restored automatically
+sudo -u git -H git checkout -- locale
+```
+
+For GitLab Community Edition:
+
+```bash
+cd /home/git/gitlab
+
+sudo -u git -H git checkout 10-5-stable
+```
+
+OR
+
+For GitLab Enterprise Edition:
+
+```bash
+cd /home/git/gitlab
+
+sudo -u git -H git checkout 10-5-stable-ee
+```
+
+### 7. Update gitlab-shell
+
+```bash
+cd /home/git/gitlab-shell
+
+sudo -u git -H git fetch --all --tags
+sudo -u git -H git checkout v$(</home/git/gitlab/GITLAB_SHELL_VERSION)
+sudo -u git -H bin/compile
+```
+
+### 8. Update gitlab-workhorse
+
+Install and compile gitlab-workhorse. GitLab-Workhorse uses
+[GNU Make](https://www.gnu.org/software/make/).
+If you are not using Linux you may have to run `gmake` instead of
+`make` below.
+
+```bash
+cd /home/git/gitlab-workhorse
+
+sudo -u git -H git fetch --all --tags
+sudo -u git -H git checkout v$(</home/git/gitlab/GITLAB_WORKHORSE_VERSION)
+sudo -u git -H make
+```
+
+### 9. Update Gitaly
+
+#### New Gitaly configuration options required
+
+In order to function Gitaly needs some additional configuration information. Below we assume you installed Gitaly in `/home/git/gitaly` and GitLab Shell in `/home/git/gitlab-shell`.
+
+```shell
+echo '
+[gitaly-ruby]
+dir = "/home/git/gitaly/ruby"
+
+[gitlab-shell]
+dir = "/home/git/gitlab-shell"
+' | sudo -u git tee -a /home/git/gitaly/config.toml
+```
+
+#### Check Gitaly configuration
+
+Due to a bug in the `rake gitlab:gitaly:install` script your Gitaly
+configuration file may contain syntax errors. The block name
+`[[storages]]`, which may occur more than once in your `config.toml`
+file, should be `[[storage]]` instead.
+
+```shell
+sudo -u git -H sed -i.pre-10.1 's/\[\[storages\]\]/[[storage]]/' /home/git/gitaly/config.toml
+```
+
+#### Compile Gitaly
+
+```shell
+cd /home/git/gitaly
+sudo -u git -H git fetch --all --tags
+sudo -u git -H git checkout v$(</home/git/gitlab/GITALY_SERVER_VERSION)
+sudo -u git -H make
+```
+
+### 10. Update MySQL permissions
+
+If you are using MySQL you need to grant the GitLab user the necessary
+permissions on the database:
+
+```bash
+mysql -u root -p -e "GRANT TRIGGER ON \`gitlabhq_production\`.* TO 'git'@'localhost';"
+```
+
+If you use MySQL with replication, or just have MySQL configured with binary logging,
+you will need to also run the following on all of your MySQL servers:
+
+```bash
+mysql -u root -p -e "SET GLOBAL log_bin_trust_function_creators = 1;"
+```
+
+You can make this setting permanent by adding it to your `my.cnf`:
+
+```
+log_bin_trust_function_creators=1
+```
+
+### 11. Update configuration files
+
+#### New configuration options for `gitlab.yml`
+
+There might be configuration options available for [`gitlab.yml`][yaml]. View them with the command below and apply them manually to your current `gitlab.yml`:
+
+```sh
+cd /home/git/gitlab
+
+git diff origin/10-4-stable:config/gitlab.yml.example origin/10-5-stable:config/gitlab.yml.example
+```
+
+#### Nginx configuration
+
+Ensure you're still up-to-date with the latest NGINX configuration changes:
+
+```sh
+cd /home/git/gitlab
+
+# For HTTPS configurations
+git diff origin/10-4-stable:lib/support/nginx/gitlab-ssl origin/10-5-stable:lib/support/nginx/gitlab-ssl
+
+# For HTTP configurations
+git diff origin/10-4-stable:lib/support/nginx/gitlab origin/10-5-stable:lib/support/nginx/gitlab
+```
+
+If you are using Strict-Transport-Security in your installation to continue using it you must enable it in your Nginx
+configuration as GitLab application no longer handles setting it.
+
+If you are using Apache instead of NGINX please see the updated [Apache templates].
+Also note that because Apache does not support upstreams behind Unix sockets you
+will need to let gitlab-workhorse listen on a TCP port. You can do this
+via [/etc/default/gitlab].
+
+[Apache templates]: https://gitlab.com/gitlab-org/gitlab-recipes/tree/master/web-server/apache
+[/etc/default/gitlab]: https://gitlab.com/gitlab-org/gitlab-ce/blob/10-5-stable/lib/support/init.d/gitlab.default.example#L38
+
+#### SMTP configuration
+
+If you're installing from source and use SMTP to deliver mail, you will need to add the following line
+to config/initializers/smtp_settings.rb:
+
+```ruby
+ActionMailer::Base.delivery_method = :smtp
+```
+
+See [smtp_settings.rb.sample] as an example.
+
+[smtp_settings.rb.sample]: https://gitlab.com/gitlab-org/gitlab-ce/blob/10-5-stable/config/initializers/smtp_settings.rb.sample#L13
+
+#### Init script
+
+There might be new configuration options available for [`gitlab.default.example`][gl-example]. View them with the command below and apply them manually to your current `/etc/default/gitlab`:
+
+```sh
+cd /home/git/gitlab
+
+git diff origin/10-4-stable:lib/support/init.d/gitlab.default.example origin/10-5-stable:lib/support/init.d/gitlab.default.example
+```
+
+Ensure you're still up-to-date with the latest init script changes:
+
+```bash
+cd /home/git/gitlab
+
+sudo cp lib/support/init.d/gitlab /etc/init.d/gitlab
+```
+
+For Ubuntu 16.04.1 LTS:
+
+```bash
+sudo systemctl daemon-reload
+```
+
+### 12. Install libs, migrations, etc.
+
+```bash
+cd /home/git/gitlab
+
+# MySQL installations (note: the line below states '--without postgres')
+sudo -u git -H bundle install --without postgres development test --deployment
+
+# PostgreSQL installations (note: the line below states '--without mysql')
+sudo -u git -H bundle install --without mysql development test --deployment
+
+# Optional: clean up old gems
+sudo -u git -H bundle clean
+
+# Run database migrations
+sudo -u git -H bundle exec rake db:migrate RAILS_ENV=production
+
+# Compile GetText PO files
+
+sudo -u git -H bundle exec rake gettext:compile RAILS_ENV=production
+
+# Update node dependencies and recompile assets
+sudo -u git -H bundle exec rake yarn:install gitlab:assets:clean gitlab:assets:compile RAILS_ENV=production NODE_ENV=production
+
+# Clean up cache
+sudo -u git -H bundle exec rake cache:clear RAILS_ENV=production
+```
+
+**MySQL installations**: Run through the `MySQL strings limits` and `Tables and data conversion to utf8mb4` [tasks](../install/database_mysql.md).
+
+### 13. Start application
+
+```bash
+sudo service gitlab start
+sudo service nginx restart
+```
+
+### 14. Check application status
+
+Check if GitLab and its environment are configured correctly:
+
+```bash
+cd /home/git/gitlab
+
+sudo -u git -H bundle exec rake gitlab:env:info RAILS_ENV=production
+```
+
+To make sure you didn't miss anything run a more thorough check:
+
+```bash
+cd /home/git/gitlab
+
+sudo -u git -H bundle exec rake gitlab:check RAILS_ENV=production
+```
+
+If all items are green, then congratulations, the upgrade is complete!
+
+## Things went south? Revert to previous version (10.4)
+
+### 1. Revert the code to the previous version
+
+Follow the [upgrade guide from 10.3 to 10.4](10.3-to-10.4.md), except for the
+database migration (the backup is already migrated to the previous version).
+
+### 2. Restore from the backup
+
+```bash
+cd /home/git/gitlab
+
+sudo -u git -H bundle exec rake gitlab:backup:restore RAILS_ENV=production
+```
+
+If you have more than one backup `*.tar` file(s) please add `BACKUP=timestamp_of_backup` to the command above.
+
+[yaml]: https://gitlab.com/gitlab-org/gitlab-ce/blob/10-5-stable/config/gitlab.yml.example
+[gl-example]: https://gitlab.com/gitlab-org/gitlab-ce/blob/10-5-stable/lib/support/init.d/gitlab.default.example
diff --git a/doc/user/project/img/label_priority_sort_order.png b/doc/user/project/img/label_priority_sort_order.png
deleted file mode 100644
index 21c7a76a322..00000000000
--- a/doc/user/project/img/label_priority_sort_order.png
+++ /dev/null
Binary files differ
diff --git a/doc/user/project/img/labels_assign_label_sidebar.png b/doc/user/project/img/labels_assign_label_sidebar.png
deleted file mode 100644
index d74796fdb4d..00000000000
--- a/doc/user/project/img/labels_assign_label_sidebar.png
+++ /dev/null
Binary files differ
diff --git a/doc/user/project/img/labels_assign_label_sidebar_saved.png b/doc/user/project/img/labels_assign_label_sidebar_saved.png
deleted file mode 100644
index dabffe956dc..00000000000
--- a/doc/user/project/img/labels_assign_label_sidebar_saved.png
+++ /dev/null
Binary files differ
diff --git a/doc/user/project/img/labels_default.png b/doc/user/project/img/labels_default.png
index 7934e3bfb5e..7a7fab611a4 100644
--- a/doc/user/project/img/labels_default.png
+++ b/doc/user/project/img/labels_default.png
Binary files differ
diff --git a/doc/user/project/img/labels_description_tooltip.png b/doc/user/project/img/labels_description_tooltip.png
deleted file mode 100644
index eea4f8cf0f4..00000000000
--- a/doc/user/project/img/labels_description_tooltip.png
+++ /dev/null
Binary files differ
diff --git a/doc/user/project/img/labels_filter.png b/doc/user/project/img/labels_filter.png
deleted file mode 100644
index 6a1ebfc2ecb..00000000000
--- a/doc/user/project/img/labels_filter.png
+++ /dev/null
Binary files differ
diff --git a/doc/user/project/img/labels_generate.png b/doc/user/project/img/labels_generate.png
deleted file mode 100644
index 987f4b5be71..00000000000
--- a/doc/user/project/img/labels_generate.png
+++ /dev/null
Binary files differ
diff --git a/doc/user/project/img/labels_generate_default.png b/doc/user/project/img/labels_generate_default.png
new file mode 100644
index 00000000000..fca2a06e04f
--- /dev/null
+++ b/doc/user/project/img/labels_generate_default.png
Binary files differ
diff --git a/doc/user/project/img/labels_group_issues.png b/doc/user/project/img/labels_group_issues.png
new file mode 100644
index 00000000000..29dcf7ff45e
--- /dev/null
+++ b/doc/user/project/img/labels_group_issues.png
Binary files differ
diff --git a/doc/user/project/img/labels_list.png b/doc/user/project/img/labels_list.png
new file mode 100644
index 00000000000..12c47ea9766
--- /dev/null
+++ b/doc/user/project/img/labels_list.png
Binary files differ
diff --git a/doc/user/project/img/labels_new_label.png b/doc/user/project/img/labels_new_label.png
deleted file mode 100644
index e26425d0188..00000000000
--- a/doc/user/project/img/labels_new_label.png
+++ /dev/null
Binary files differ
diff --git a/doc/user/project/img/labels_new_label_on_the_fly.png b/doc/user/project/img/labels_new_label_on_the_fly.png
deleted file mode 100644
index 2ac9805b1ab..00000000000
--- a/doc/user/project/img/labels_new_label_on_the_fly.png
+++ /dev/null
Binary files differ
diff --git a/doc/user/project/img/labels_new_label_on_the_fly_create.png b/doc/user/project/img/labels_new_label_on_the_fly_create.png
deleted file mode 100644
index 02ccf68553b..00000000000
--- a/doc/user/project/img/labels_new_label_on_the_fly_create.png
+++ /dev/null
Binary files differ
diff --git a/doc/user/project/img/labels_prioritize.png b/doc/user/project/img/labels_prioritize.png
deleted file mode 100644
index d602a3c90ec..00000000000
--- a/doc/user/project/img/labels_prioritize.png
+++ /dev/null
Binary files differ
diff --git a/doc/user/project/img/labels_prioritized.png b/doc/user/project/img/labels_prioritized.png
new file mode 100644
index 00000000000..57dcfe89b3d
--- /dev/null
+++ b/doc/user/project/img/labels_prioritized.png
Binary files differ
diff --git a/doc/user/project/img/labels_promotion.png b/doc/user/project/img/labels_promotion.png
new file mode 100644
index 00000000000..8a5efd210a2
--- /dev/null
+++ b/doc/user/project/img/labels_promotion.png
Binary files differ
diff --git a/doc/user/project/img/labels_sidebar.png b/doc/user/project/img/labels_sidebar.png
new file mode 100644
index 00000000000..7349c6d4f0c
--- /dev/null
+++ b/doc/user/project/img/labels_sidebar.png
Binary files differ
diff --git a/doc/user/project/img/labels_sidebar_assign.png b/doc/user/project/img/labels_sidebar_assign.png
new file mode 100644
index 00000000000..61e8d04fc85
--- /dev/null
+++ b/doc/user/project/img/labels_sidebar_assign.png
Binary files differ
diff --git a/doc/user/project/img/labels_sidebar_inline.png b/doc/user/project/img/labels_sidebar_inline.png
new file mode 100644
index 00000000000..31fa397761d
--- /dev/null
+++ b/doc/user/project/img/labels_sidebar_inline.png
Binary files differ
diff --git a/doc/user/project/img/labels_sort_label_priority.png b/doc/user/project/img/labels_sort_label_priority.png
new file mode 100644
index 00000000000..c8b97639121
--- /dev/null
+++ b/doc/user/project/img/labels_sort_label_priority.png
Binary files differ
diff --git a/doc/user/project/img/labels_sort_priority.png b/doc/user/project/img/labels_sort_priority.png
new file mode 100644
index 00000000000..a95198e7f72
--- /dev/null
+++ b/doc/user/project/img/labels_sort_priority.png
Binary files differ
diff --git a/doc/user/project/img/labels_subscribe.png b/doc/user/project/img/labels_subscribe.png
deleted file mode 100644
index 56f24ae7bc8..00000000000
--- a/doc/user/project/img/labels_subscribe.png
+++ /dev/null
Binary files differ
diff --git a/doc/user/project/img/labels_subscriptions.png b/doc/user/project/img/labels_subscriptions.png
new file mode 100644
index 00000000000..8bcb3b57f6c
--- /dev/null
+++ b/doc/user/project/img/labels_subscriptions.png
Binary files differ
diff --git a/doc/user/project/img/new_label_from_sidebar.gif b/doc/user/project/img/new_label_from_sidebar.gif
new file mode 100644
index 00000000000..572b29a86e1
--- /dev/null
+++ b/doc/user/project/img/new_label_from_sidebar.gif
Binary files differ
diff --git a/doc/user/project/issues/index.md b/doc/user/project/issues/index.md
index 88acd8edbe2..be4436749f9 100644
--- a/doc/user/project/issues/index.md
+++ b/doc/user/project/issues/index.md
@@ -64,9 +64,7 @@ You can also [search and filter](../../search/index.md#issues-and-merge-requests
### Issues per group
-View all the issues in a group (that is, all the issues across all projects in that
-group) by navigating to **Group > Issues**. This view also has the open and closed
-issue tabs.
+View issues in all projects in the group, including all projects of all descendant subgroups of the group. Navigate to **Group > Issues** to view these issues. This view also has the open and closed issues tabs.
![Group Issues list view](img/group_issues_list_view.png)
diff --git a/doc/user/project/labels.md b/doc/user/project/labels.md
index d7eb4bca89c..49f7baf9652 100644
--- a/doc/user/project/labels.md
+++ b/doc/user/project/labels.md
@@ -1,174 +1,125 @@
# Labels
-Labels provide an easy way to categorize the issues or merge requests based on
-descriptive titles like `bug`, `documentation` or any other text you feel like.
-They can have different colors, a description, and are visible throughout
-the issue tracker or inside each issue individually.
+## Overview
-With labels, you can navigate the issue tracker and filter any bloated
-information to visualize only the issues you are interested in. Let's see how
-that works.
+Labels allow you to categorize issues or merge requests using descriptive titles like `bug`, `feature request`, or `docs`. Each label also has a customizable color. They allow you to quickly and dynamically filter and manage issues or merge requests you care about, and are visible throughout GitLab in most places where issues and merge requests are located.
-## Create new labels
+## Project labels and group labels
+
+In GitLab, you can create project and group labels:
+
+- **Project labels** can be assigned to issues or merge requests in that project only.
+- **Group labels** can be assigned to any issue or merge request of any project in that group.
+- In the [future](https://gitlab.com/gitlab-org/gitlab-ce/issues/40915), you will be able to assign group labels to issues and merge reqeusts of projects in [subgroups](../group/subgroups/index.md).
+
+## Creating labels
>**Note:**
-A permission level of `Developer` or higher is required in order to manage
-labels.
+A permission level of `Developer` or higher is required in order to create labels.
-Head over a single project and navigate to **Issues > Labels**.
+### New project label
-The first time you visit this page, you'll notice that there are no labels
-created yet.
+To create a **project label**, navigate to **Issues > Labels** in the project.
-Creating a new label from scratch is as easy as pressing the **New label**
-button. From there on you can choose the name, give it an optional description,
-a color and you are set.
+Click the **New label** button. Enter the title, an optional description, and the background color. Click **Create label** to create the label.
-When you are ready press the **Create label** button to create the new label.
+If a project has no labels, you can generate a default set of project labels from its empty label list page:
-![New label](img/labels_new_label.png)
+![Labels generate default](img/labels_generate_default.png)
----
+GitLab will add the following default labels to the project:
-## Default labels
+![Labels default](img/labels_default.png)
-The very first time you visit the labels area, it's gonna be empty. In that
-case, it's possible to populate the labels for your project from a set of
-predefined labels.
+### New group label
-Click the link to 'Generate a default set of labels' and GitLab will
-generate them for you. There are 8 default generated labels in total:
+To create a **group label**, follow similar steps from above to project labels. Navigate to **Issues > Labels** in the group and create it from there.
-- bug
-- confirmed
-- critical
-- discussion
-- documentation
-- enhancement
-- suggestion
-- support
+Group labels appear in every label list page of the group's child projects.
-## Labels Overview
+![Labels list](img/labels_list.png)
-![Default generated labels](img/labels_default.png)
+### New project label from sidebar
-You can see that from the labels page you can have an overview of the number of
-issues and merge requests assigned to each label.
+From the sidebar of an issue or a merge request, you can create a create a new **project label** inline immediately, instead of navigating to the project label list page.
-## Prioritize labels
+![Labels inline](img/new_label_from_sidebar.gif)
->**Notes:**
->
-> - Introduced in GitLab 8.9.
-> - Priority sorting is based on the highest priority label only. This might
-> change in the future, follow the discussion in
-> https://gitlab.com/gitlab-org/gitlab-ce/issues/18554.
+## Editing labels
-Prioritized labels are like any other label, but sorted by priority. This allows
-you to sort issues and merge requests by label priority.
+NOTE: **Note:**
+A permission level of `Developer` or higher is required in order to edit labels.
-To prioritize labels, navigate to your project's **Issues > Labels** and click
-on the star icon next to them to put them in the priority list. Click on the
-star icon again to remove them from the list.
+You can update a label by navigating to **Issues > Labels** in the project ot group and clicking the pencil icon.
-From there, you can drag them around to set the desired priority. Priority is
-set from high to low with an ascending order. Labels with no priority, count as
-having their priority set to null.
+You can delete a label by clicking the trash icon.
-![Prioritize labels](img/labels_prioritize.png)
+### Promoting project labels to group labels
-Now that you have labels prioritized, you can use the 'Label priority' and 'Priority'
-sort orders in the issues or merge requests tracker.
+If you are expanding from a few projects to a larger number of projects within the same group, you may want to share the same label among multiple projects in the same group. If you previously created a project label and now want to make it available for other projects, you can promote it to a group label.
-In the following, everything applies to both issues and merge requests, but we'll
-refer to just issues for brevity.
+From the project label list page, you can promote a project label to a group label. This will merge all project labels across all projects in this group with the same name into a single group label. All issues and merge requests that previously were assigned one of these project labels will now be assigned the new group label. This action cannot be reversed and the changes are permanent.
-The 'Label priority' sort order positions issues with higher priority labels
-toward the top, and issues with lower priority labels toward the bottom. A non-prioritized
-label is considered to have the lowest priority. For a given issue, we _only_ consider the
-highest priority label assigned to it in the comparison. ([We are discussing](https://gitlab.com/gitlab-org/gitlab-ce/issues/18554)
-including all the labels in a given issue for this comparison.) Given two issues
-are equal according to this sort comparison, their relative order is equal, and
-therefore it's not guaranteed that one will be always above the other.
+![Labels promotion](img/labels_promotion.png)
-![Label priority sort order](img/label_priority_sort_order.png)
+## Assigning labels from the sidebar
-The 'Priority' sort order comparison first considers an issue's milestone's due date,
-(if the issue is assigned a milestone and the milestone's due date exists), and then
-secondarily considers the label priority comparison above. Sooner due dates results
-a higher sort order. If an issue doesn't have a milestone due date, it is equivalent to
-being assigned to a milestone that has a due date in the infinite future. Given two issues
-are equal according to this two-stage sort comparison, their relative order is equal, and
-therefore it's not guaranteed that one will be always above the other.
+Every issue and merge request can be assigned any number of labels. The labels are visible on every issue and merge request page, in the sidebar. They are also visible in the issue board. From the sidebar, you can assign or unassign a label to the object (i.e. label or unlabel it). You can also perform this as a [quick action](quick_actions.md) in a comment.
-![Priority sort order](img/priority_sort_order.png)
+| View labels in sidebar | Assign labels from sidebar |
+|:---:|:---:|
+| ![Labels sidebar](img/labels_sidebar.png) | ![Labels sidebar assign](img/labels_sidebar_assign.png) |
+## Filtering issues and merge requests by label
-## Subscribe to labels
+### Filtering in list pages
-If you don’t want to miss issues or merge requests that are important to you,
-simply subscribe to a label. You’ll get notified whenever the label gets added
-to an issue or merge request, making sure you don’t miss a thing.
+From the project issue list page and the project merge request list page, you can [filter](../search/index.md#issues-and-merge-requests) by both group labels and project labels.
-Go to your project's **Issues > Labels** area, find the label(s) you want to
-subscribe to and click on the eye icon. Click again to unsubscribe.
+From the group issue list page and the group merge request list page, you can [filter](../search/index.md#issues-and-merge-requests) by both group labels and project labels.
-![Subscribe to labels](img/labels_subscribe.png)
+![Labels group issues](img/labels_group_issues.png)
-If you work on a large or popular project, try subscribing only to the labels
-that are relevant to you. You’ll notice it’ll be much easier to focus on what’s
-important.
+### Filtering in issue boards
-## Create a new label when inside an issue
+- From [project boards](issue_board.md), you can filter by both group labels and project labels in the [search and filter bar](../search/index.md#issue-boards).
-There are times when you are already inside an issue searching to assign a
-label, only to realize it doesn't exist. Instead of going to the **Labels**
-page and being distracted from your original purpose, you can create new
-labels on the fly.
+## Subscribing to labels
-Expand the issue sidebar and select **Create new label** from the labels dropdown
-list. Provide a name, pick a color and hit **Create**. The new label will be
-ready to used right away!
+From the project label list page and the group label list page, you can subscribe to [notifications](../../workflow/notifications.md) of a given label, to alert you that that label has been assigned to an issue or merge request.
-![New label on the fly](img/labels_new_label_on_the_fly.png)
+![Labels subscriptions](img/labels_subscriptions.png)
-## Assigning labels to issues and merge requests
+## Label priority
-There are generally two ways to assign a label to an issue or merge request.
+>**Notes:**
+>
+> - Introduced in GitLab 8.9.
+> - Priority sorting is based on the highest priority label only. [This discussion](https://gitlab.com/gitlab-org/gitlab-ce/issues/18554) considers changing this.
-The first one is to assign a label when you first create or edit an issue or
-merge request.
+Labels can have relative priorities, which are used in the "Label priority" and "Priority" sort orders of the issue and merge request list pages.
-The second way is by using the right sidebar when inside an issue or merge
-request. Expand it and hit **Edit** in the labels area. Start typing the name
-of the label you are looking for to narrow down the list, and select it. You
-can add more than one labels at once. When done, click outside the sidebar area
-for the changes to take effect.
+From the project label list page, star a label to indicate that it has a priority. Drag starred labels up and down to change their priority. Higher means higher priority. Prioritization happens at the project level, only on the project label list page, and not on the group label list page. However, both project and group labels can be prioritized on the project label list page since both types are displayed on the project label list page.
-![Assign label in sidebar](img/labels_assign_label_sidebar.png)
-![Save labels in sidebar](img/labels_assign_label_sidebar_saved.png)
+![Labels prioritized](img/labels_prioritized.png)
----
+On the project and group issue and merge request list pages, you can sort by `Label priority` and `Priority`, which account for objects (issues and merge requests) that have prioritized labels assigned to them.
-To remove labels, expand the left sidebar and unmark them from the labels list.
-Simple as that.
+If you sort by `Label priority`, GitLab considers this sort comparison order:
-## Use labels to filter issues
+- Object with a higher priority prioritized label.
+- Object without a prioritized label.
-Once you start adding labels to your issues, you'll see the benefit of it.
-Labels can have several uses, one of them being the quick filtering of issues
-or merge requests.
+Ties are broken arbitrarily. (Note that we _only_ consider the highest prioritized label in an object, and not any of the lower prioritized labels. [This discussion](https://gitlab.com/gitlab-org/gitlab-ce/issues/18554) considers changing this.)
-Pick an existing label from the dropdown _Label_ menu or click on an existing
-label from the issue tracker. In the latter case, you also get to see the
-label description like shown below.
+![Labels sort label priority](img/labels_sort_label_priority.png)
-![Filter labels](img/labels_filter.png)
+If you sort by `Priority`, GitLab considers this sort comparison order:
----
+- Object's assigned [milestone](milestones/index.md)'s due date is sooner, provided the object has a milestone and the milestone has a due date. If this isn't the case, consider the object having a due date in the infinite future.
+- Object with a higher priority prioritized label.
+- Object without a prioritized label.
-And if you added a description to your label, you can see it by hovering your
-mouse over the label in the issue tracker or wherever else the label is
-rendered.
+Ties are broken arbitrarily.
-![Label tooltips](img/labels_description_tooltip.png)
+![Labels sort priority](img/labels_sort_priority.png)
diff --git a/doc/user/project/merge_requests/index.md b/doc/user/project/merge_requests/index.md
index aa3266cb457..0de89f90e21 100644
--- a/doc/user/project/merge_requests/index.md
+++ b/doc/user/project/merge_requests/index.md
@@ -70,9 +70,9 @@ and you can use the tabs available to quickly filter by open and closed. You can
## Merge requests per group
-View all the merge requests in a group (that is, all the merge requests across all projects in that
-group) by navigating to **Group > Merge Requests**. This view also has the open, merged, and closed
-merge request tabs, from which you can [search and filter the results](../../search/index.md#issues-and-merge-requests-per-group).
+View merge requests in all projects in the group, including all projects of all descendant subgroups of the group. Navigate to **Group > Merge Requests** to view these merge requests. This view also has the open and closed merge requests tabs.
+
+You can [search and filter the results](../../search/index.md#issues-and-merge-requests-per-group) from here.
![Group Issues list view](img/group_merge_requests_list_view.png)
@@ -146,6 +146,19 @@ administrator to do so.
![Create new merge requests by email](img/create_from_email.png)
+## Find the merge request that introduced a change
+
+> **Note**: this feature was [implemented in GitLab 10.5](https://gitlab.com/gitlab-org/gitlab-ce/issues/2383).
+
+When viewing the commit details page, GitLab will link to the merge request (or
+merge requests, if it's in more than one) containing that commit.
+
+This only applies to commits that are in the most recent version of a merge
+request - if a commit was in a merge request, then rebased out of that merge
+request, they will not be linked.
+
+[Read more about merge request versions](versions.md)
+
## Revert changes
GitLab implements Git's powerful feature to revert any commit with introducing
@@ -160,7 +173,7 @@ of merge request diff is created. When you visit a merge request that contains
more than one pushes, you can select and compare the versions of those merge
request diffs.
-[Read more about the merge requests versions.](versions.md)
+[Read more about merge request versions](versions.md)
## Work In Progress merge requests
diff --git a/doc/user/project/merge_requests/work_in_progress_merge_requests.md b/doc/user/project/merge_requests/work_in_progress_merge_requests.md
index 546c8bdc5e5..f01da06fa6e 100644
--- a/doc/user/project/merge_requests/work_in_progress_merge_requests.md
+++ b/doc/user/project/merge_requests/work_in_progress_merge_requests.md
@@ -7,7 +7,8 @@ have been marked a **Work In Progress**.
![Blocked Accept Button](img/wip_blocked_accept_button.png)
To mark a merge request a Work In Progress, simply start its title with `[WIP]`
-or `WIP:`.
+or `WIP:`. As an alternative, you're also able to do it by sending a commit
+with its title starting with `wip` or `WIP` to the merge request's source branch.
![Mark as WIP](img/wip_mark_as_wip.png)
diff --git a/doc/user/project/pages/getting_started_part_three.md b/doc/user/project/pages/getting_started_part_three.md
index 0096f8507d2..a153610c712 100644
--- a/doc/user/project/pages/getting_started_part_three.md
+++ b/doc/user/project/pages/getting_started_part_three.md
@@ -155,15 +155,40 @@ Certificates are NOT required to add to your custom
(sub)domain on your GitLab Pages project, though they are
highly recommendable.
-The importance of having any website securely served under HTTPS
-is explained on the introductory section of the blog post
-[Secure GitLab Pages with StartSSL](https://about.gitlab.com/2016/06/24/secure-gitlab-pages-with-startssl/#https-a-quick-overview).
+Let's start with an introduction to the importance of HTTPS.
+Alternatively, jump ahead to [adding certificates to your project](#adding-certificates-to-your-project).
-The reason why certificates are so important is that they encrypt
+#### Why should I care about HTTPS?
+
+This might be your first question. If our sites are hosted by GitLab Pages,
+they are static, hence we are not dealing with server-side scripts
+nor credit card transactions, then why do we need secure connections?
+
+Back in the 1990s, where HTTPS came out, [SSL](https://en.wikipedia.org/wiki/Transport_Layer_Security#SSL_1.0.2C_2.0_and_3.0) was considered a "special"
+security measure, necessary just for big companies, like banks and shoppings sites
+with financial transactions.
+Now we have a different picture. [According to Josh Aas](https://letsencrypt.org/2015/10/29/phishing-and-malware.html), Executive Director at [ISRG](https://en.wikipedia.org/wiki/Internet_Security_Research_Group):
+
+> _We’ve since come to realize that HTTPS is important for almost all websites. It’s important for any website that allows people to log in with a password, any website that [tracks its users](https://www.washingtonpost.com/news/the-switch/wp/2013/12/10/nsa-uses-google-cookies-to-pinpoint-targets-for-hacking/) in any way, any website that [doesn’t want its content altered](http://arstechnica.com/tech-policy/2014/09/why-comcasts-javascript-ad-injections-threaten-security-net-neutrality/), and for any site that offers content people might not want others to know they are consuming. We’ve also learned that any site not secured by HTTPS [can be used to attack other sites](http://krebsonsecurity.com/2015/04/dont-be-fodder-for-chinas-great-cannon/)._
+
+Therefore, the reason why certificates are so important is that they encrypt
the connection between the **client** (you, me, your visitors)
and the **server** (where you site lives), through a keychain of
authentications and validations.
+How about taking Josh's advice and protecting our sites too? We will be
+well supported, and we'll contribute to a safer internet.
+
+#### Organizations supporting HTTPS
+
+There is a huge movement in favor of securing all the web. W3C fully
+[supports the cause](https://w3ctag.github.io/web-https/) and explains very well
+the reasons for that. Richard Barnes, a writer for Mozilla Security Blog,
+suggested that [Firefox would deprecate HTTP](https://blog.mozilla.org/security/2015/04/30/deprecating-non-secure-http/),
+and would no longer accept unsecured connections. Recently, Mozilla published a
+[communication](https://blog.mozilla.org/security/2016/03/29/march-2016-ca-communication/)
+reiterating the importance of HTTPS.
+
### Issuing Certificates
GitLab Pages accepts [PEM](https://support.quovadisglobal.com/kb/a37/what-is-pem-format.aspx) certificates issued by
diff --git a/doc/user/project/pages/index.md b/doc/user/project/pages/index.md
index 8404d789de6..df245710940 100644
--- a/doc/user/project/pages/index.md
+++ b/doc/user/project/pages/index.md
@@ -54,7 +54,6 @@ _Blog posts for securing GitLab Pages custom domains with SSL/TLS certificates:_
- [CloudFlare](https://about.gitlab.com/2017/02/07/setting-up-gitlab-pages-with-cloudflare-certificates/)
- [Let's Encrypt](https://about.gitlab.com/2016/04/11/tutorial-securing-your-gitlab-pages-with-tls-and-letsencrypt/) (outdated)
-- [StartSSL](https://about.gitlab.com/2016/06/24/secure-gitlab-pages-with-startssl/) (deprecated)
## Advanced use
diff --git a/lib/api/internal.rb b/lib/api/internal.rb
index 9285fb90cdc..b3660e4a1d0 100644
--- a/lib/api/internal.rb
+++ b/lib/api/internal.rb
@@ -13,7 +13,7 @@ module API
# key_id - ssh key id for Git over SSH
# user_id - user id for Git over HTTP
# protocol - Git access protocol being used, e.g. HTTP or SSH
- # project - project path with namespace
+ # project - project full_path (not path on disk)
# action - git action (git-upload-pack or git-receive-pack)
# changes - changes as "oldrev newrev ref", see Gitlab::ChangesList
post "/allowed" do
diff --git a/lib/api/search.rb b/lib/api/search.rb
index 9f08fd96a3b..b9982e03bb3 100644
--- a/lib/api/search.rb
+++ b/lib/api/search.rb
@@ -85,9 +85,9 @@ module API
use :pagination
end
get ':id/-/search' do
- find_group!(params[:id])
+ group = find_group!(params[:id])
- present search(group_id: params[:id]), with: entity
+ present search(group_id: group.id), with: entity
end
end
@@ -106,9 +106,9 @@ module API
use :pagination
end
get ':id/-/search' do
- find_project!(params[:id])
+ project = find_project!(params[:id])
- present search(project_id: params[:id]), with: entity
+ present search(project_id: project.id), with: entity
end
end
end
diff --git a/lib/api/todos.rb b/lib/api/todos.rb
index ffccfebe752..c6dbcf84e3a 100644
--- a/lib/api/todos.rb
+++ b/lib/api/todos.rb
@@ -60,7 +60,7 @@ module API
end
post ':id/mark_as_done' do
TodoService.new.mark_todos_as_done_by_ids(params[:id], current_user)
- todo = Todo.find(params[:id])
+ todo = current_user.todos.find(params[:id])
present todo, with: Entities::Todo, current_user: current_user
end
diff --git a/lib/api/v3/todos.rb b/lib/api/v3/todos.rb
index 2f2cf259987..3e2c61f6dbd 100644
--- a/lib/api/v3/todos.rb
+++ b/lib/api/v3/todos.rb
@@ -12,7 +12,7 @@ module API
end
delete ':id' do
TodoService.new.mark_todos_as_done_by_ids(params[:id], current_user)
- todo = Todo.find(params[:id])
+ todo = current_user.todos.find(params[:id])
present todo, with: ::API::Entities::Todo, current_user: current_user
end
diff --git a/lib/banzai/filter/syntax_highlight_filter.rb b/lib/banzai/filter/syntax_highlight_filter.rb
index a79a0154846..0ac7e231b5b 100644
--- a/lib/banzai/filter/syntax_highlight_filter.rb
+++ b/lib/banzai/filter/syntax_highlight_filter.rb
@@ -14,23 +14,33 @@ module Banzai
end
def highlight_node(node)
- code = node.text
css_classes = 'code highlight js-syntax-highlight'
- language = node.attr('lang')
+ lang = node.attr('lang')
+ retried = false
- if use_rouge?(language)
- lexer = lexer_for(language)
+ if use_rouge?(lang)
+ lexer = lexer_for(lang)
language = lexer.tag
+ else
+ lexer = Rouge::Lexers::PlainText.new
+ language = lang
+ end
+
+ begin
+ code = Rouge::Formatters::HTMLGitlab.format(lex(lexer, node.text), tag: language)
+ css_classes << " #{language}" if language
+ rescue
+ # Gracefully handle syntax highlighter bugs/errors to ensure users can
+ # still access an issue/comment/etc. First, retry with the plain text
+ # filter. If that fails, then just skip this entirely, but that would
+ # be a pretty bad upstream bug.
+ return if retried
- begin
- code = Rouge::Formatters::HTMLGitlab.format(lex(lexer, code), tag: language)
- css_classes << " #{language}"
- rescue
- # Gracefully handle syntax highlighter bugs/errors to ensure
- # users can still access an issue/comment/etc.
+ language = nil
+ lexer = Rouge::Lexers::PlainText.new
+ retried = true
- language = nil
- end
+ retry
end
highlighted = %(<pre class="#{css_classes}" lang="#{language}" v-pre="true"><code>#{code}</code></pre>)
diff --git a/lib/gitlab/background_migration/create_fork_network_memberships_range.rb b/lib/gitlab/background_migration/create_fork_network_memberships_range.rb
index 03b17b319fa..1b4a9e8a194 100644
--- a/lib/gitlab/background_migration/create_fork_network_memberships_range.rb
+++ b/lib/gitlab/background_migration/create_fork_network_memberships_range.rb
@@ -14,6 +14,14 @@ module Gitlab
def perform(start_id, end_id)
log("Creating memberships for forks: #{start_id} - #{end_id}")
+ insert_members(start_id, end_id)
+
+ if missing_members?(start_id, end_id)
+ BackgroundMigrationWorker.perform_in(RESCHEDULE_DELAY, "CreateForkNetworkMembershipsRange", [start_id, end_id])
+ end
+ end
+
+ def insert_members(start_id, end_id)
ActiveRecord::Base.connection.execute <<~INSERT_MEMBERS
INSERT INTO fork_network_members (fork_network_id, project_id, forked_from_project_id)
@@ -33,10 +41,9 @@ module Gitlab
WHERE existing_members.project_id = forked_project_links.forked_to_project_id
)
INSERT_MEMBERS
-
- if missing_members?(start_id, end_id)
- BackgroundMigrationWorker.perform_in(RESCHEDULE_DELAY, "CreateForkNetworkMembershipsRange", [start_id, end_id])
- end
+ rescue ActiveRecord::RecordNotUnique => e
+ # `fork_network_member` was created concurrently in another migration
+ log(e.message)
end
def missing_members?(start_id, end_id)
diff --git a/lib/gitlab/encoding_helper.rb b/lib/gitlab/encoding_helper.rb
index c0edcabc6fd..6659efa0961 100644
--- a/lib/gitlab/encoding_helper.rb
+++ b/lib/gitlab/encoding_helper.rb
@@ -28,9 +28,9 @@ module Gitlab
# encode and clean the bad chars
message.replace clean(message)
- rescue ArgumentError
- return nil
- rescue
+ rescue ArgumentError => e
+ return unless e.message.include?('unknown encoding name')
+
encoding = detect ? detect[:encoding] : "unknown"
"--broken encoding: #{encoding}"
end
diff --git a/lib/gitlab/git/repository.rb b/lib/gitlab/git/repository.rb
index 6761fb0937a..5f014e43c6f 100644
--- a/lib/gitlab/git/repository.rb
+++ b/lib/gitlab/git/repository.rb
@@ -1614,17 +1614,14 @@ module Gitlab
# Gitaly note: JV: Trying to get rid of the 'filter' option so we can implement this with 'git'.
def branches_filter(filter: nil, sort_by: nil)
- # n+1: https://gitlab.com/gitlab-org/gitlab-ce/issues/37464
- branches = Gitlab::GitalyClient.allow_n_plus_1_calls do
- rugged.branches.each(filter).map do |rugged_ref|
- begin
- target_commit = Gitlab::Git::Commit.find(self, rugged_ref.target)
- Gitlab::Git::Branch.new(self, rugged_ref.name, rugged_ref.target, target_commit)
- rescue Rugged::ReferenceError
- # Omit invalid branch
- end
- end.compact
- end
+ branches = rugged.branches.each(filter).map do |rugged_ref|
+ begin
+ target_commit = Gitlab::Git::Commit.find(self, rugged_ref.target)
+ Gitlab::Git::Branch.new(self, rugged_ref.name, rugged_ref.target, target_commit)
+ rescue Rugged::ReferenceError
+ # Omit invalid branch
+ end
+ end.compact
sort_branches(branches, sort_by)
end
diff --git a/lib/gitlab/shell.rb b/lib/gitlab/shell.rb
index f4a41dc3eda..4ba44e0feef 100644
--- a/lib/gitlab/shell.rb
+++ b/lib/gitlab/shell.rb
@@ -294,7 +294,8 @@ module Gitlab
# add_namespace("/path/to/storage", "gitlab")
#
def add_namespace(storage, name)
- Gitlab::GitalyClient.migrate(:add_namespace) do |enabled|
+ Gitlab::GitalyClient.migrate(:add_namespace,
+ status: Gitlab::GitalyClient::MigrationStatus::OPT_OUT) do |enabled|
if enabled
gitaly_namespace_client(storage).add(name)
else
@@ -315,7 +316,8 @@ module Gitlab
# rm_namespace("/path/to/storage", "gitlab")
#
def rm_namespace(storage, name)
- Gitlab::GitalyClient.migrate(:remove_namespace) do |enabled|
+ Gitlab::GitalyClient.migrate(:remove_namespace,
+ status: Gitlab::GitalyClient::MigrationStatus::OPT_OUT) do |enabled|
if enabled
gitaly_namespace_client(storage).remove(name)
else
@@ -333,7 +335,8 @@ module Gitlab
# mv_namespace("/path/to/storage", "gitlab", "gitlabhq")
#
def mv_namespace(storage, old_name, new_name)
- Gitlab::GitalyClient.migrate(:rename_namespace) do |enabled|
+ Gitlab::GitalyClient.migrate(:rename_namespace,
+ status: Gitlab::GitalyClient::MigrationStatus::OPT_OUT) do |enabled|
if enabled
gitaly_namespace_client(storage).rename(old_name, new_name)
else
@@ -368,7 +371,8 @@ module Gitlab
#
# Gitaly migration: https://gitlab.com/gitlab-org/gitaly/issues/385
def exists?(storage, dir_name)
- Gitlab::GitalyClient.migrate(:namespace_exists) do |enabled|
+ Gitlab::GitalyClient.migrate(:namespace_exists,
+ status: Gitlab::GitalyClient::MigrationStatus::OPT_OUT) do |enabled|
if enabled
gitaly_namespace_client(storage).exists?(dir_name)
else
diff --git a/lib/tasks/gemojione.rake b/lib/tasks/gemojione.rake
index c2d3a6b6950..c6942d22926 100644
--- a/lib/tasks/gemojione.rake
+++ b/lib/tasks/gemojione.rake
@@ -115,7 +115,7 @@ namespace :gemojione do
end
end
- style_path = Rails.root.join(*%w(app assets stylesheets framework emoji-sprites.scss))
+ style_path = Rails.root.join(*%w(app assets stylesheets framework emoji_sprites.scss))
# Combine the resized assets into a packed sprite and re-generate the SCSS
SpriteFactory.cssurl = "image-url('$IMAGE')"
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index a51141d5360..fadc17a659d 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -261,6 +261,9 @@ msgstr ""
msgid "Author"
msgstr ""
+msgid "Authors: %{authors}"
+msgstr ""
+
msgid "Auto Review Apps and Auto Deploy need a %{kubernetes} to work correctly."
msgstr ""
@@ -294,6 +297,9 @@ msgstr ""
msgid "Avatar will be removed. Are you sure?"
msgstr ""
+msgid "Average per day: %{average}"
+msgstr ""
+
msgid "Begin with the selected commit"
msgstr ""
@@ -725,6 +731,9 @@ msgstr ""
msgid "ClusterIntegration|Make sure your account %{link_to_requirements} to create Kubernetes clusters"
msgstr ""
+msgid "ClusterIntegration|Manage"
+msgstr ""
+
msgid "ClusterIntegration|Manage your Kubernetes cluster by visiting %{link_gke}"
msgstr ""
@@ -859,6 +868,9 @@ msgstr ""
msgid "Commit message"
msgstr ""
+msgid "Commit statistics for %{ref} %{start_time} - %{end_time}"
+msgstr ""
+
msgid "CommitBoxTitle|Commit"
msgstr ""
@@ -871,6 +883,15 @@ msgstr ""
msgid "Commits feed"
msgstr ""
+msgid "Commits per day hour (UTC)"
+msgstr ""
+
+msgid "Commits per day of month"
+msgstr ""
+
+msgid "Commits per weekday"
+msgstr ""
+
msgid "Commits|An error occurred while fetching merge requests data."
msgstr ""
@@ -2033,6 +2054,9 @@ msgstr ""
msgid "Profiles|your account"
msgstr ""
+msgid "Programming languages used in this repository"
+msgstr ""
+
msgid "Project '%{project_name}' is in the process of being deleted."
msgstr ""
@@ -2901,6 +2925,9 @@ msgstr ""
msgid "Total test time for all commits/merges"
msgstr ""
+msgid "Total: %{total}"
+msgstr ""
+
msgid "Track time with quick actions"
msgstr ""
diff --git a/package.json b/package.json
index c508a6e9931..75d11afbbe1 100644
--- a/package.json
+++ b/package.json
@@ -52,6 +52,7 @@
"jed": "^1.1.1",
"jquery": "^2.2.4",
"jquery-ujs": "1.2.2",
+ "jquery.waitforimages": "^2.2.0",
"js-cookie": "^2.1.3",
"jszip": "^3.1.3",
"jszip-utils": "^0.0.2",
diff --git a/qa/README.md b/qa/README.md
index 3c1b61900d9..3a99a30d379 100644
--- a/qa/README.md
+++ b/qa/README.md
@@ -70,6 +70,30 @@ If you need to authenticate as a different user, you can provide the
GITLAB_USERNAME=jsmith GITLAB_PASSWORD=password bin/qa Test::Instance https://gitlab.example.com
```
+If your user doesn't have permission to default sandbox group
+`gitlab-qa-sandbox`, you could also use another sandbox group by giving
+`GITLAB_SANDBOX_NAME`:
+
+```
+GITLAB_USERNAME=jsmith GITLAB_PASSWORD=password GITLAB_SANDBOX_NAME=jsmith-qa-sandbox bin/qa Test::Instance https://gitlab.example.com
+```
+
+In addition, the `GITLAB_USER_TYPE` can be set to "ldap" to sign in as an LDAP user:
+
+```
+GITLAB_USER_TYPE=ldap GITLAB_USERNAME=jsmith GITLAB_PASSWORD=password GITLAB_SANDBOX_NAME=jsmith-qa-sandbox bin/qa Test::Instance https://gitlab.example.com
+```
+
All [supported environment variables are here](https://gitlab.com/gitlab-org/gitlab-qa#supported-environment-variables).
+### Building a Docker image to test
+
+Once you have made changes to the CE/EE repositories, you may want to build a
+Docker image to test locally instead of waiting for the `gitlab-ce-qa` or
+`gitlab-ee-qa` nightly builds. To do that, you can run from this directory:
+
+```sh
+docker build -t gitlab/gitlab-ce-qa:nightly .
+```
+
[GDK]: https://gitlab.com/gitlab-org/gitlab-development-kit/
diff --git a/qa/qa/page/main/login.rb b/qa/qa/page/main/login.rb
index 0d1ffd9694a..a8a5601dbe6 100644
--- a/qa/qa/page/main/login.rb
+++ b/qa/qa/page/main/login.rb
@@ -31,22 +31,37 @@ module QA
end
end
+ def set_initial_password_if_present
+ if page.has_content?('Change your password')
+ fill_in :user_password, with: Runtime::User.password
+ fill_in :user_password_confirmation, with: Runtime::User.password
+ click_button 'Change your password'
+ end
+ end
+
+ def sign_in_using_credentials
+ if Runtime::User.ldap_user?
+ sign_in_using_ldap_credentials
+ else
+ sign_in_using_gitlab_credentials
+ end
+ end
+
def sign_in_using_ldap_credentials
- click_link 'LDAP'
+ using_wait_time 0 do
+ set_initial_password_if_present
- fill_in :username, with: Runtime::User.name
- fill_in :password, with: Runtime::User.password
+ click_link 'LDAP'
- click_button 'Sign in'
+ fill_in :username, with: Runtime::User.name
+ fill_in :password, with: Runtime::User.password
+ click_button 'Sign in'
+ end
end
- def sign_in_using_credentials
+ def sign_in_using_gitlab_credentials
using_wait_time 0 do
- if page.has_content?('Change your password')
- fill_in :user_password, with: Runtime::User.password
- fill_in :user_password_confirmation, with: Runtime::User.password
- click_button 'Change your password'
- end
+ set_initial_password_if_present
click_link 'Standard' if page.has_content?('LDAP')
diff --git a/qa/qa/runtime/env.rb b/qa/qa/runtime/env.rb
index 56944e8b641..5401372e225 100644
--- a/qa/qa/runtime/env.rb
+++ b/qa/qa/runtime/env.rb
@@ -16,6 +16,28 @@ module QA
def personal_access_token
ENV['PERSONAL_ACCESS_TOKEN']
end
+
+ # By default, "standard" denotes a standard GitLab user login.
+ # Set this to "ldap" if the user should be logged in via LDAP.
+ def user_type
+ (ENV['GITLAB_USER_TYPE'] || 'standard').tap do |type|
+ unless %w(ldap standard).include?(type)
+ raise ArgumentError.new("Invalid user type '#{type}': must be 'ldap' or 'standard'")
+ end
+ end
+ end
+
+ def user_username
+ ENV['GITLAB_USERNAME']
+ end
+
+ def user_password
+ ENV['GITLAB_PASSWORD']
+ end
+
+ def sandbox_name
+ ENV['GITLAB_SANDBOX_NAME']
+ end
end
end
end
diff --git a/qa/qa/runtime/namespace.rb b/qa/qa/runtime/namespace.rb
index a72c2d21898..8d05b387416 100644
--- a/qa/qa/runtime/namespace.rb
+++ b/qa/qa/runtime/namespace.rb
@@ -16,7 +16,7 @@ module QA
end
def sandbox_name
- 'gitlab-qa-sandbox'
+ Runtime::Env.sandbox_name || 'gitlab-qa-sandbox'
end
end
end
diff --git a/qa/qa/runtime/user.rb b/qa/qa/runtime/user.rb
index 60027c89ab1..39e6adf9522 100644
--- a/qa/qa/runtime/user.rb
+++ b/qa/qa/runtime/user.rb
@@ -4,11 +4,15 @@ module QA
extend self
def name
- ENV['GITLAB_USERNAME'] || 'root'
+ Runtime::Env.user_username || 'root'
end
def password
- ENV['GITLAB_PASSWORD'] || '5iveL!fe'
+ Runtime::Env.user_password || '5iveL!fe'
+ end
+
+ def ldap_user?
+ Runtime::Env.user_type == 'ldap'
end
end
end
diff --git a/qa/qa/service/runner.rb b/qa/qa/service/runner.rb
index d0ee33c69f2..c0352e0467a 100644
--- a/qa/qa/service/runner.rb
+++ b/qa/qa/service/runner.rb
@@ -15,6 +15,14 @@ module QA
@tags = %w[qa test]
end
+ def network
+ shell "docker network inspect #{@network}"
+ rescue CommandError
+ 'bridge'
+ else
+ @network
+ end
+
def pull
shell "docker pull #{@image}"
end
@@ -22,7 +30,7 @@ module QA
def register!
shell <<~CMD.tr("\n", ' ')
docker run -d --rm --entrypoint=/bin/sh
- --network #{@network} --name #{@name}
+ --network #{network} --name #{@name}
-e CI_SERVER_URL=#{@address}
-e REGISTER_NON_INTERACTIVE=true
-e REGISTRATION_TOKEN=#{@token}
diff --git a/qa/qa/service/shellout.rb b/qa/qa/service/shellout.rb
index 898febde63c..76fb2af6319 100644
--- a/qa/qa/service/shellout.rb
+++ b/qa/qa/service/shellout.rb
@@ -3,6 +3,8 @@ require 'open3'
module QA
module Service
module Shellout
+ CommandError = Class.new(StandardError)
+
##
# TODO, make it possible to use generic QA framework classes
# as a library - gitlab-org/gitlab-qa#94
@@ -14,7 +16,7 @@ module QA
out.each { |line| puts line }
if wait.value.exited? && wait.value.exitstatus.nonzero?
- raise "Command `#{command}` failed!"
+ raise CommandError, "Command `#{command}` failed!"
end
end
end
diff --git a/qa/qa/specs/features/api/users_spec.rb b/qa/qa/specs/features/api/users_spec.rb
index 9d039590a0e..d4ff4ebbc9a 100644
--- a/qa/qa/specs/features/api/users_spec.rb
+++ b/qa/qa/specs/features/api/users_spec.rb
@@ -14,7 +14,7 @@ module QA
end
scenario 'submit request with a valid user name' do
- get request.url, { params: { username: 'root' } }
+ get request.url, { params: { username: Runtime::User.name } }
expect_status(200)
expect(json_body).to be_an Array
@@ -23,7 +23,7 @@ module QA
end
scenario 'submit request with an invalid user name' do
- get request.url, { params: { username: 'invalid' } }
+ get request.url, { params: { username: SecureRandom.hex(10) } }
expect_status(200)
expect(json_body).to be_an Array
diff --git a/qa/spec/runtime/env_spec.rb b/qa/spec/runtime/env_spec.rb
index 103573db6be..2b6365dbc41 100644
--- a/qa/spec/runtime/env_spec.rb
+++ b/qa/spec/runtime/env_spec.rb
@@ -55,4 +55,25 @@ describe QA::Runtime::Env do
end
end
end
+
+ describe '.user_type' do
+ it 'returns standard if not defined' do
+ expect(described_class.user_type).to eq('standard')
+ end
+
+ it 'returns standard as defined' do
+ stub_env('GITLAB_USER_TYPE', 'standard')
+ expect(described_class.user_type).to eq('standard')
+ end
+
+ it 'returns ldap as defined' do
+ stub_env('GITLAB_USER_TYPE', 'ldap')
+ expect(described_class.user_type).to eq('ldap')
+ end
+
+ it 'returns an error if invalid user type' do
+ stub_env('GITLAB_USER_TYPE', 'foobar')
+ expect { described_class.user_type }.to raise_error(ArgumentError)
+ end
+ end
end
diff --git a/spec/controllers/import/bitbucket_controller_spec.rb b/spec/controllers/import/bitbucket_controller_spec.rb
index e8707760a5a..2be46049aab 100644
--- a/spec/controllers/import/bitbucket_controller_spec.rb
+++ b/spec/controllers/import/bitbucket_controller_spec.rb
@@ -84,20 +84,42 @@ describe Import::BitbucketController do
double(slug: "vim", owner: bitbucket_username, name: 'vim')
end
+ let(:project) { create(:project) }
+
before do
allow_any_instance_of(Bitbucket::Client).to receive(:repo).and_return(bitbucket_repo)
allow_any_instance_of(Bitbucket::Client).to receive(:user).and_return(bitbucket_user)
assign_session_tokens
end
+ it 'returns 200 response when the project is imported successfully' do
+ allow(Gitlab::BitbucketImport::ProjectCreator)
+ .to receive(:new).with(bitbucket_repo, bitbucket_repo.name, user.namespace, user, access_params)
+ .and_return(double(execute: project))
+
+ post :create, format: :json
+
+ expect(response).to have_gitlab_http_status(200)
+ end
+
+ it 'returns 422 response when the project could not be imported' do
+ allow(Gitlab::BitbucketImport::ProjectCreator)
+ .to receive(:new).with(bitbucket_repo, bitbucket_repo.name, user.namespace, user, access_params)
+ .and_return(double(execute: build(:project)))
+
+ post :create, format: :json
+
+ expect(response).to have_gitlab_http_status(422)
+ end
+
context "when the repository owner is the Bitbucket user" do
context "when the Bitbucket user and GitLab user's usernames match" do
it "takes the current user's namespace" do
expect(Gitlab::BitbucketImport::ProjectCreator)
.to receive(:new).with(bitbucket_repo, bitbucket_repo.name, user.namespace, user, access_params)
- .and_return(double(execute: true))
+ .and_return(double(execute: project))
- post :create, format: :js
+ post :create, format: :json
end
end
@@ -107,9 +129,9 @@ describe Import::BitbucketController do
it "takes the current user's namespace" do
expect(Gitlab::BitbucketImport::ProjectCreator)
.to receive(:new).with(bitbucket_repo, bitbucket_repo.name, user.namespace, user, access_params)
- .and_return(double(execute: true))
+ .and_return(double(execute: project))
- post :create, format: :js
+ post :create, format: :json
end
end
@@ -120,7 +142,7 @@ describe Import::BitbucketController do
allow(controller).to receive(:current_user).and_return(user)
allow(user).to receive(:can?).and_return(false)
- post :create, format: :js
+ post :create, format: :json
end
end
end
@@ -143,9 +165,9 @@ describe Import::BitbucketController do
it "takes the existing namespace" do
expect(Gitlab::BitbucketImport::ProjectCreator)
.to receive(:new).with(bitbucket_repo, bitbucket_repo.name, existing_namespace, user, access_params)
- .and_return(double(execute: true))
+ .and_return(double(execute: project))
- post :create, format: :js
+ post :create, format: :json
end
end
@@ -154,7 +176,7 @@ describe Import::BitbucketController do
expect(Gitlab::BitbucketImport::ProjectCreator)
.not_to receive(:new)
- post :create, format: :js
+ post :create, format: :json
end
end
end
@@ -163,17 +185,17 @@ describe Import::BitbucketController do
context "when current user can create namespaces" do
it "creates the namespace" do
expect(Gitlab::BitbucketImport::ProjectCreator)
- .to receive(:new).and_return(double(execute: true))
+ .to receive(:new).and_return(double(execute: project))
- expect { post :create, format: :js }.to change(Namespace, :count).by(1)
+ expect { post :create, format: :json }.to change(Namespace, :count).by(1)
end
it "takes the new namespace" do
expect(Gitlab::BitbucketImport::ProjectCreator)
.to receive(:new).with(bitbucket_repo, bitbucket_repo.name, an_instance_of(Group), user, access_params)
- .and_return(double(execute: true))
+ .and_return(double(execute: project))
- post :create, format: :js
+ post :create, format: :json
end
end
@@ -184,23 +206,23 @@ describe Import::BitbucketController do
it "doesn't create the namespace" do
expect(Gitlab::BitbucketImport::ProjectCreator)
- .to receive(:new).and_return(double(execute: true))
+ .to receive(:new).and_return(double(execute: project))
- expect { post :create, format: :js }.not_to change(Namespace, :count)
+ expect { post :create, format: :json }.not_to change(Namespace, :count)
end
it "takes the current user's namespace" do
expect(Gitlab::BitbucketImport::ProjectCreator)
.to receive(:new).with(bitbucket_repo, bitbucket_repo.name, user.namespace, user, access_params)
- .and_return(double(execute: true))
+ .and_return(double(execute: project))
- post :create, format: :js
+ post :create, format: :json
end
end
end
end
- context 'user has chosen an existing nested namespace and name for the project' do
+ context 'user has chosen an existing nested namespace and name for the project', :postgresql do
let(:parent_namespace) { create(:group, name: 'foo', owner: user) }
let(:nested_namespace) { create(:group, name: 'bar', parent: parent_namespace) }
let(:test_name) { 'test_name' }
@@ -212,63 +234,77 @@ describe Import::BitbucketController do
it 'takes the selected namespace and name' do
expect(Gitlab::BitbucketImport::ProjectCreator)
.to receive(:new).with(bitbucket_repo, test_name, nested_namespace, user, access_params)
- .and_return(double(execute: true))
+ .and_return(double(execute: project))
- post :create, { target_namespace: nested_namespace.full_path, new_name: test_name, format: :js }
+ post :create, { target_namespace: nested_namespace.full_path, new_name: test_name, format: :json }
end
end
- context 'user has chosen a non-existent nested namespaces and name for the project' do
+ context 'user has chosen a non-existent nested namespaces and name for the project', :postgresql do
let(:test_name) { 'test_name' }
it 'takes the selected namespace and name' do
expect(Gitlab::BitbucketImport::ProjectCreator)
.to receive(:new).with(bitbucket_repo, test_name, kind_of(Namespace), user, access_params)
- .and_return(double(execute: true))
+ .and_return(double(execute: project))
- post :create, { target_namespace: 'foo/bar', new_name: test_name, format: :js }
+ post :create, { target_namespace: 'foo/bar', new_name: test_name, format: :json }
end
it 'creates the namespaces' do
allow(Gitlab::BitbucketImport::ProjectCreator)
.to receive(:new).with(bitbucket_repo, test_name, kind_of(Namespace), user, access_params)
- .and_return(double(execute: true))
+ .and_return(double(execute: project))
- expect { post :create, { target_namespace: 'foo/bar', new_name: test_name, format: :js } }
+ expect { post :create, { target_namespace: 'foo/bar', new_name: test_name, format: :json } }
.to change { Namespace.count }.by(2)
end
it 'new namespace has the right parent' do
allow(Gitlab::BitbucketImport::ProjectCreator)
.to receive(:new).with(bitbucket_repo, test_name, kind_of(Namespace), user, access_params)
- .and_return(double(execute: true))
+ .and_return(double(execute: project))
- post :create, { target_namespace: 'foo/bar', new_name: test_name, format: :js }
+ post :create, { target_namespace: 'foo/bar', new_name: test_name, format: :json }
expect(Namespace.find_by_path_or_name('bar').parent.path).to eq('foo')
end
end
- context 'user has chosen existent and non-existent nested namespaces and name for the project' do
+ context 'user has chosen existent and non-existent nested namespaces and name for the project', :postgresql do
let(:test_name) { 'test_name' }
let!(:parent_namespace) { create(:group, name: 'foo', owner: user) }
+ before do
+ parent_namespace.add_owner(user)
+ end
+
it 'takes the selected namespace and name' do
expect(Gitlab::BitbucketImport::ProjectCreator)
.to receive(:new).with(bitbucket_repo, test_name, kind_of(Namespace), user, access_params)
- .and_return(double(execute: true))
+ .and_return(double(execute: project))
- post :create, { target_namespace: 'foo/foobar/bar', new_name: test_name, format: :js }
+ post :create, { target_namespace: 'foo/foobar/bar', new_name: test_name, format: :json }
end
it 'creates the namespaces' do
allow(Gitlab::BitbucketImport::ProjectCreator)
.to receive(:new).with(bitbucket_repo, test_name, kind_of(Namespace), user, access_params)
- .and_return(double(execute: true))
+ .and_return(double(execute: project))
- expect { post :create, { target_namespace: 'foo/foobar/bar', new_name: test_name, format: :js } }
+ expect { post :create, { target_namespace: 'foo/foobar/bar', new_name: test_name, format: :json } }
.to change { Namespace.count }.by(2)
end
end
+
+ context 'when user can not create projects in the chosen namespace' do
+ it 'returns 422 response' do
+ other_namespace = create(:group, name: 'other_namespace')
+
+ post :create, { target_namespace: other_namespace.name, format: :json }
+
+ expect(response).to have_gitlab_http_status(422)
+ end
+ end
end
end
diff --git a/spec/controllers/import/gitlab_controller_spec.rb b/spec/controllers/import/gitlab_controller_spec.rb
index faf1e6f63ea..e958be077c2 100644
--- a/spec/controllers/import/gitlab_controller_spec.rb
+++ b/spec/controllers/import/gitlab_controller_spec.rb
@@ -57,6 +57,7 @@ describe Import::GitlabController do
end
describe "POST create" do
+ let(:project) { create(:project) }
let(:gitlab_username) { user.username }
let(:gitlab_user) do
{ username: gitlab_username }.with_indifferent_access
@@ -75,14 +76,34 @@ describe Import::GitlabController do
assign_session_token
end
+ it 'returns 200 response when the project is imported successfully' do
+ allow(Gitlab::GitlabImport::ProjectCreator)
+ .to receive(:new).with(gitlab_repo, user.namespace, user, access_params)
+ .and_return(double(execute: project))
+
+ post :create, format: :json
+
+ expect(response).to have_gitlab_http_status(200)
+ end
+
+ it 'returns 422 response when the project could not be imported' do
+ allow(Gitlab::GitlabImport::ProjectCreator)
+ .to receive(:new).with(gitlab_repo, user.namespace, user, access_params)
+ .and_return(double(execute: build(:project)))
+
+ post :create, format: :json
+
+ expect(response).to have_gitlab_http_status(422)
+ end
+
context "when the repository owner is the GitLab.com user" do
context "when the GitLab.com user and GitLab server user's usernames match" do
it "takes the current user's namespace" do
expect(Gitlab::GitlabImport::ProjectCreator)
.to receive(:new).with(gitlab_repo, user.namespace, user, access_params)
- .and_return(double(execute: true))
+ .and_return(double(execute: project))
- post :create, format: :js
+ post :create, format: :json
end
end
@@ -92,9 +113,9 @@ describe Import::GitlabController do
it "takes the current user's namespace" do
expect(Gitlab::GitlabImport::ProjectCreator)
.to receive(:new).with(gitlab_repo, user.namespace, user, access_params)
- .and_return(double(execute: true))
+ .and_return(double(execute: project))
- post :create, format: :js
+ post :create, format: :json
end
end
end
@@ -118,9 +139,9 @@ describe Import::GitlabController do
it "takes the existing namespace" do
expect(Gitlab::GitlabImport::ProjectCreator)
.to receive(:new).with(gitlab_repo, existing_namespace, user, access_params)
- .and_return(double(execute: true))
+ .and_return(double(execute: project))
- post :create, format: :js
+ post :create, format: :json
end
end
@@ -129,7 +150,7 @@ describe Import::GitlabController do
expect(Gitlab::GitlabImport::ProjectCreator)
.not_to receive(:new)
- post :create, format: :js
+ post :create, format: :json
end
end
end
@@ -138,17 +159,17 @@ describe Import::GitlabController do
context "when current user can create namespaces" do
it "creates the namespace" do
expect(Gitlab::GitlabImport::ProjectCreator)
- .to receive(:new).and_return(double(execute: true))
+ .to receive(:new).and_return(double(execute: project))
- expect { post :create, format: :js }.to change(Namespace, :count).by(1)
+ expect { post :create, format: :json }.to change(Namespace, :count).by(1)
end
it "takes the new namespace" do
expect(Gitlab::GitlabImport::ProjectCreator)
.to receive(:new).with(gitlab_repo, an_instance_of(Group), user, access_params)
- .and_return(double(execute: true))
+ .and_return(double(execute: project))
- post :create, format: :js
+ post :create, format: :json
end
end
@@ -159,22 +180,22 @@ describe Import::GitlabController do
it "doesn't create the namespace" do
expect(Gitlab::GitlabImport::ProjectCreator)
- .to receive(:new).and_return(double(execute: true))
+ .to receive(:new).and_return(double(execute: project))
- expect { post :create, format: :js }.not_to change(Namespace, :count)
+ expect { post :create, format: :json }.not_to change(Namespace, :count)
end
it "takes the current user's namespace" do
expect(Gitlab::GitlabImport::ProjectCreator)
.to receive(:new).with(gitlab_repo, user.namespace, user, access_params)
- .and_return(double(execute: true))
+ .and_return(double(execute: project))
- post :create, format: :js
+ post :create, format: :json
end
end
end
- context 'user has chosen an existing nested namespace for the project' do
+ context 'user has chosen an existing nested namespace for the project', :postgresql do
let(:parent_namespace) { create(:group, name: 'foo', owner: user) }
let(:nested_namespace) { create(:group, name: 'bar', parent: parent_namespace) }
@@ -185,64 +206,78 @@ describe Import::GitlabController do
it 'takes the selected namespace and name' do
expect(Gitlab::GitlabImport::ProjectCreator)
.to receive(:new).with(gitlab_repo, nested_namespace, user, access_params)
- .and_return(double(execute: true))
+ .and_return(double(execute: project))
- post :create, { target_namespace: nested_namespace.full_path, format: :js }
+ post :create, { target_namespace: nested_namespace.full_path, format: :json }
end
end
- context 'user has chosen a non-existent nested namespaces for the project' do
+ context 'user has chosen a non-existent nested namespaces for the project', :postgresql do
let(:test_name) { 'test_name' }
it 'takes the selected namespace and name' do
expect(Gitlab::GitlabImport::ProjectCreator)
.to receive(:new).with(gitlab_repo, kind_of(Namespace), user, access_params)
- .and_return(double(execute: true))
+ .and_return(double(execute: project))
- post :create, { target_namespace: 'foo/bar', format: :js }
+ post :create, { target_namespace: 'foo/bar', format: :json }
end
it 'creates the namespaces' do
allow(Gitlab::GitlabImport::ProjectCreator)
.to receive(:new).with(gitlab_repo, kind_of(Namespace), user, access_params)
- .and_return(double(execute: true))
+ .and_return(double(execute: project))
- expect { post :create, { target_namespace: 'foo/bar', format: :js } }
+ expect { post :create, { target_namespace: 'foo/bar', format: :json } }
.to change { Namespace.count }.by(2)
end
it 'new namespace has the right parent' do
allow(Gitlab::GitlabImport::ProjectCreator)
.to receive(:new).with(gitlab_repo, kind_of(Namespace), user, access_params)
- .and_return(double(execute: true))
+ .and_return(double(execute: project))
- post :create, { target_namespace: 'foo/bar', format: :js }
+ post :create, { target_namespace: 'foo/bar', format: :json }
expect(Namespace.find_by_path_or_name('bar').parent.path).to eq('foo')
end
end
- context 'user has chosen existent and non-existent nested namespaces and name for the project' do
+ context 'user has chosen existent and non-existent nested namespaces and name for the project', :postgresql do
let(:test_name) { 'test_name' }
let!(:parent_namespace) { create(:group, name: 'foo', owner: user) }
+ before do
+ parent_namespace.add_owner(user)
+ end
+
it 'takes the selected namespace and name' do
expect(Gitlab::GitlabImport::ProjectCreator)
.to receive(:new).with(gitlab_repo, kind_of(Namespace), user, access_params)
- .and_return(double(execute: true))
+ .and_return(double(execute: project))
- post :create, { target_namespace: 'foo/foobar/bar', format: :js }
+ post :create, { target_namespace: 'foo/foobar/bar', format: :json }
end
it 'creates the namespaces' do
allow(Gitlab::GitlabImport::ProjectCreator)
.to receive(:new).with(gitlab_repo, kind_of(Namespace), user, access_params)
- .and_return(double(execute: true))
+ .and_return(double(execute: project))
- expect { post :create, { target_namespace: 'foo/foobar/bar', format: :js } }
+ expect { post :create, { target_namespace: 'foo/foobar/bar', format: :json } }
.to change { Namespace.count }.by(2)
end
end
+
+ context 'when user can not create projects in the chosen namespace' do
+ it 'returns 422 response' do
+ other_namespace = create(:group, name: 'other_namespace')
+
+ post :create, { target_namespace: other_namespace.name, format: :json }
+
+ expect(response).to have_gitlab_http_status(422)
+ end
+ end
end
end
end
diff --git a/spec/controllers/profiles_controller_spec.rb b/spec/controllers/profiles_controller_spec.rb
index d380978b86e..03cbbb21e62 100644
--- a/spec/controllers/profiles_controller_spec.rb
+++ b/spec/controllers/profiles_controller_spec.rb
@@ -69,9 +69,8 @@ describe ProfilesController, :request_store do
describe 'PUT update_username' do
let(:namespace) { user.namespace }
- let(:project) { create(:project_empty_repo, namespace: namespace) }
let(:gitlab_shell) { Gitlab::Shell.new }
- let(:new_username) { 'renamedtosomethingelse' }
+ let(:new_username) { generate(:username) }
it 'allows username change' do
sign_in(user)
@@ -85,16 +84,39 @@ describe ProfilesController, :request_store do
expect(user.username).to eq(new_username)
end
- it 'moves dependent projects to new namespace' do
- sign_in(user)
+ context 'with legacy storage' do
+ it 'moves dependent projects to new namespace' do
+ project = create(:project_empty_repo, :legacy_storage, namespace: namespace)
- put :update_username,
- user: { username: new_username }
+ sign_in(user)
- user.reload
+ put :update_username,
+ user: { username: new_username }
- expect(response.status).to eq(302)
- expect(gitlab_shell.exists?(project.repository_storage_path, "#{new_username}/#{project.path}.git")).to be_truthy
+ user.reload
+
+ expect(response.status).to eq(302)
+ expect(gitlab_shell.exists?(project.repository_storage_path, "#{new_username}/#{project.path}.git")).to be_truthy
+ end
+ end
+
+ context 'with hashed storage' do
+ it 'keeps repository location unchanged on disk' do
+ project = create(:project_empty_repo, namespace: namespace)
+
+ before_disk_path = project.disk_path
+
+ sign_in(user)
+
+ put :update_username,
+ user: { username: new_username }
+
+ user.reload
+
+ expect(response.status).to eq(302)
+ expect(gitlab_shell.exists?(project.repository_storage_path, "#{project.disk_path}.git")).to be_truthy
+ expect(before_disk_path).to eq(project.disk_path)
+ end
end
end
end
diff --git a/spec/controllers/projects_controller_spec.rb b/spec/controllers/projects_controller_spec.rb
index 5202ffdd8bb..994da3cd159 100644
--- a/spec/controllers/projects_controller_spec.rb
+++ b/spec/controllers/projects_controller_spec.rb
@@ -288,62 +288,82 @@ describe ProjectsController do
render_views
let(:admin) { create(:admin) }
- let(:project) { create(:project, :repository) }
before do
sign_in(admin)
end
- context 'when only renaming a project path' do
- it "sets the repository to the right path after a rename" do
- expect { update_project path: 'renamed_path' }
- .to change { project.reload.path }
+ shared_examples_for 'updating a project' do
+ context 'when only renaming a project path' do
+ it "sets the repository to the right path after a rename" do
+ original_repository_path = project.repository.path
- expect(project.path).to include 'renamed_path'
- expect(assigns(:repository).path).to include project.path
- expect(response).to have_gitlab_http_status(302)
- end
- end
+ expect { update_project path: 'renamed_path' }
+ .to change { project.reload.path }
+ expect(project.path).to include 'renamed_path'
- context 'when project has container repositories with tags' do
- before do
- stub_container_registry_config(enabled: true)
- stub_container_registry_tags(repository: /image/, tags: %w[rc1])
- create(:container_repository, project: project, name: :image)
+ if project.hashed_storage?(:repository)
+ expect(assigns(:repository).path).to eq(original_repository_path)
+ else
+ expect(assigns(:repository).path).to include(project.path)
+ end
+
+ expect(response).to have_gitlab_http_status(302)
+ end
end
- it 'does not allow to rename the project' do
- expect { update_project path: 'renamed_path' }
- .not_to change { project.reload.path }
+ context 'when project has container repositories with tags' do
+ before do
+ stub_container_registry_config(enabled: true)
+ stub_container_registry_tags(repository: /image/, tags: %w[rc1])
+ create(:container_repository, project: project, name: :image)
+ end
- expect(controller).to set_flash[:alert].to(/container registry tags/)
- expect(response).to have_gitlab_http_status(200)
+ it 'does not allow to rename the project' do
+ expect { update_project path: 'renamed_path' }
+ .not_to change { project.reload.path }
+
+ expect(controller).to set_flash[:alert].to(/container registry tags/)
+ expect(response).to have_gitlab_http_status(200)
+ end
end
- end
- it 'updates Fast Forward Merge attributes' do
- controller.instance_variable_set(:@project, project)
+ it 'updates Fast Forward Merge attributes' do
+ controller.instance_variable_set(:@project, project)
- params = {
- merge_method: :ff
- }
+ params = {
+ merge_method: :ff
+ }
- put :update,
- namespace_id: project.namespace,
- id: project.id,
- project: params
+ put :update,
+ namespace_id: project.namespace,
+ id: project.id,
+ project: params
- expect(response).to have_gitlab_http_status(302)
- params.each do |param, value|
- expect(project.public_send(param)).to eq(value)
+ expect(response).to have_gitlab_http_status(302)
+ params.each do |param, value|
+ expect(project.public_send(param)).to eq(value)
+ end
+ end
+
+ def update_project(**parameters)
+ put :update,
+ namespace_id: project.namespace.path,
+ id: project.path,
+ project: parameters
end
end
- def update_project(**parameters)
- put :update,
- namespace_id: project.namespace.path,
- id: project.path,
- project: parameters
+ context 'hashed storage' do
+ let(:project) { create(:project, :repository) }
+
+ it_behaves_like 'updating a project'
+ end
+
+ context 'legacy storage' do
+ let(:project) { create(:project, :repository, :legacy_storage) }
+
+ it_behaves_like 'updating a project'
end
end
diff --git a/spec/factories/projects.rb b/spec/factories/projects.rb
index f92b307fee4..1761b6e2a3b 100644
--- a/spec/factories/projects.rb
+++ b/spec/factories/projects.rb
@@ -81,8 +81,10 @@ FactoryBot.define do
archived true
end
- trait :hashed do
- storage_version Project::LATEST_STORAGE_VERSION
+ storage_version Project::LATEST_STORAGE_VERSION
+
+ trait :legacy_storage do
+ storage_version nil
end
trait :access_requestable do
diff --git a/spec/features/ci_lint_spec.rb b/spec/features/ci_lint_spec.rb
index 9bc23baf6cf..b1dceec9da8 100644
--- a/spec/features/ci_lint_spec.rb
+++ b/spec/features/ci_lint_spec.rb
@@ -3,16 +3,19 @@ require 'spec_helper'
describe 'CI Lint', :js do
before do
sign_in(create(:user))
+
+ visit ci_lint_path
+ find('#ci-editor')
+ execute_script("ace.edit('ci-editor').setValue(#{yaml_content.to_json});")
+
+ # Ace editor updates a hidden textarea and it happens asynchronously
+ wait_for('YAML content') do
+ find('.ace_content').text.present?
+ end
end
describe 'YAML parsing' do
before do
- visit ci_lint_path
- # Ace editor updates a hidden textarea and it happens asynchronously
- # `sleep 0.1` is actually needed here because of this
- find('#ci-editor')
- execute_script("ace.edit('ci-editor').setValue(" + yaml_content.to_json + ");")
- sleep 0.1
click_on 'Validate'
end
@@ -32,11 +35,10 @@ describe 'CI Lint', :js do
end
context 'YAML is incorrect' do
- let(:yaml_content) { '' }
+ let(:yaml_content) { 'value: cannot have :' }
it 'displays information about an error' do
expect(page).to have_content('Status: syntax is incorrect')
- expect(page).to have_content('Error: Please provide content of .gitlab-ci.yml')
end
end
@@ -48,4 +50,20 @@ describe 'CI Lint', :js do
end
end
end
+
+ describe 'YAML clearing' do
+ before do
+ click_on 'Clear'
+ end
+
+ context 'YAML is present' do
+ let(:yaml_content) do
+ File.read(Rails.root.join('spec/support/gitlab_stubs/gitlab_ci.yml'))
+ end
+
+ it 'YAML content is cleared' do
+ expect(page).to have_field('content', with: '', visible: false, type: 'textarea')
+ end
+ end
+ end
end
diff --git a/spec/features/copy_as_gfm_spec.rb b/spec/features/markdown/copy_as_gfm_spec.rb
index f82ed6300cc..f82ed6300cc 100644
--- a/spec/features/copy_as_gfm_spec.rb
+++ b/spec/features/markdown/copy_as_gfm_spec.rb
diff --git a/spec/features/gitlab_flavored_markdown_spec.rb b/spec/features/markdown/gitlab_flavored_markdown_spec.rb
index 3c2186b3598..3c2186b3598 100644
--- a/spec/features/gitlab_flavored_markdown_spec.rb
+++ b/spec/features/markdown/gitlab_flavored_markdown_spec.rb
diff --git a/spec/features/markdown_spec.rb b/spec/features/markdown/markdown_spec.rb
index f13d78d24e3..f13d78d24e3 100644
--- a/spec/features/markdown_spec.rb
+++ b/spec/features/markdown/markdown_spec.rb
diff --git a/spec/features/markdown/math_spec.rb b/spec/features/markdown/math_spec.rb
new file mode 100644
index 00000000000..6a23d6b78ab
--- /dev/null
+++ b/spec/features/markdown/math_spec.rb
@@ -0,0 +1,22 @@
+require 'spec_helper'
+
+describe 'Math rendering', :js do
+ it 'renders inline and display math correctly' do
+ description = <<~MATH
+ This math is inline $`a^2+b^2=c^2`$.
+
+ This is on a separate line
+ ```math
+ a^2+b^2=c^2
+ ```
+ MATH
+
+ project = create(:project, :public)
+ issue = create(:issue, project: project, description: description)
+
+ visit project_issue_path(project, issue)
+
+ expect(page).to have_selector('.katex .mord.mathit', text: 'b')
+ expect(page).to have_selector('.katex-display .mord.mathit', text: 'b')
+ end
+end
diff --git a/spec/features/markdown/mermaid_spec.rb b/spec/features/markdown/mermaid_spec.rb
new file mode 100644
index 00000000000..a25d701ee35
--- /dev/null
+++ b/spec/features/markdown/mermaid_spec.rb
@@ -0,0 +1,24 @@
+require 'spec_helper'
+
+describe 'Mermaid rendering', :js do
+ it 'renders Mermaid diagrams correctly' do
+ description = <<~MERMAID
+ ```mermaid
+ graph TD;
+ A-->B;
+ A-->C;
+ B-->D;
+ C-->D;
+ ```
+ MERMAID
+
+ project = create(:project, :public)
+ issue = create(:issue, project: project, description: description)
+
+ visit project_issue_path(project, issue)
+
+ %w[A B C D].each do |label|
+ expect(page).to have_selector('svg foreignObject', text: label)
+ end
+ end
+end
diff --git a/spec/features/projects/import_export/namespace_export_file_spec.rb b/spec/features/projects/import_export/namespace_export_file_spec.rb
index c1fccf4a40b..7d056b0c140 100644
--- a/spec/features/projects/import_export/namespace_export_file_spec.rb
+++ b/spec/features/projects/import_export/namespace_export_file_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-feature 'Import/Export - Namespace export file cleanup', :js do
+describe 'Import/Export - Namespace export file cleanup', :js do
let(:export_path) { Dir.mktmpdir('namespace_export_file_spec') }
before do
@@ -42,13 +42,13 @@ feature 'Import/Export - Namespace export file cleanup', :js do
end
describe 'legacy storage' do
- let(:project) { create(:project) }
+ let(:project) { create(:project, :legacy_storage) }
it_behaves_like 'handling project exports on namespace change'
end
describe 'hashed storage' do
- let(:project) { create(:project, :hashed) }
+ let(:project) { create(:project) }
it_behaves_like 'handling project exports on namespace change'
end
diff --git a/spec/finders/snippets_finder_spec.rb b/spec/finders/snippets_finder_spec.rb
index 0a018d2b417..54a07eccaba 100644
--- a/spec/finders/snippets_finder_spec.rb
+++ b/spec/finders/snippets_finder_spec.rb
@@ -1,57 +1,8 @@
require 'spec_helper'
describe SnippetsFinder do
- let(:user) { create :user }
- let(:user1) { create :user }
- let(:group) { create :group, :public }
-
- let(:project1) { create(:project, :public, group: group) }
- let(:project2) { create(:project, :private, group: group) }
-
- context 'all snippets visible to a user' do
- let!(:snippet1) { create(:personal_snippet, :private) }
- let!(:snippet2) { create(:personal_snippet, :internal) }
- let!(:snippet3) { create(:personal_snippet, :public) }
- let!(:project_snippet1) { create(:project_snippet, :private) }
- let!(:project_snippet2) { create(:project_snippet, :internal) }
- let!(:project_snippet3) { create(:project_snippet, :public) }
-
- it "returns all private and internal snippets" do
- snippets = described_class.new(user, scope: :all).execute
- expect(snippets).to include(snippet2, snippet3, project_snippet2, project_snippet3)
- expect(snippets).not_to include(snippet1, project_snippet1)
- end
-
- it "returns all public snippets" do
- snippets = described_class.new(nil, scope: :all).execute
- expect(snippets).to include(snippet3, project_snippet3)
- expect(snippets).not_to include(snippet1, snippet2, project_snippet1, project_snippet2)
- end
-
- it "returns all public and internal snippets for normal user" do
- snippets = described_class.new(user).execute
-
- expect(snippets).to include(snippet2, snippet3, project_snippet2, project_snippet3)
- expect(snippets).not_to include(snippet1, project_snippet1)
- end
-
- it "returns all public snippets for non authorized user" do
- snippets = described_class.new(nil).execute
-
- expect(snippets).to include(snippet3, project_snippet3)
- expect(snippets).not_to include(snippet1, snippet2, project_snippet1, project_snippet2)
- end
-
- it "returns all public and authored snippets for external user" do
- external_user = create(:user, :external)
- authored_snippet = create(:personal_snippet, :internal, author: external_user)
-
- snippets = described_class.new(external_user).execute
-
- expect(snippets).to include(snippet3, project_snippet3, authored_snippet)
- expect(snippets).not_to include(snippet1, snippet2, project_snippet1, project_snippet2)
- end
- end
+ include Gitlab::Allowable
+ using RSpec::Parameterized::TableSyntax
context 'filter by visibility' do
let!(:snippet1) { create(:personal_snippet, :private) }
@@ -67,6 +18,7 @@ describe SnippetsFinder do
end
context 'filter by scope' do
+ let(:user) { create :user }
let!(:snippet1) { create(:personal_snippet, :private, author: user) }
let!(:snippet2) { create(:personal_snippet, :internal, author: user) }
let!(:snippet3) { create(:personal_snippet, :public, author: user) }
@@ -84,7 +36,7 @@ describe SnippetsFinder do
expect(snippets).not_to include(snippet2, snippet3)
end
- it "returns all snippets for 'are_interna;' scope" do
+ it "returns all snippets for 'are_internal' scope" do
snippets = described_class.new(user, scope: :are_internal).execute
expect(snippets).to include(snippet2)
@@ -100,6 +52,8 @@ describe SnippetsFinder do
end
context 'filter by author' do
+ let(:user) { create :user }
+ let(:user1) { create :user }
let!(:snippet1) { create(:personal_snippet, :private, author: user) }
let!(:snippet2) { create(:personal_snippet, :internal, author: user) }
let!(:snippet3) { create(:personal_snippet, :public, author: user) }
@@ -147,6 +101,10 @@ describe SnippetsFinder do
end
context 'filter by project' do
+ let(:user) { create :user }
+ let(:group) { create :group, :public }
+ let(:project1) { create(:project, :public, group: group) }
+
before do
@snippet1 = create(:project_snippet, :private, project: project1)
@snippet2 = create(:project_snippet, :internal, project: project1)
@@ -203,4 +161,9 @@ describe SnippetsFinder do
expect(snippets).to include(@snippet1)
end
end
+
+ describe "#execute" do
+ # Snippet visibility scenarios are included in more details in spec/support/snippet_visibility.rb
+ include_examples 'snippet visibility', described_class
+ end
end
diff --git a/spec/javascripts/ci_variable_list/ci_variable_list_spec.js b/spec/javascripts/ci_variable_list/ci_variable_list_spec.js
index 6ab7b50e035..8acb346901f 100644
--- a/spec/javascripts/ci_variable_list/ci_variable_list_spec.js
+++ b/spec/javascripts/ci_variable_list/ci_variable_list_spec.js
@@ -126,7 +126,7 @@ describe('VariableList', () => {
// Check for the correct default in the new row
const $protectedInput = $wrapper.find('.js-row:last-child').find('.js-ci-variable-input-protected');
- expect($protectedInput.val()).toBe('true');
+ expect($protectedInput.val()).toBe('false');
})
.then(done)
.catch(done.fail);
diff --git a/spec/javascripts/gl_form_spec.js b/spec/javascripts/gl_form_spec.js
index 5a8009e57fd..9c1fc0fda9e 100644
--- a/spec/javascripts/gl_form_spec.js
+++ b/spec/javascripts/gl_form_spec.js
@@ -1,10 +1,8 @@
-import Autosize from 'autosize';
+import autosize from 'autosize';
import GLForm from '~/gl_form';
import '~/lib/utils/text_utility';
import '~/lib/utils/common_utils';
-window.autosize = Autosize;
-
describe('GLForm', () => {
describe('when instantiated', function () {
beforeEach((done) => {
@@ -13,14 +11,12 @@ describe('GLForm', () => {
spyOn($.prototype, 'off').and.returnValue(this.textarea);
spyOn($.prototype, 'on').and.returnValue(this.textarea);
spyOn($.prototype, 'css');
- spyOn(window, 'autosize');
- this.glForm = new GLForm(this.form);
+ this.glForm = new GLForm(this.form, false);
setTimeout(() => {
$.prototype.off.calls.reset();
$.prototype.on.calls.reset();
$.prototype.css.calls.reset();
- window.autosize.calls.reset();
done();
});
});
@@ -43,10 +39,6 @@ describe('GLForm', () => {
expect($.prototype.on).toHaveBeenCalledWith('mouseup.autosize', jasmine.any(Function));
});
- it('should autosize the textarea', () => {
- expect(window.autosize).toHaveBeenCalledWith(jasmine.any(Object));
- });
-
it('should set the resize css property to vertical', () => {
expect($.prototype.css).toHaveBeenCalledWith('resize', 'vertical');
});
@@ -74,7 +66,7 @@ describe('GLForm', () => {
spyOn($.prototype, 'data');
spyOn($.prototype, 'outerHeight').and.returnValue(200);
spyOn(window, 'outerHeight').and.returnValue(400);
- spyOn(window.autosize, 'destroy');
+ spyOn(autosize, 'destroy');
this.glForm.destroyAutosize();
});
@@ -88,7 +80,7 @@ describe('GLForm', () => {
});
it('should call autosize destroy', () => {
- expect(window.autosize.destroy).toHaveBeenCalledWith(this.textarea);
+ expect(autosize.destroy).toHaveBeenCalledWith(this.textarea);
});
it('should set the data-height attribute', () => {
@@ -107,9 +99,9 @@ describe('GLForm', () => {
it('should return undefined if the data-height equals the outerHeight', () => {
spyOn($.prototype, 'outerHeight').and.returnValue(200);
spyOn($.prototype, 'data').and.returnValue(200);
- spyOn(window.autosize, 'destroy');
+ spyOn(autosize, 'destroy');
expect(this.glForm.destroyAutosize()).toBeUndefined();
- expect(window.autosize.destroy).not.toHaveBeenCalled();
+ expect(autosize.destroy).not.toHaveBeenCalled();
});
});
});
diff --git a/spec/javascripts/gpg_badges_spec.js b/spec/javascripts/gpg_badges_spec.js
index 7a826487bf9..5decb5e6bbd 100644
--- a/spec/javascripts/gpg_badges_spec.js
+++ b/spec/javascripts/gpg_badges_spec.js
@@ -1,6 +1,9 @@
+import MockAdapter from 'axios-mock-adapter';
+import axios from '~/lib/utils/axios_utils';
import GpgBadges from '~/gpg_badges';
describe('GpgBadges', () => {
+ let mock;
const dummyCommitSha = 'n0m0rec0ffee';
const dummyBadgeHtml = 'dummy html';
const dummyResponse = {
@@ -11,38 +14,43 @@ describe('GpgBadges', () => {
};
beforeEach(() => {
+ mock = new MockAdapter(axios);
setFixtures(`
+ <form
+ class="commits-search-form" data-signatures-path="/hello" action="/hello"
+ method="get">
+ <input name="utf8" type="hidden" value="✓">
+ <input type="search" name="search" id="commits-search"class="form-control search-text-input input-short">
+ </form>
<div class="parent-container">
<div class="js-loading-gpg-badge" data-commit-sha="${dummyCommitSha}"></div>
</div>
`);
});
- it('displays a loading spinner', () => {
- spyOn($, 'get').and.returnValue({
- done() {
- // intentionally left blank
- },
- });
+ afterEach(() => {
+ mock.restore();
+ });
- GpgBadges.fetch();
+ it('displays a loading spinner', (done) => {
+ mock.onGet('/hello').reply(200);
- expect(document.querySelector('.js-loading-gpg-badge:empty')).toBe(null);
- const spinners = document.querySelectorAll('.js-loading-gpg-badge i.fa.fa-spinner.fa-spin');
- expect(spinners.length).toBe(1);
+ GpgBadges.fetch().then(() => {
+ expect(document.querySelector('.js-loading-gpg-badge:empty')).toBe(null);
+ const spinners = document.querySelectorAll('.js-loading-gpg-badge i.fa.fa-spinner.fa-spin');
+ expect(spinners.length).toBe(1);
+ done();
+ }).catch(done.fail);
});
- it('replaces the loading spinner', () => {
- spyOn($, 'get').and.returnValue({
- done(callback) {
- callback(dummyResponse);
- },
- });
-
- GpgBadges.fetch();
+ it('replaces the loading spinner', (done) => {
+ mock.onGet('/hello').reply(200, dummyResponse);
- expect(document.querySelector('.js-loading-gpg-badge')).toBe(null);
- const parentContainer = document.querySelector('.parent-container');
- expect(parentContainer.innerHTML.trim()).toEqual(dummyBadgeHtml);
+ GpgBadges.fetch().then(() => {
+ expect(document.querySelector('.js-loading-gpg-badge')).toBe(null);
+ const parentContainer = document.querySelector('.parent-container');
+ expect(parentContainer.innerHTML.trim()).toEqual(dummyBadgeHtml);
+ done();
+ }).catch(done.fail);
});
});
diff --git a/spec/javascripts/importer_status_spec.js b/spec/javascripts/importer_status_spec.js
new file mode 100644
index 00000000000..bb49c576e91
--- /dev/null
+++ b/spec/javascripts/importer_status_spec.js
@@ -0,0 +1,47 @@
+import { ImporterStatus } from '~/importer_status';
+import axios from '~/lib/utils/axios_utils';
+import MockAdapter from 'axios-mock-adapter';
+
+describe('Importer Status', () => {
+ describe('addToImport', () => {
+ let instance;
+ let mock;
+ const importUrl = '/import_url';
+
+ beforeEach(() => {
+ setFixtures(`
+ <tr id="repo_123">
+ <td class="import-target"></td>
+ <td class="import-actions job-status">
+ <button name="button" type="submit" class="btn btn-import js-add-to-import">
+ </button>
+ </td>
+ </tr>
+ `);
+ spyOn(ImporterStatus.prototype, 'initStatusPage').and.callFake(() => {});
+ spyOn(ImporterStatus.prototype, 'setAutoUpdate').and.callFake(() => {});
+ instance = new ImporterStatus('', importUrl);
+ mock = new MockAdapter(axios);
+ });
+
+ afterEach(() => {
+ mock.restore();
+ });
+
+ it('sets table row to active after post request', (done) => {
+ mock.onPost(importUrl).reply(200, {
+ id: 1,
+ full_path: '/full_path',
+ });
+
+ instance.addToImport({
+ currentTarget: document.querySelector('.js-add-to-import'),
+ })
+ .then(() => {
+ expect(document.querySelector('tr').classList.contains('active')).toEqual(true);
+ done();
+ })
+ .catch(done.fail);
+ });
+ });
+});
diff --git a/spec/javascripts/issuable_time_tracker_spec.js b/spec/javascripts/issuable_time_tracker_spec.js
index 8ff93c4f918..365e9fe6a4b 100644
--- a/spec/javascripts/issuable_time_tracker_spec.js
+++ b/spec/javascripts/issuable_time_tracker_spec.js
@@ -2,7 +2,7 @@
import Vue from 'vue';
-import timeTracker from '~/sidebar/components/time_tracking/time_tracker';
+import timeTracker from '~/sidebar/components/time_tracking/time_tracker.vue';
function initTimeTrackingComponent(opts) {
setFixtures(`
diff --git a/spec/javascripts/vue_mr_widget/components/states/mr_widget_missing_branch_spec.js b/spec/javascripts/vue_mr_widget/components/states/mr_widget_missing_branch_spec.js
index 720effb5c1c..3d7f4abd420 100644
--- a/spec/javascripts/vue_mr_widget/components/states/mr_widget_missing_branch_spec.js
+++ b/spec/javascripts/vue_mr_widget/components/states/mr_widget_missing_branch_spec.js
@@ -1,38 +1,22 @@
import Vue from 'vue';
-import missingBranchComponent from '~/vue_merge_request_widget/components/states/mr_widget_missing_branch';
-
-const createComponent = () => {
- const Component = Vue.extend(missingBranchComponent);
- const mr = {
- sourceBranchRemoved: true,
- };
-
- return new Component({
- el: document.createElement('div'),
- propsData: { mr },
- });
-};
+import missingBranchComponent from '~/vue_merge_request_widget/components/states/mr_widget_missing_branch.vue';
+import mountComponent from '../../../helpers/vue_mount_component_helper';
describe('MRWidgetMissingBranch', () => {
- describe('props', () => {
- it('should have props', () => {
- const mrProp = missingBranchComponent.props.mr;
+ let vm;
- expect(mrProp.type instanceof Object).toBeTruthy();
- expect(mrProp.required).toBeTruthy();
- });
+ beforeEach(() => {
+ const Component = Vue.extend(missingBranchComponent);
+ vm = mountComponent(Component, { mr: { sourceBranchRemoved: true } });
});
- describe('components', () => {
- it('should have components added', () => {
- expect(missingBranchComponent.components['mr-widget-merge-help']).toBeDefined();
- });
+ afterEach(() => {
+ vm.$destroy();
});
describe('computed', () => {
describe('missingBranchName', () => {
it('should return proper branch name', () => {
- const vm = createComponent();
expect(vm.missingBranchName).toEqual('source');
vm.mr.sourceBranchRemoved = false;
@@ -43,7 +27,7 @@ describe('MRWidgetMissingBranch', () => {
describe('template', () => {
it('should have correct elements', () => {
- const el = createComponent().$el;
+ const el = vm.$el;
const content = el.textContent.replace(/\n(\s)+/g, ' ').trim();
expect(el.classList.contains('mr-widget-body')).toBeTruthy();
diff --git a/spec/javascripts/vue_shared/components/confirmation_input_spec.js b/spec/javascripts/vue_shared/components/confirmation_input_spec.js
deleted file mode 100644
index a6a12614e77..00000000000
--- a/spec/javascripts/vue_shared/components/confirmation_input_spec.js
+++ /dev/null
@@ -1,63 +0,0 @@
-import Vue from 'vue';
-import confirmationInput from '~/vue_shared/components/confirmation_input.vue';
-import mountComponent from '../../helpers/vue_mount_component_helper';
-
-describe('Confirmation input component', () => {
- const Component = Vue.extend(confirmationInput);
- const props = {
- inputId: 'dummy-id',
- confirmationKey: 'confirmation-key',
- confirmationValue: 'confirmation-value',
- };
- let vm;
-
- afterEach(() => {
- vm.$destroy();
- });
-
- describe('props', () => {
- beforeEach(() => {
- vm = mountComponent(Component, props);
- });
-
- it('sets id of the input field to inputId', () => {
- expect(vm.$refs.enteredValue.id).toBe(props.inputId);
- });
-
- it('sets name of the input field to confirmationKey', () => {
- expect(vm.$refs.enteredValue.name).toBe(props.confirmationKey);
- });
- });
-
- describe('computed', () => {
- describe('inputLabel', () => {
- it('escapes confirmationValue by default', () => {
- vm = mountComponent(Component, { ...props, confirmationValue: 'n<e></e>ds escap"ng' });
- expect(vm.inputLabel).toBe('Type <code>n&lt;e&gt;&lt;/e&gt;ds escap&quot;ng</code> to confirm:');
- });
-
- it('does not escape confirmationValue if escapeValue is false', () => {
- vm = mountComponent(Component, { ...props, confirmationValue: 'n<e></e>ds escap"ng', shouldEscapeConfirmationValue: false });
- expect(vm.inputLabel).toBe('Type <code>n<e></e>ds escap"ng</code> to confirm:');
- });
- });
- });
-
- describe('methods', () => {
- describe('hasCorrectValue', () => {
- beforeEach(() => {
- vm = mountComponent(Component, props);
- });
-
- it('returns false if entered value is incorrect', () => {
- vm.$refs.enteredValue.value = 'incorrect';
- expect(vm.hasCorrectValue()).toBe(false);
- });
-
- it('returns true if entered value is correct', () => {
- vm.$refs.enteredValue.value = props.confirmationValue;
- expect(vm.hasCorrectValue()).toBe(true);
- });
- });
- });
-});
diff --git a/spec/lib/backup/repository_spec.rb b/spec/lib/backup/repository_spec.rb
index 6ee3d531d6e..f7b1a61f4f8 100644
--- a/spec/lib/backup/repository_spec.rb
+++ b/spec/lib/backup/repository_spec.rb
@@ -33,10 +33,22 @@ describe Backup::Repository do
allow(Gitlab::Popen).to receive(:popen).and_return(['error', 1])
end
- it 'shows the appropriate error' do
- described_class.new.restore
+ context 'hashed storage' do
+ it 'shows the appropriate error' do
+ described_class.new.restore
- expect(progress).to have_received(:puts).with("Ignoring error on #{project.full_path} - error")
+ expect(progress).to have_received(:puts).with("Ignoring error on #{project.full_path} (#{project.disk_path}) - error")
+ end
+ end
+
+ context 'legacy storage' do
+ let!(:project) { create(:project, :legacy_storage) }
+
+ it 'shows the appropriate error' do
+ described_class.new.restore
+
+ expect(progress).to have_received(:puts).with("Ignoring error on #{project.full_path} - error")
+ end
end
end
end
diff --git a/spec/lib/banzai/filter/syntax_highlight_filter_spec.rb b/spec/lib/banzai/filter/syntax_highlight_filter_spec.rb
index 9f2efa05a01..ef52c572898 100644
--- a/spec/lib/banzai/filter/syntax_highlight_filter_spec.rb
+++ b/spec/lib/banzai/filter/syntax_highlight_filter_spec.rb
@@ -3,35 +3,86 @@ require 'spec_helper'
describe Banzai::Filter::SyntaxHighlightFilter do
include FilterSpecHelper
+ shared_examples "XSS prevention" do |lang|
+ it "escapes HTML tags" do
+ # This is how a script tag inside a code block is presented to this filter
+ # after Markdown rendering.
+ result = filter(%{<pre lang="#{lang}"><code>&lt;script&gt;alert(1)&lt;/script&gt;</code></pre>})
+
+ expect(result.to_html).not_to include("<script>alert(1)</script>")
+ expect(result.to_html).to include("alert(1)")
+ end
+ end
+
context "when no language is specified" do
it "highlights as plaintext" do
result = filter('<pre><code>def fun end</code></pre>')
+
expect(result.to_html).to eq('<pre class="code highlight js-syntax-highlight plaintext" lang="plaintext" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">def fun end</span></code></pre>')
end
+
+ include_examples "XSS prevention", ""
end
context "when a valid language is specified" do
it "highlights as that language" do
result = filter('<pre><code lang="ruby">def fun end</code></pre>')
+
expect(result.to_html).to eq('<pre class="code highlight js-syntax-highlight ruby" lang="ruby" v-pre="true"><code><span id="LC1" class="line" lang="ruby"><span class="k">def</span> <span class="nf">fun</span> <span class="k">end</span></span></code></pre>')
end
+
+ include_examples "XSS prevention", "ruby"
end
context "when an invalid language is specified" do
it "highlights as plaintext" do
result = filter('<pre><code lang="gnuplot">This is a test</code></pre>')
+
expect(result.to_html).to eq('<pre class="code highlight js-syntax-highlight plaintext" lang="plaintext" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">This is a test</span></code></pre>')
end
+
+ include_examples "XSS prevention", "gnuplot"
end
- context "when Rouge formatting fails" do
+ context "languages that should be passed through" do
+ %w(math mermaid plantuml).each do |lang|
+ context "when #{lang} is specified" do
+ it "highlights as plaintext but with the correct language attribute and class" do
+ result = filter(%{<pre><code lang="#{lang}">This is a test</code></pre>})
+
+ expect(result.to_html).to eq(%{<pre class="code highlight js-syntax-highlight #{lang}" lang="#{lang}" v-pre="true"><code><span id="LC1" class="line" lang="#{lang}">This is a test</span></code></pre>})
+ end
+
+ include_examples "XSS prevention", lang
+ end
+ end
+ end
+
+ context "when Rouge lexing fails" do
before do
- allow_any_instance_of(Rouge::Formatter).to receive(:format).and_raise(StandardError)
+ allow_any_instance_of(Rouge::Lexers::Ruby).to receive(:stream_tokens).and_raise(StandardError)
end
it "highlights as plaintext" do
result = filter('<pre><code lang="ruby">This is a test</code></pre>')
- expect(result.to_html).to eq('<pre class="code highlight js-syntax-highlight" lang="" v-pre="true"><code>This is a test</code></pre>')
+
+ expect(result.to_html).to eq('<pre class="code highlight js-syntax-highlight" lang="" v-pre="true"><code><span id="LC1" class="line" lang="">This is a test</span></code></pre>')
+ end
+
+ include_examples "XSS prevention", "ruby"
+ end
+
+ context "when Rouge lexing fails after a retry" do
+ before do
+ allow_any_instance_of(Rouge::Lexers::PlainText).to receive(:stream_tokens).and_raise(StandardError)
+ end
+
+ it "does not add highlighting classes" do
+ result = filter('<pre><code>This is a test</code></pre>')
+
+ expect(result.to_html).to eq('<pre><code>This is a test</code></pre>')
end
+
+ include_examples "XSS prevention", "ruby"
end
end
diff --git a/spec/lib/gitlab/background_migration/populate_untracked_uploads_spec.rb b/spec/lib/gitlab/background_migration/populate_untracked_uploads_spec.rb
index be45c00dfe6..8590522f3ef 100644
--- a/spec/lib/gitlab/background_migration/populate_untracked_uploads_spec.rb
+++ b/spec/lib/gitlab/background_migration/populate_untracked_uploads_spec.rb
@@ -23,8 +23,8 @@ describe Gitlab::BackgroundMigration::PopulateUntrackedUploads, :sidekiq do
let!(:appearance) { create_or_update_appearance(logo: uploaded_file, header_logo: uploaded_file) }
let!(:user1) { create(:user, :with_avatar) }
let!(:user2) { create(:user, :with_avatar) }
- let!(:project1) { create(:project, :with_avatar) }
- let!(:project2) { create(:project, :with_avatar) }
+ let!(:project1) { create(:project, :legacy_storage, :with_avatar) }
+ let!(:project2) { create(:project, :legacy_storage, :with_avatar) }
before do
UploadService.new(project1, uploaded_file, FileUploader).execute # Markdown upload
@@ -48,7 +48,7 @@ describe Gitlab::BackgroundMigration::PopulateUntrackedUploads, :sidekiq do
it 'adds untracked files to the uploads table' do
expect do
- subject.perform(1, untracked_files_for_uploads.last.id)
+ subject.perform(1, untracked_files_for_uploads.reorder(:id).last.id)
end.to change { uploads.count }.from(4).to(8)
expect(user2.uploads.count).to eq(1)
@@ -213,13 +213,13 @@ describe Gitlab::BackgroundMigration::PopulateUntrackedUploads, :sidekiq do
end
context 'for a project avatar file path' do
- let(:model) { create(:project, :with_avatar) }
+ let(:model) { create(:project, :legacy_storage, :with_avatar) }
it_behaves_like 'non_markdown_file'
end
context 'for a project Markdown attachment (notes, issues, MR descriptions) file path' do
- let(:model) { create(:project) }
+ let(:model) { create(:project, :legacy_storage) }
before do
# Upload the file
@@ -304,7 +304,7 @@ describe Gitlab::BackgroundMigration::PopulateUntrackedUploads::UntrackedFile do
context 'for a project Markdown attachment (notes, issues, MR descriptions) file path' do
it 'returns the file path relative to the project directory in uploads' do
- project = create(:project)
+ project = create(:project, :legacy_storage)
random_hex = SecureRandom.hex
assert_upload_path("/#{project.full_path}/#{random_hex}/Some file.jpg", "#{random_hex}/Some file.jpg")
@@ -357,7 +357,7 @@ describe Gitlab::BackgroundMigration::PopulateUntrackedUploads::UntrackedFile do
context 'for a project Markdown attachment (notes, issues, MR descriptions) file path' do
it 'returns FileUploader as a string' do
- project = create(:project)
+ project = create(:project, :legacy_storage)
assert_uploader("/#{project.full_path}/#{SecureRandom.hex}/Some file.jpg", 'FileUploader')
end
@@ -409,7 +409,7 @@ describe Gitlab::BackgroundMigration::PopulateUntrackedUploads::UntrackedFile do
context 'for a project Markdown attachment (notes, issues, MR descriptions) file path' do
it 'returns Project as a string' do
- project = create(:project)
+ project = create(:project, :legacy_storage)
assert_model_type("/#{project.full_path}/#{SecureRandom.hex}/Some file.jpg", 'Project')
end
@@ -461,7 +461,7 @@ describe Gitlab::BackgroundMigration::PopulateUntrackedUploads::UntrackedFile do
context 'for a project Markdown attachment (notes, issues, MR descriptions) file path' do
it 'returns the ID as a string' do
- project = create(:project)
+ project = create(:project, :legacy_storage)
assert_model_id("/#{project.full_path}/#{SecureRandom.hex}/Some file.jpg", project.id)
end
@@ -483,7 +483,7 @@ describe Gitlab::BackgroundMigration::PopulateUntrackedUploads::UntrackedFile do
end
context 'for a project avatar file path' do
- let(:project) { create(:project, avatar: uploaded_file) }
+ let(:project) { create(:project, :legacy_storage, avatar: uploaded_file) }
let(:untracked_file) { described_class.create!(path: project.uploads.first.path) }
it 'returns the file size' do
@@ -496,7 +496,7 @@ describe Gitlab::BackgroundMigration::PopulateUntrackedUploads::UntrackedFile do
end
context 'for a project Markdown attachment (notes, issues, MR descriptions) file path' do
- let(:project) { create(:project) }
+ let(:project) { create(:project, :legacy_storage) }
let(:untracked_file) { create_untracked_file("/#{project.full_path}/#{project.uploads.first.path}") }
before do
diff --git a/spec/lib/gitlab/background_migration/prepare_untracked_uploads_spec.rb b/spec/lib/gitlab/background_migration/prepare_untracked_uploads_spec.rb
index 370c2490b97..48204114ae8 100644
--- a/spec/lib/gitlab/background_migration/prepare_untracked_uploads_spec.rb
+++ b/spec/lib/gitlab/background_migration/prepare_untracked_uploads_spec.rb
@@ -77,7 +77,7 @@ describe Gitlab::BackgroundMigration::PrepareUntrackedUploads, :sidekiq do
context 'when files were uploaded before and after hashed storage was enabled' do
let!(:appearance) { create_or_update_appearance(logo: uploaded_file, header_logo: uploaded_file) }
let!(:user) { create(:user, :with_avatar) }
- let!(:project1) { create(:project, :with_avatar) }
+ let!(:project1) { create(:project, :with_avatar, :legacy_storage) }
let(:project2) { create(:project) } # instantiate after enabling hashed_storage
before do
@@ -149,7 +149,7 @@ describe Gitlab::BackgroundMigration::PrepareUntrackedUploads, :sidekiq do
context 'when files were uploaded before and after hashed storage was enabled' do
let!(:appearance) { create_or_update_appearance(logo: uploaded_file, header_logo: uploaded_file) }
let!(:user) { create(:user, :with_avatar) }
- let!(:project1) { create(:project, :with_avatar) }
+ let!(:project1) { create(:project, :with_avatar, :legacy_storage) }
let(:project2) { create(:project) } # instantiate after enabling hashed_storage
before do
diff --git a/spec/lib/gitlab/bare_repository_import/importer_spec.rb b/spec/lib/gitlab/bare_repository_import/importer_spec.rb
index f302e412a6e..eb4b9d8b12f 100644
--- a/spec/lib/gitlab/bare_repository_import/importer_spec.rb
+++ b/spec/lib/gitlab/bare_repository_import/importer_spec.rb
@@ -8,11 +8,15 @@ describe Gitlab::BareRepositoryImport::Importer, repository: true do
subject(:importer) { described_class.new(admin, bare_repository) }
before do
+ @rainbow = Rainbow.enabled
+ Rainbow.enabled = false
+
allow(described_class).to receive(:log)
end
after do
FileUtils.rm_rf(base_dir)
+ Rainbow.enabled = @rainbow
end
shared_examples 'importing a repository' do
@@ -148,7 +152,7 @@ describe Gitlab::BareRepositoryImport::Importer, repository: true do
# This is a quick way to get a valid repository instead of copying an
# existing one. Since it's not persisted, the importer will try to
# create the project.
- project = build(:project, :repository)
+ project = build(:project, :legacy_storage, :repository)
original_commit_count = project.repository.commit_count
bare_repo = Gitlab::BareRepositoryImport::Repository.new(project.repository_storage_path, project.repository.path)
diff --git a/spec/lib/gitlab/database/rename_reserved_paths_migration/v1/rename_namespaces_spec.rb b/spec/lib/gitlab/database/rename_reserved_paths_migration/v1/rename_namespaces_spec.rb
index f31475dbd71..b411aaa19da 100644
--- a/spec/lib/gitlab/database/rename_reserved_paths_migration/v1/rename_namespaces_spec.rb
+++ b/spec/lib/gitlab/database/rename_reserved_paths_migration/v1/rename_namespaces_spec.rb
@@ -94,7 +94,7 @@ describe Gitlab::Database::RenameReservedPathsMigration::V1::RenameNamespaces, :
describe '#move_repositories' do
let(:namespace) { create(:group, name: 'hello-group') }
it 'moves a project for a namespace' do
- create(:project, :repository, namespace: namespace, path: 'hello-project')
+ create(:project, :repository, :legacy_storage, namespace: namespace, path: 'hello-project')
expected_path = File.join(TestEnv.repos_path, 'bye-group', 'hello-project.git')
subject.move_repositories(namespace, 'hello-group', 'bye-group')
@@ -104,7 +104,7 @@ describe Gitlab::Database::RenameReservedPathsMigration::V1::RenameNamespaces, :
it 'moves a namespace in a subdirectory correctly' do
child_namespace = create(:group, name: 'sub-group', parent: namespace)
- create(:project, :repository, namespace: child_namespace, path: 'hello-project')
+ create(:project, :repository, :legacy_storage, namespace: child_namespace, path: 'hello-project')
expected_path = File.join(TestEnv.repos_path, 'hello-group', 'renamed-sub-group', 'hello-project.git')
@@ -115,7 +115,7 @@ describe Gitlab::Database::RenameReservedPathsMigration::V1::RenameNamespaces, :
it 'moves a parent namespace with subdirectories' do
child_namespace = create(:group, name: 'sub-group', parent: namespace)
- create(:project, :repository, namespace: child_namespace, path: 'hello-project')
+ create(:project, :repository, :legacy_storage, namespace: child_namespace, path: 'hello-project')
expected_path = File.join(TestEnv.repos_path, 'renamed-group', 'sub-group', 'hello-project.git')
subject.move_repositories(child_namespace, 'hello-group', 'renamed-group')
@@ -166,7 +166,7 @@ describe Gitlab::Database::RenameReservedPathsMigration::V1::RenameNamespaces, :
describe '#rename_namespace_dependencies' do
it "moves the the repository for a project in the namespace" do
- create(:project, :repository, namespace: namespace, path: "the-path-project")
+ create(:project, :repository, :legacy_storage, namespace: namespace, path: "the-path-project")
expected_repo = File.join(TestEnv.repos_path, "the-path0", "the-path-project.git")
subject.rename_namespace_dependencies(namespace, 'the-path', 'the-path0')
@@ -187,7 +187,7 @@ describe Gitlab::Database::RenameReservedPathsMigration::V1::RenameNamespaces, :
end
it 'invalidates the markdown cache of related projects' do
- project = create(:project, namespace: namespace, path: "the-path-project")
+ project = create(:project, :legacy_storage, namespace: namespace, path: "the-path-project")
expect(subject).to receive(:remove_cached_html_for_projects).with([project.id])
@@ -243,7 +243,7 @@ describe Gitlab::Database::RenameReservedPathsMigration::V1::RenameNamespaces, :
describe '#revert_renames', :redis do
it 'renames the routes back to the previous values' do
- project = create(:project, :repository, path: 'a-project', namespace: namespace)
+ project = create(:project, :legacy_storage, :repository, path: 'a-project', namespace: namespace)
subject.rename_namespace(namespace)
expect(subject).to receive(:perform_rename)
@@ -261,7 +261,7 @@ describe Gitlab::Database::RenameReservedPathsMigration::V1::RenameNamespaces, :
end
it 'moves the repositories back to their original place' do
- project = create(:project, :repository, path: 'a-project', namespace: namespace)
+ project = create(:project, :repository, :legacy_storage, path: 'a-project', namespace: namespace)
project.create_repository
subject.rename_namespace(namespace)
diff --git a/spec/lib/gitlab/database/rename_reserved_paths_migration/v1/rename_projects_spec.rb b/spec/lib/gitlab/database/rename_reserved_paths_migration/v1/rename_projects_spec.rb
index 0958144643b..b4896d69077 100644
--- a/spec/lib/gitlab/database/rename_reserved_paths_migration/v1/rename_projects_spec.rb
+++ b/spec/lib/gitlab/database/rename_reserved_paths_migration/v1/rename_projects_spec.rb
@@ -5,6 +5,7 @@ describe Gitlab::Database::RenameReservedPathsMigration::V1::RenameProjects, :de
let(:subject) { described_class.new(['the-path'], migration) }
let(:project) do
create(:project,
+ :legacy_storage,
path: 'the-path',
namespace: create(:namespace, path: 'known-parent' ))
end
@@ -17,7 +18,7 @@ describe Gitlab::Database::RenameReservedPathsMigration::V1::RenameProjects, :de
describe '#projects_for_paths' do
it 'searches using nested paths' do
namespace = create(:namespace, path: 'hello')
- project = create(:project, path: 'THE-path', namespace: namespace)
+ project = create(:project, :legacy_storage, path: 'THE-path', namespace: namespace)
result_ids = described_class.new(['Hello/the-path'], migration)
.projects_for_paths.map(&:id)
@@ -26,8 +27,8 @@ describe Gitlab::Database::RenameReservedPathsMigration::V1::RenameProjects, :de
end
it 'includes the correct projects' do
- project = create(:project, path: 'THE-path')
- _other_project = create(:project)
+ project = create(:project, :legacy_storage, path: 'THE-path')
+ _other_project = create(:project, :legacy_storage)
result_ids = subject.projects_for_paths.map(&:id)
@@ -36,7 +37,7 @@ describe Gitlab::Database::RenameReservedPathsMigration::V1::RenameProjects, :de
end
describe '#rename_projects' do
- let!(:projects) { create_list(:project, 2, path: 'the-path') }
+ let!(:projects) { create_list(:project, 2, :legacy_storage, path: 'the-path') }
it 'renames each project' do
expect(subject).to receive(:rename_project).twice
@@ -120,7 +121,7 @@ describe Gitlab::Database::RenameReservedPathsMigration::V1::RenameProjects, :de
describe '#move_repository' do
let(:known_parent) { create(:namespace, path: 'known-parent') }
- let(:project) { create(:project, :repository, path: 'the-path', namespace: known_parent) }
+ let(:project) { create(:project, :repository, :legacy_storage, path: 'the-path', namespace: known_parent) }
it 'moves the repository for a project' do
expected_path = File.join(TestEnv.repos_path, 'known-parent', 'new-repo.git')
diff --git a/spec/lib/gitlab/email/attachment_uploader_spec.rb b/spec/lib/gitlab/email/attachment_uploader_spec.rb
index f61dbc67ad1..45c690842bc 100644
--- a/spec/lib/gitlab/email/attachment_uploader_spec.rb
+++ b/spec/lib/gitlab/email/attachment_uploader_spec.rb
@@ -2,7 +2,7 @@ require "spec_helper"
describe Gitlab::Email::AttachmentUploader do
describe "#execute" do
- let(:project) { build(:project) }
+ let(:project) { create(:project) }
let(:message_raw) { fixture_file("emails/attachment.eml") }
let(:message) { Mail::Message.new(message_raw) }
diff --git a/spec/lib/gitlab/encoding_helper_spec.rb b/spec/lib/gitlab/encoding_helper_spec.rb
index 4e9367323cb..83d431a7458 100644
--- a/spec/lib/gitlab/encoding_helper_spec.rb
+++ b/spec/lib/gitlab/encoding_helper_spec.rb
@@ -24,6 +24,11 @@ describe Gitlab::EncodingHelper do
'removes invalid bytes from ASCII-8bit encoded multibyte string. This can occur when a git diff match line truncates in the middle of a multibyte character. This occurs after the second word in this example. The test string is as short as we can get while still triggering the error condition when not looking at `detect[:confidence]`.',
"mu ns\xC3\n Lorem ipsum dolor sit amet, consectetur adipisicing ut\xC3\xA0y\xC3\xB9abcd\xC3\xB9efg kia elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non p\n {: .normal_pn}\n \n-Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in\n# *Lorem ipsum\xC3\xB9l\xC3\xB9l\xC3\xA0 dolor\xC3\xB9k\xC3\xB9 sit\xC3\xA8b\xC3\xA8 N\xC3\xA8 amet b\xC3\xA0d\xC3\xAC*\n+# *consectetur\xC3\xB9l\xC3\xB9l\xC3\xA0 adipisicing\xC3\xB9k\xC3\xB9 elit\xC3\xA8b\xC3\xA8 N\xC3\xA8 sed do\xC3\xA0d\xC3\xAC*{: .italic .smcaps}\n \n \xEF\x9B\xA1 eiusmod tempor incididunt, ut\xC3\xAAn\xC3\xB9 labore et dolore. Tw\xC4\x83nj\xC3\xAC magna aliqua. Ut enim ad minim veniam\n {: .normal}\n@@ -9,5 +9,5 @@ quis nostrud\xC3\xAAt\xC3\xB9 exercitiation ullamco laboris m\xC3\xB9s\xC3\xB9k\xC3\xB9abc\xC3\xB9 nisi ".force_encoding('ASCII-8BIT'),
"mu ns\n Lorem ipsum dolor sit amet, consectetur adipisicing ut\xC3\xA0y\xC3\xB9abcd\xC3\xB9efg kia elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non p\n {: .normal_pn}\n \n-Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in\n# *Lorem ipsum\xC3\xB9l\xC3\xB9l\xC3\xA0 dolor\xC3\xB9k\xC3\xB9 sit\xC3\xA8b\xC3\xA8 N\xC3\xA8 amet b\xC3\xA0d\xC3\xAC*\n+# *consectetur\xC3\xB9l\xC3\xB9l\xC3\xA0 adipisicing\xC3\xB9k\xC3\xB9 elit\xC3\xA8b\xC3\xA8 N\xC3\xA8 sed do\xC3\xA0d\xC3\xAC*{: .italic .smcaps}\n \n \xEF\x9B\xA1 eiusmod tempor incididunt, ut\xC3\xAAn\xC3\xB9 labore et dolore. Tw\xC4\x83nj\xC3\xAC magna aliqua. Ut enim ad minim veniam\n {: .normal}\n@@ -9,5 +9,5 @@ quis nostrud\xC3\xAAt\xC3\xB9 exercitiation ullamco laboris m\xC3\xB9s\xC3\xB9k\xC3\xB9abc\xC3\xB9 nisi "
+ ],
+ [
+ 'string with detected encoding that is not supported in Ruby',
+ "\xFFe,i\xFF,\xB8oi,'\xB8,\xFF,-",
+ "--broken encoding: IBM420_ltr"
]
].each do |description, test_string, xpect|
it description do
diff --git a/spec/lib/gitlab/gfm/uploads_rewriter_spec.rb b/spec/lib/gitlab/gfm/uploads_rewriter_spec.rb
index 326ed2f2ecf..13df8531b63 100644
--- a/spec/lib/gitlab/gfm/uploads_rewriter_spec.rb
+++ b/spec/lib/gitlab/gfm/uploads_rewriter_spec.rb
@@ -39,8 +39,8 @@ describe Gitlab::Gfm::UploadsRewriter do
it 'copies files' do
expect(new_files).to all(exist)
expect(old_paths).not_to match_array new_paths
- expect(old_paths).to all(include(old_project.full_path))
- expect(new_paths).to all(include(new_project.full_path))
+ expect(old_paths).to all(include(old_project.disk_path))
+ expect(new_paths).to all(include(new_project.disk_path))
end
it 'does not remove old files' do
diff --git a/spec/lib/gitlab/import_export/uploads_restorer_spec.rb b/spec/lib/gitlab/import_export/uploads_restorer_spec.rb
index a685521cbf0..8a3a244be21 100644
--- a/spec/lib/gitlab/import_export/uploads_restorer_spec.rb
+++ b/spec/lib/gitlab/import_export/uploads_restorer_spec.rb
@@ -16,7 +16,7 @@ describe Gitlab::ImportExport::UploadsRestorer do
end
describe 'legacy storage' do
- let(:project) { create(:project) }
+ let(:project) { create(:project, :legacy_storage) }
subject(:restorer) { described_class.new(project: project, shared: shared) }
@@ -34,7 +34,7 @@ describe Gitlab::ImportExport::UploadsRestorer do
end
describe 'hashed storage' do
- let(:project) { create(:project, :hashed) }
+ let(:project) { create(:project) }
subject(:restorer) { described_class.new(project: project, shared: shared) }
diff --git a/spec/lib/gitlab/import_export/uploads_saver_spec.rb b/spec/lib/gitlab/import_export/uploads_saver_spec.rb
index 959779523f4..177036c109b 100644
--- a/spec/lib/gitlab/import_export/uploads_saver_spec.rb
+++ b/spec/lib/gitlab/import_export/uploads_saver_spec.rb
@@ -15,7 +15,7 @@ describe Gitlab::ImportExport::UploadsSaver do
end
describe 'legacy storage' do
- let(:project) { create(:project) }
+ let(:project) { create(:project, :legacy_storage) }
subject(:saver) { described_class.new(shared: shared, project: project) }
@@ -37,7 +37,7 @@ describe Gitlab::ImportExport::UploadsSaver do
end
describe 'hashed storage' do
- let(:project) { create(:project, :hashed) }
+ let(:project) { create(:project) }
subject(:saver) { described_class.new(shared: shared, project: project) }
diff --git a/spec/lib/gitlab/repo_path_spec.rb b/spec/lib/gitlab/repo_path_spec.rb
index 1a925a15e0c..b67bcc77bd4 100644
--- a/spec/lib/gitlab/repo_path_spec.rb
+++ b/spec/lib/gitlab/repo_path_spec.rb
@@ -6,11 +6,11 @@ describe ::Gitlab::RepoPath do
context 'a repository storage path' do
it 'parses a full repository path' do
- expect(described_class.parse(project.repository.path)).to eq([project, false, nil])
+ expect(described_class.parse(project.repository.full_path)).to eq([project, false, nil])
end
it 'parses a full wiki path' do
- expect(described_class.parse(project.wiki.repository.path)).to eq([project, true, nil])
+ expect(described_class.parse(project.wiki.repository.full_path)).to eq([project, true, nil])
end
end
diff --git a/spec/lib/gitlab/shell_spec.rb b/spec/lib/gitlab/shell_spec.rb
index 2b61ce38418..4506cbc3982 100644
--- a/spec/lib/gitlab/shell_spec.rb
+++ b/spec/lib/gitlab/shell_spec.rb
@@ -443,7 +443,7 @@ describe Gitlab::Shell do
end
describe '#remove_repository' do
- let!(:project) { create(:project, :repository) }
+ let!(:project) { create(:project, :repository, :legacy_storage) }
let(:disk_path) { "#{project.disk_path}.git" }
it 'returns true when the command succeeds' do
diff --git a/spec/lib/gitlab/workhorse_spec.rb b/spec/lib/gitlab/workhorse_spec.rb
index dc2bb5b9747..37a0bf1ad36 100644
--- a/spec/lib/gitlab/workhorse_spec.rb
+++ b/spec/lib/gitlab/workhorse_spec.rb
@@ -324,7 +324,7 @@ describe Gitlab::Workhorse do
it 'includes a Repository param' do
repo_param = {
storage_name: 'default',
- relative_path: project.full_path + '.git',
+ relative_path: project.disk_path + '.git',
gl_repository: "project-#{project.id}"
}
diff --git a/spec/migrations/migrate_process_commit_worker_jobs_spec.rb b/spec/migrations/migrate_process_commit_worker_jobs_spec.rb
index e5793a3c0ee..657113812bd 100644
--- a/spec/migrations/migrate_process_commit_worker_jobs_spec.rb
+++ b/spec/migrations/migrate_process_commit_worker_jobs_spec.rb
@@ -4,7 +4,7 @@ require 'spec_helper'
require Rails.root.join('db', 'migrate', '20161124141322_migrate_process_commit_worker_jobs.rb')
describe MigrateProcessCommitWorkerJobs do
- let(:project) { create(:project, :repository) }
+ let(:project) { create(:project, :legacy_storage, :repository) }
let(:user) { create(:user) }
let(:commit) { project.commit.raw.rugged_commit }
diff --git a/spec/migrations/turn_nested_groups_into_regular_groups_for_mysql_spec.rb b/spec/migrations/turn_nested_groups_into_regular_groups_for_mysql_spec.rb
index 6f7a730edff..528dc54781d 100644
--- a/spec/migrations/turn_nested_groups_into_regular_groups_for_mysql_spec.rb
+++ b/spec/migrations/turn_nested_groups_into_regular_groups_for_mysql_spec.rb
@@ -4,7 +4,7 @@ require Rails.root.join('db', 'migrate', '20170503140202_turn_nested_groups_into
describe TurnNestedGroupsIntoRegularGroupsForMysql do
let!(:parent_group) { create(:group) }
let!(:child_group) { create(:group, parent: parent_group) }
- let!(:project) { create(:project, :empty_repo, namespace: child_group) }
+ let!(:project) { create(:project, :legacy_storage, :empty_repo, namespace: child_group) }
let!(:member) { create(:user) }
let(:migration) { described_class.new }
diff --git a/spec/models/ci/build_spec.rb b/spec/models/ci/build_spec.rb
index 0b3d5c6a0bd..78fcbf6d47e 100644
--- a/spec/models/ci/build_spec.rb
+++ b/spec/models/ci/build_spec.rb
@@ -1413,6 +1413,7 @@ describe Ci::Build do
[
{ key: 'CI', value: 'true', public: true },
{ key: 'GITLAB_CI', value: 'true', public: true },
+ { key: 'GITLAB_FEATURES', value: '', public: true },
{ key: 'CI_SERVER_NAME', value: 'GitLab', public: true },
{ key: 'CI_SERVER_VERSION', value: Gitlab::VERSION, public: true },
{ key: 'CI_SERVER_REVISION', value: Gitlab::REVISION, public: true },
@@ -1589,7 +1590,7 @@ describe Ci::Build do
context 'when the branch is protected' do
before do
- create(:protected_branch, project: build.project, name: build.ref)
+ allow(build.project).to receive(:protected_for?).with(build.ref).and_return(true)
end
it { is_expected.to include(protected_variable) }
@@ -1597,7 +1598,7 @@ describe Ci::Build do
context 'when the tag is protected' do
before do
- create(:protected_tag, project: build.project, name: build.ref)
+ allow(build.project).to receive(:protected_for?).with(build.ref).and_return(true)
end
it { is_expected.to include(protected_variable) }
@@ -1634,7 +1635,7 @@ describe Ci::Build do
context 'when the branch is protected' do
before do
- create(:protected_branch, project: build.project, name: build.ref)
+ allow(build.project).to receive(:protected_for?).with(build.ref).and_return(true)
end
it { is_expected.to include(protected_variable) }
@@ -1642,7 +1643,7 @@ describe Ci::Build do
context 'when the tag is protected' do
before do
- create(:protected_tag, project: build.project, name: build.ref)
+ allow(build.project).to receive(:protected_for?).with(build.ref).and_return(true)
end
it { is_expected.to include(protected_variable) }
diff --git a/spec/models/group_spec.rb b/spec/models/group_spec.rb
index 338fb314ee9..4f16b73ef38 100644
--- a/spec/models/group_spec.rb
+++ b/spec/models/group_spec.rb
@@ -549,7 +549,7 @@ describe Group do
context 'when the ref is a protected branch' do
before do
- create(:protected_branch, name: 'ref', project: project)
+ allow(project).to receive(:protected_for?).with('ref').and_return(true)
end
it_behaves_like 'ref is protected'
@@ -557,7 +557,7 @@ describe Group do
context 'when the ref is a protected tag' do
before do
- create(:protected_tag, name: 'ref', project: project)
+ allow(project).to receive(:protected_for?).with('ref').and_return(true)
end
it_behaves_like 'ref is protected'
@@ -571,6 +571,10 @@ describe Group do
let(:variable_child_2) { create(:ci_group_variable, group: group_child_2) }
let(:variable_child_3) { create(:ci_group_variable, group: group_child_3) }
+ before do
+ allow(project).to receive(:protected_for?).with('ref').and_return(true)
+ end
+
it 'returns all variables belong to the group and parent groups' do
expected_array1 = [protected_variable, secret_variable]
expected_array2 = [variable_child, variable_child_2, variable_child_3]
diff --git a/spec/models/namespace_spec.rb b/spec/models/namespace_spec.rb
index 191b60e4383..e626efd054d 100644
--- a/spec/models/namespace_spec.rb
+++ b/spec/models/namespace_spec.rb
@@ -168,84 +168,105 @@ describe Namespace do
end
describe '#move_dir', :request_store do
- let(:namespace) { create(:namespace) }
- let!(:project) { create(:project_empty_repo, namespace: namespace) }
+ shared_examples "namespace restrictions" do
+ context "when any project has container images" do
+ let(:container_repository) { create(:container_repository) }
- it "raises error when directory exists" do
- expect { namespace.move_dir }.to raise_error("namespace directory cannot be moved")
- end
+ before do
+ stub_container_registry_config(enabled: true)
+ stub_container_registry_tags(repository: :any, tags: ['tag'])
- it "moves dir if path changed" do
- namespace.update_attributes(path: namespace.full_path + '_new')
+ create(:project, namespace: namespace, container_repositories: [container_repository])
- expect(gitlab_shell.exists?(project.repository_storage_path, "#{namespace.path}/#{project.path}.git")).to be_truthy
- end
+ allow(namespace).to receive(:path_was).and_return(namespace.path)
+ allow(namespace).to receive(:path).and_return('new_path')
+ end
- context "when any project has container images" do
- let(:container_repository) { create(:container_repository) }
+ it 'raises an error about not movable project' do
+ expect { namespace.move_dir }.to raise_error(/Namespace cannot be moved/)
+ end
+ end
+ end
- before do
- stub_container_registry_config(enabled: true)
- stub_container_registry_tags(repository: :any, tags: ['tag'])
+ context 'legacy storage' do
+ let(:namespace) { create(:namespace) }
+ let!(:project) { create(:project_empty_repo, :legacy_storage, namespace: namespace) }
- create(:project, namespace: namespace, container_repositories: [container_repository])
+ it_behaves_like 'namespace restrictions'
- allow(namespace).to receive(:path_was).and_return(namespace.path)
- allow(namespace).to receive(:path).and_return('new_path')
+ it "raises error when directory exists" do
+ expect { namespace.move_dir }.to raise_error("namespace directory cannot be moved")
end
- it 'raises an error about not movable project' do
- expect { namespace.move_dir }.to raise_error(/Namespace cannot be moved/)
+ it "moves dir if path changed" do
+ namespace.update_attributes(path: namespace.full_path + '_new')
+
+ expect(gitlab_shell.exists?(project.repository_storage_path, "#{namespace.path}/#{project.path}.git")).to be_truthy
end
- end
- context 'with subgroups' do
- let(:parent) { create(:group, name: 'parent', path: 'parent') }
- let(:child) { create(:group, name: 'child', path: 'child', parent: parent) }
- let!(:project) { create(:project_empty_repo, path: 'the-project', namespace: child, skip_disk_validation: true) }
- let(:uploads_dir) { FileUploader.root }
- let(:pages_dir) { File.join(TestEnv.pages_path) }
+ context 'with subgroups' do
+ let(:parent) { create(:group, name: 'parent', path: 'parent') }
+ let(:child) { create(:group, name: 'child', path: 'child', parent: parent) }
+ let!(:project) { create(:project_empty_repo, :legacy_storage, path: 'the-project', namespace: child, skip_disk_validation: true) }
+ let(:uploads_dir) { FileUploader.root }
+ let(:pages_dir) { File.join(TestEnv.pages_path) }
- before do
- FileUtils.mkdir_p(File.join(uploads_dir, 'parent', 'child', 'the-project'))
- FileUtils.mkdir_p(File.join(pages_dir, 'parent', 'child', 'the-project'))
- end
+ before do
+ FileUtils.mkdir_p(File.join(uploads_dir, project.full_path))
+ FileUtils.mkdir_p(File.join(pages_dir, project.full_path))
+ end
+
+ context 'renaming child' do
+ it 'correctly moves the repository, uploads and pages' do
+ expected_repository_path = File.join(TestEnv.repos_path, 'parent', 'renamed', 'the-project.git')
+ expected_upload_path = File.join(uploads_dir, 'parent', 'renamed', 'the-project')
+ expected_pages_path = File.join(pages_dir, 'parent', 'renamed', 'the-project')
- context 'renaming child' do
- it 'correctly moves the repository, uploads and pages' do
- expected_repository_path = File.join(TestEnv.repos_path, 'parent', 'renamed', 'the-project.git')
- expected_upload_path = File.join(uploads_dir, 'parent', 'renamed', 'the-project')
- expected_pages_path = File.join(pages_dir, 'parent', 'renamed', 'the-project')
+ child.update_attributes!(path: 'renamed')
- child.update_attributes!(path: 'renamed')
+ expect(File.directory?(expected_repository_path)).to be(true)
+ expect(File.directory?(expected_upload_path)).to be(true)
+ expect(File.directory?(expected_pages_path)).to be(true)
+ end
+ end
+
+ context 'renaming parent' do
+ it 'correctly moves the repository, uploads and pages' do
+ expected_repository_path = File.join(TestEnv.repos_path, 'renamed', 'child', 'the-project.git')
+ expected_upload_path = File.join(uploads_dir, 'renamed', 'child', 'the-project')
+ expected_pages_path = File.join(pages_dir, 'renamed', 'child', 'the-project')
- expect(File.directory?(expected_repository_path)).to be(true)
- expect(File.directory?(expected_upload_path)).to be(true)
- expect(File.directory?(expected_pages_path)).to be(true)
+ parent.update_attributes!(path: 'renamed')
+
+ expect(File.directory?(expected_repository_path)).to be(true)
+ expect(File.directory?(expected_upload_path)).to be(true)
+ expect(File.directory?(expected_pages_path)).to be(true)
+ end
end
end
+ end
- context 'renaming parent' do
- it 'correctly moves the repository, uploads and pages' do
- expected_repository_path = File.join(TestEnv.repos_path, 'renamed', 'child', 'the-project.git')
- expected_upload_path = File.join(uploads_dir, 'renamed', 'child', 'the-project')
- expected_pages_path = File.join(pages_dir, 'renamed', 'child', 'the-project')
+ context 'hashed storage' do
+ let(:namespace) { create(:namespace) }
+ let!(:project) { create(:project_empty_repo, namespace: namespace) }
- parent.update_attributes!(path: 'renamed')
+ it_behaves_like 'namespace restrictions'
- expect(File.directory?(expected_repository_path)).to be(true)
- expect(File.directory?(expected_upload_path)).to be(true)
- expect(File.directory?(expected_pages_path)).to be(true)
- end
+ it "repository directory remains unchanged if path changed" do
+ before_disk_path = project.disk_path
+ namespace.update_attributes(path: namespace.full_path + '_new')
+
+ expect(before_disk_path).to eq(project.disk_path)
+ expect(gitlab_shell.exists?(project.repository_storage_path, "#{project.disk_path}.git")).to be_truthy
end
end
it 'updates project full path in .git/config for each project inside namespace' do
parent = create(:group, name: 'mygroup', path: 'mygroup')
subgroup = create(:group, name: 'mysubgroup', path: 'mysubgroup', parent: parent)
- project_in_parent_group = create(:project, :repository, namespace: parent, name: 'foo1')
- hashed_project_in_subgroup = create(:project, :repository, :hashed, namespace: subgroup, name: 'foo2')
- legacy_project_in_subgroup = create(:project, :repository, namespace: subgroup, name: 'foo3')
+ project_in_parent_group = create(:project, :legacy_storage, :repository, namespace: parent, name: 'foo1')
+ hashed_project_in_subgroup = create(:project, :repository, namespace: subgroup, name: 'foo2')
+ legacy_project_in_subgroup = create(:project, :legacy_storage, :repository, namespace: subgroup, name: 'foo3')
parent.update(path: 'mygroup_new')
@@ -260,38 +281,18 @@ describe Namespace do
end
describe '#rm_dir', 'callback' do
- let!(:project) { create(:project_empty_repo, namespace: namespace) }
let(:repository_storage_path) { Gitlab.config.repositories.storages.default['path'] }
let(:path_in_dir) { File.join(repository_storage_path, namespace.full_path) }
let(:deleted_path) { namespace.full_path.gsub(namespace.path, "#{namespace.full_path}+#{namespace.id}+deleted") }
let(:deleted_path_in_dir) { File.join(repository_storage_path, deleted_path) }
- it 'renames its dirs when deleted' do
- allow(GitlabShellWorker).to receive(:perform_in)
-
- namespace.destroy
-
- expect(File.exist?(deleted_path_in_dir)).to be(true)
- end
-
- it 'schedules the namespace for deletion' do
- expect(GitlabShellWorker).to receive(:perform_in).with(5.minutes, :rm_namespace, repository_storage_path, deleted_path)
-
- namespace.destroy
- end
-
- context 'in sub-groups' do
- let(:parent) { create(:group, path: 'parent') }
- let(:child) { create(:group, parent: parent, path: 'child') }
- let!(:project) { create(:project_empty_repo, namespace: child) }
- let(:path_in_dir) { File.join(repository_storage_path, 'parent', 'child') }
- let(:deleted_path) { File.join('parent', "child+#{child.id}+deleted") }
- let(:deleted_path_in_dir) { File.join(repository_storage_path, deleted_path) }
+ context 'legacy storage' do
+ let!(:project) { create(:project_empty_repo, :legacy_storage, namespace: namespace) }
it 'renames its dirs when deleted' do
allow(GitlabShellWorker).to receive(:perform_in)
- child.destroy
+ namespace.destroy
expect(File.exist?(deleted_path_in_dir)).to be(true)
end
@@ -299,14 +300,57 @@ describe Namespace do
it 'schedules the namespace for deletion' do
expect(GitlabShellWorker).to receive(:perform_in).with(5.minutes, :rm_namespace, repository_storage_path, deleted_path)
- child.destroy
+ namespace.destroy
+ end
+
+ context 'in sub-groups' do
+ let(:parent) { create(:group, path: 'parent') }
+ let(:child) { create(:group, parent: parent, path: 'child') }
+ let!(:project) { create(:project_empty_repo, :legacy_storage, namespace: child) }
+ let(:path_in_dir) { File.join(repository_storage_path, 'parent', 'child') }
+ let(:deleted_path) { File.join('parent', "child+#{child.id}+deleted") }
+ let(:deleted_path_in_dir) { File.join(repository_storage_path, deleted_path) }
+
+ it 'renames its dirs when deleted' do
+ allow(GitlabShellWorker).to receive(:perform_in)
+
+ child.destroy
+
+ expect(File.exist?(deleted_path_in_dir)).to be(true)
+ end
+
+ it 'schedules the namespace for deletion' do
+ expect(GitlabShellWorker).to receive(:perform_in).with(5.minutes, :rm_namespace, repository_storage_path, deleted_path)
+
+ child.destroy
+ end
+ end
+
+ it 'removes the exports folder' do
+ expect(namespace).to receive(:remove_exports!)
+
+ namespace.destroy
end
end
- it 'removes the exports folder' do
- expect(namespace).to receive(:remove_exports!)
+ context 'hashed storage' do
+ let!(:project) { create(:project_empty_repo, namespace: namespace) }
+
+ it 'has no repositories base directories to remove' do
+ allow(GitlabShellWorker).to receive(:perform_in)
+
+ expect(File.exist?(path_in_dir)).to be(false)
- namespace.destroy
+ namespace.destroy
+
+ expect(File.exist?(deleted_path_in_dir)).to be(false)
+ end
+
+ it 'removes the exports folder' do
+ expect(namespace).to receive(:remove_exports!)
+
+ namespace.destroy
+ end
end
end
@@ -567,8 +611,8 @@ describe Namespace do
end
describe '#remove_exports' do
- let(:legacy_project) { create(:project, :with_export, namespace: namespace) }
- let(:hashed_project) { create(:project, :with_export, :hashed, namespace: namespace) }
+ let(:legacy_project) { create(:project, :with_export, :legacy_storage, namespace: namespace) }
+ let(:hashed_project) { create(:project, :with_export, namespace: namespace) }
let(:export_path) { Dir.mktmpdir('namespace_remove_exports_spec') }
let(:legacy_export) { legacy_project.export_project_path }
let(:hashed_export) { hashed_project.export_project_path }
diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb
index c6ca038a2ba..ee04d74d848 100644
--- a/spec/models/project_spec.rb
+++ b/spec/models/project_spec.rb
@@ -2092,7 +2092,7 @@ describe Project do
context 'when the ref is a protected branch' do
before do
- create(:protected_branch, name: 'ref', project: project)
+ allow(project).to receive(:protected_for?).with('ref').and_return(true)
end
it_behaves_like 'ref is protected'
@@ -2100,7 +2100,7 @@ describe Project do
context 'when the ref is a protected tag' do
before do
- create(:protected_tag, name: 'ref', project: project)
+ allow(project).to receive(:protected_for?).with('ref').and_return(true)
end
it_behaves_like 'ref is protected'
@@ -2125,6 +2125,8 @@ describe Project do
context 'when the ref is a protected branch' do
before do
+ allow(project).to receive(:repository).and_call_original
+ allow(project).to receive_message_chain(:repository, :branch_exists?).and_return(true)
create(:protected_branch, name: 'ref', project: project)
end
@@ -2135,6 +2137,8 @@ describe Project do
context 'when the ref is a protected tag' do
before do
+ allow(project).to receive_message_chain(:repository, :branch_exists?).and_return(false)
+ allow(project).to receive_message_chain(:repository, :tag_exists?).and_return(true)
create(:protected_tag, name: 'ref', project: project)
end
@@ -2504,6 +2508,7 @@ describe Project do
end
describe '#remove_exports' do
+ let(:legacy_project) { create(:project, :legacy_storage, :with_export) }
let(:project) { create(:project, :with_export) }
it 'removes the exports directory for the project' do
@@ -2516,15 +2521,29 @@ describe Project do
expect(File.exist?(project.export_path)).to be_falsy
end
- it 'is a no-op when there is no namespace' do
+ it 'is a no-op on legacy projects when there is no namespace' do
+ export_path = legacy_project.export_path
+
+ legacy_project.update_column(:namespace_id, nil)
+
+ expect(FileUtils).not_to receive(:rm_rf).with(export_path)
+
+ legacy_project.remove_exports
+
+ expect(File.exist?(export_path)).to be_truthy
+ end
+
+ it 'runs on hashed storage projects when there is no namespace' do
export_path = project.export_path
+
project.update_column(:namespace_id, nil)
- expect(FileUtils).not_to receive(:rm_rf).with(export_path)
+ allow(FileUtils).to receive(:rm_rf).and_call_original
+ expect(FileUtils).to receive(:rm_rf).with(export_path).and_call_original
project.remove_exports
- expect(File.exist?(export_path)).to be_truthy
+ expect(File.exist?(export_path)).to be_falsy
end
it 'is run when the project is destroyed' do
@@ -2545,7 +2564,7 @@ describe Project do
end
context 'legacy storage' do
- let(:project) { create(:project, :repository) }
+ let(:project) { create(:project, :repository, :legacy_storage) }
let(:gitlab_shell) { Gitlab::Shell.new }
let(:project_storage) { project.send(:storage) }
@@ -2719,6 +2738,8 @@ describe Project do
let(:project) { create(:project, :repository, skip_disk_validation: true) }
let(:gitlab_shell) { Gitlab::Shell.new }
let(:hash) { Digest::SHA2.hexdigest(project.id.to_s) }
+ let(:hashed_prefix) { File.join('@hashed', hash[0..1], hash[2..3]) }
+ let(:hashed_path) { File.join(hashed_prefix, hash) }
before do
stub_application_setting(hashed_storage_enabled: true)
@@ -2744,14 +2765,12 @@ describe Project do
describe '#base_dir' do
it 'returns base_dir based on hash of project id' do
- expect(project.base_dir).to eq("@hashed/#{hash[0..1]}/#{hash[2..3]}")
+ expect(project.base_dir).to eq(hashed_prefix)
end
end
describe '#disk_path' do
it 'returns disk_path based on hash of project id' do
- hashed_path = "@hashed/#{hash[0..1]}/#{hash[2..3]}/#{hash}"
-
expect(project.disk_path).to eq(hashed_path)
end
end
@@ -2760,7 +2779,7 @@ describe Project do
it 'delegates to gitlab_shell to ensure namespace is created' do
allow(project).to receive(:gitlab_shell).and_return(gitlab_shell)
- expect(gitlab_shell).to receive(:add_namespace).with(project.repository_storage_path, "@hashed/#{hash[0..1]}/#{hash[2..3]}")
+ expect(gitlab_shell).to receive(:add_namespace).with(project.repository_storage_path, hashed_prefix)
project.ensure_storage_path_exists
end
diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb
index cb02d526a98..76a6aef39cc 100644
--- a/spec/models/user_spec.rb
+++ b/spec/models/user_spec.rb
@@ -1586,14 +1586,37 @@ describe User do
describe '#authorized_groups' do
let!(:user) { create(:user) }
let!(:private_group) { create(:group) }
+ let!(:child_group) { create(:group, parent: private_group) }
+
+ let!(:project_group) { create(:group) }
+ let!(:project) { create(:project, group: project_group) }
before do
private_group.add_user(user, Gitlab::Access::MASTER)
+ project.add_master(user)
end
subject { user.authorized_groups }
- it { is_expected.to eq([private_group]) }
+ it { is_expected.to contain_exactly private_group, project_group }
+ end
+
+ describe '#membership_groups' do
+ let!(:user) { create(:user) }
+ let!(:parent_group) { create(:group) }
+ let!(:child_group) { create(:group, parent: parent_group) }
+
+ before do
+ parent_group.add_user(user, Gitlab::Access::MASTER)
+ end
+
+ subject { user.membership_groups }
+
+ if Group.supports_nested_groups?
+ it { is_expected.to contain_exactly parent_group, child_group }
+ else
+ it { is_expected.to contain_exactly parent_group }
+ end
end
describe '#authorized_projects', :delete do
diff --git a/spec/policies/personal_snippet_policy_spec.rb b/spec/policies/personal_snippet_policy_spec.rb
index b70c8646a3d..50bb0899eba 100644
--- a/spec/policies/personal_snippet_policy_spec.rb
+++ b/spec/policies/personal_snippet_policy_spec.rb
@@ -1,5 +1,6 @@
require 'spec_helper'
+# Snippet visibility scenarios are included in more details in spec/support/snippet_visibility.rb
describe PersonalSnippetPolicy do
let(:regular_user) { create(:user) }
let(:external_user) { create(:user, :external) }
diff --git a/spec/policies/project_snippet_policy_spec.rb b/spec/policies/project_snippet_policy_spec.rb
index cdba1b09fc1..4d32e06b553 100644
--- a/spec/policies/project_snippet_policy_spec.rb
+++ b/spec/policies/project_snippet_policy_spec.rb
@@ -1,5 +1,6 @@
require 'spec_helper'
+# Snippet visibility scenarios are included in more details in spec/support/snippet_visibility.rb
describe ProjectSnippetPolicy do
let(:regular_user) { create(:user) }
let(:external_user) { create(:user, :external) }
diff --git a/spec/requests/api/internal_spec.rb b/spec/requests/api/internal_spec.rb
index ea6b0a71849..c7df6251d74 100644
--- a/spec/requests/api/internal_spec.rb
+++ b/spec/requests/api/internal_spec.rb
@@ -366,20 +366,9 @@ describe API::Internal do
end
end
- context 'project as /namespace/project' do
- it do
- push(key, project_with_repo_path('/' + project.full_path))
-
- expect(response).to have_gitlab_http_status(200)
- expect(json_response["status"]).to be_truthy
- expect(json_response["repository_path"]).to eq(project.repository.path_to_repo)
- expect(json_response["gl_repository"]).to eq("project-#{project.id}")
- end
- end
-
context 'project as namespace/project' do
it do
- push(key, project_with_repo_path(project.full_path))
+ push(key, project)
expect(response).to have_gitlab_http_status(200)
expect(json_response["status"]).to be_truthy
@@ -496,8 +485,10 @@ describe API::Internal do
end
context 'project does not exist' do
- it do
- pull(key, project_with_repo_path('gitlab/notexist'))
+ it 'returns a 200 response with status: false' do
+ project.destroy
+
+ pull(key, project)
expect(response).to have_gitlab_http_status(200)
expect(json_response["status"]).to be_falsey
@@ -569,6 +560,7 @@ describe API::Internal do
end
context 'the project path was changed' do
+ let(:project) { create(:project, :repository, :legacy_storage) }
let!(:old_path_to_repo) { project.repository.path_to_repo }
let!(:repository) { project.repository }
@@ -858,9 +850,14 @@ describe API::Internal do
end
end
- def project_with_repo_path(path)
- double().tap do |fake_project|
- allow(fake_project).to receive_message_chain('repository.path_to_repo' => path)
+ def gl_repository_for(project_or_wiki)
+ case project_or_wiki
+ when ProjectWiki
+ project_or_wiki.project.gl_repository(is_wiki: true)
+ when Project
+ project_or_wiki.gl_repository(is_wiki: false)
+ else
+ nil
end
end
@@ -868,18 +865,8 @@ describe API::Internal do
post(
api("/internal/allowed"),
key_id: key.id,
- project: project.repository.path_to_repo,
- action: 'git-upload-pack',
- secret_token: secret_token,
- protocol: protocol
- )
- end
-
- def pull_with_path(key, path_to_repo, protocol = 'ssh')
- post(
- api("/internal/allowed"),
- key_id: key.id,
- project: path_to_repo,
+ project: project.full_path,
+ gl_repository: gl_repository_for(project),
action: 'git-upload-pack',
secret_token: secret_token,
protocol: protocol
@@ -891,20 +878,8 @@ describe API::Internal do
api("/internal/allowed"),
changes: 'd14d6c0abdd253381df51a723d58691b2ee1ab08 570e7b2abdd848b95f2f578043fc23bd6f6fd24d refs/heads/master',
key_id: key.id,
- project: project.repository.path_to_repo,
- action: 'git-receive-pack',
- secret_token: secret_token,
- protocol: protocol,
- env: env
- )
- end
-
- def push_with_path(key, path_to_repo, protocol = 'ssh', env: nil)
- post(
- api("/internal/allowed"),
- changes: 'd14d6c0abdd253381df51a723d58691b2ee1ab08 570e7b2abdd848b95f2f578043fc23bd6f6fd24d refs/heads/master',
- key_id: key.id,
- project: path_to_repo,
+ project: project.full_path,
+ gl_repository: gl_repository_for(project),
action: 'git-receive-pack',
secret_token: secret_token,
protocol: protocol,
@@ -917,7 +892,8 @@ describe API::Internal do
api("/internal/allowed"),
ref: 'master',
key_id: key.id,
- project: project.repository.path_to_repo,
+ project: project.full_path,
+ gl_repository: gl_repository_for(project),
action: 'git-upload-archive',
secret_token: secret_token,
protocol: 'ssh'
@@ -929,7 +905,7 @@ describe API::Internal do
api("/internal/lfs_authenticate"),
key_id: key_id,
secret_token: secret_token,
- project: project.repository.path_to_repo
+ project: project.full_path
)
end
end
diff --git a/spec/requests/api/projects_spec.rb b/spec/requests/api/projects_spec.rb
index f11cd638d96..00dd8897e6a 100644
--- a/spec/requests/api/projects_spec.rb
+++ b/spec/requests/api/projects_spec.rb
@@ -460,7 +460,7 @@ describe API::Projects do
expect(response).to have_gitlab_http_status(201)
project.each_pair do |k, v|
- next if %i[has_external_issue_tracker issues_enabled merge_requests_enabled wiki_enabled].include?(k)
+ next if %i[has_external_issue_tracker issues_enabled merge_requests_enabled wiki_enabled storage_version].include?(k)
expect(json_response[k.to_s]).to eq(v)
end
@@ -622,12 +622,8 @@ describe API::Projects do
end
describe 'POST /projects/user/:id' do
- before do
- expect(project).to be_persisted
- end
-
it 'creates new project without path but with name and return 201' do
- expect { post api("/projects/user/#{user.id}", admin), name: 'Foo Project' }.to change {Project.count}.by(1)
+ expect { post api("/projects/user/#{user.id}", admin), name: 'Foo Project' }.to change { Project.count }.by(1)
expect(response).to have_gitlab_http_status(201)
project = Project.last
@@ -666,8 +662,9 @@ describe API::Projects do
post api("/projects/user/#{user.id}", admin), project
expect(response).to have_gitlab_http_status(201)
+
project.each_pair do |k, v|
- next if %i[has_external_issue_tracker path].include?(k)
+ next if %i[has_external_issue_tracker path storage_version].include?(k)
expect(json_response[k.to_s]).to eq(v)
end
diff --git a/spec/requests/api/search_spec.rb b/spec/requests/api/search_spec.rb
index a0026c6e11c..ddda5752f0c 100644
--- a/spec/requests/api/search_spec.rb
+++ b/spec/requests/api/search_spec.rb
@@ -180,6 +180,18 @@ describe API::Search do
it_behaves_like 'response is correct', schema: 'public_api/v4/milestones'
end
+
+ context 'for milestones scope with group path as id' do
+ before do
+ another_project = create(:project, :public)
+ create(:milestone, project: project, title: 'awesome milestone')
+ create(:milestone, project: another_project, title: 'awesome milestone other project')
+
+ get api("/groups/#{CGI.escape(group.full_path)}/-/search", user), scope: 'milestones', search: 'awesome'
+ end
+
+ it_behaves_like 'response is correct', schema: 'public_api/v4/milestones'
+ end
end
end
@@ -286,6 +298,14 @@ describe API::Search do
it_behaves_like 'response is correct', schema: 'public_api/v4/commits'
end
+ context 'for commits scope with project path as id' do
+ before do
+ get api("/projects/#{CGI.escape(repo_project.full_path)}/-/search", user), scope: 'commits', search: '498214de67004b1da3d820901307bed2a68a8ef6'
+ end
+
+ it_behaves_like 'response is correct', schema: 'public_api/v4/commits'
+ end
+
context 'for blobs scope' do
before do
get api("/projects/#{repo_project.id}/-/search", user), scope: 'blobs', search: 'monitors'
diff --git a/spec/requests/api/snippets_spec.rb b/spec/requests/api/snippets_spec.rb
index 74198c8eb4f..b3e253befc6 100644
--- a/spec/requests/api/snippets_spec.rb
+++ b/spec/requests/api/snippets_spec.rb
@@ -32,6 +32,27 @@ describe API::Snippets do
expect(json_response).to be_an Array
expect(json_response.size).to eq(0)
end
+
+ it 'returns 404 for non-authenticated' do
+ create(:personal_snippet, :internal)
+
+ get api("/snippets/")
+
+ expect(response).to have_gitlab_http_status(401)
+ end
+
+ it 'does not return snippets related to a project with disable feature visibility' do
+ project = create(:project)
+ create(:project_member, project: project, user: user)
+ public_snippet = create(:personal_snippet, :public, author: user, project: project)
+ project.project_feature.update_attribute(:snippets_access_level, 0)
+
+ get api("/snippets/", user)
+
+ json_response.each do |snippet|
+ expect(snippet["id"]).not_to eq(public_snippet.id)
+ end
+ end
end
describe 'GET /snippets/public' do
diff --git a/spec/requests/api/todos_spec.rb b/spec/requests/api/todos_spec.rb
index fb3a33cadff..2ee8d150dc8 100644
--- a/spec/requests/api/todos_spec.rb
+++ b/spec/requests/api/todos_spec.rb
@@ -129,6 +129,12 @@ describe API::Todos do
post api("/todos/#{pending_1.id}/mark_as_done", john_doe)
end
+
+ it 'returns 404 if the todo does not belong to the current user' do
+ post api("/todos/#{pending_1.id}/mark_as_done", author_1)
+
+ expect(response.status).to eq(404)
+ end
end
end
diff --git a/spec/requests/api/v3/projects_spec.rb b/spec/requests/api/v3/projects_spec.rb
index 5d99d9495f3..bf36d3e245a 100644
--- a/spec/requests/api/v3/projects_spec.rb
+++ b/spec/requests/api/v3/projects_spec.rb
@@ -401,7 +401,7 @@ describe API::V3::Projects do
post v3_api('/projects', user), project
project.each_pair do |k, v|
- next if %i[has_external_issue_tracker issues_enabled merge_requests_enabled wiki_enabled].include?(k)
+ next if %i[storage_version has_external_issue_tracker issues_enabled merge_requests_enabled wiki_enabled].include?(k)
expect(json_response[k.to_s]).to eq(v)
end
@@ -545,7 +545,7 @@ describe API::V3::Projects do
expect(response).to have_gitlab_http_status(201)
project.each_pair do |k, v|
- next if %i[has_external_issue_tracker path].include?(k)
+ next if %i[storage_version has_external_issue_tracker path].include?(k)
expect(json_response[k.to_s]).to eq(v)
end
diff --git a/spec/requests/api/v3/todos_spec.rb b/spec/requests/api/v3/todos_spec.rb
index 53fd962272a..ea648e3917f 100644
--- a/spec/requests/api/v3/todos_spec.rb
+++ b/spec/requests/api/v3/todos_spec.rb
@@ -38,6 +38,12 @@ describe API::V3::Todos do
delete v3_api("/todos/#{pending_1.id}", john_doe)
end
+
+ it 'returns 404 if the todo does not belong to the current user' do
+ delete v3_api("/todos/#{pending_1.id}", author_1)
+
+ expect(response.status).to eq(404)
+ end
end
end
diff --git a/spec/requests/git_http_spec.rb b/spec/requests/git_http_spec.rb
index 2e2dccdafad..942e5b2bb1b 100644
--- a/spec/requests/git_http_spec.rb
+++ b/spec/requests/git_http_spec.rb
@@ -163,7 +163,7 @@ describe 'Git HTTP requests' do
download(path) do |response|
json_body = ActiveSupport::JSON.decode(response.body)
- expect(json_body['RepoPath']).to include(wiki.repository.full_path)
+ expect(json_body['RepoPath']).to include(wiki.repository.disk_path)
end
end
end
diff --git a/spec/requests/openid_connect_spec.rb b/spec/requests/openid_connect_spec.rb
index 1a5ad9b04e4..5d349f45a33 100644
--- a/spec/requests/openid_connect_spec.rb
+++ b/spec/requests/openid_connect_spec.rb
@@ -65,10 +65,20 @@ describe 'OpenID Connect requests' do
)
end
- let(:public_email) { build :email, email: 'public@example.com' }
- let(:private_email) { build :email, email: 'private@example.com' }
+ let!(:public_email) { build :email, email: 'public@example.com' }
+ let!(:private_email) { build :email, email: 'private@example.com' }
- it 'includes all user information' do
+ let!(:group1) { create :group, path: 'group1' }
+ let!(:group2) { create :group, path: 'group2' }
+ let!(:group3) { create :group, path: 'group3', parent: group2 }
+ let!(:group4) { create :group, path: 'group4', parent: group3 }
+
+ before do
+ group1.add_user(user, GroupMember::OWNER)
+ group3.add_user(user, Gitlab::Access::DEVELOPER)
+ end
+
+ it 'includes all user information and group memberships' do
request_user_info
expect(json_response).to eq({
@@ -79,7 +89,13 @@ describe 'OpenID Connect requests' do
'email_verified' => true,
'website' => 'https://example.com',
'profile' => 'http://localhost/alice',
- 'picture' => "http://localhost/uploads/-/system/user/avatar/#{user.id}/dk.png"
+ 'picture' => "http://localhost/uploads/-/system/user/avatar/#{user.id}/dk.png",
+ 'groups' =>
+ if Group.supports_nested_groups?
+ ['group1', 'group2/group3', 'group2/group3/group4']
+ else
+ ['group1', 'group2/group3']
+ end
})
end
end
diff --git a/spec/services/groups/destroy_service_spec.rb b/spec/services/groups/destroy_service_spec.rb
index ac4b9c02ba7..e8216abb08b 100644
--- a/spec/services/groups/destroy_service_spec.rb
+++ b/spec/services/groups/destroy_service_spec.rb
@@ -6,7 +6,7 @@ describe Groups::DestroyService do
let!(:user) { create(:user) }
let!(:group) { create(:group) }
let!(:nested_group) { create(:group, parent: group) }
- let!(:project) { create(:project, namespace: group) }
+ let!(:project) { create(:project, :legacy_storage, namespace: group) }
let!(:notification_setting) { create(:notification_setting, source: group)}
let(:gitlab_shell) { Gitlab::Shell.new }
let(:remove_path) { group.path + "+#{group.id}+deleted" }
@@ -141,7 +141,7 @@ describe Groups::DestroyService do
end
context 'legacy storage' do
- let!(:project) { create(:project, :empty_repo, namespace: group) }
+ let!(:project) { create(:project, :legacy_storage, :empty_repo, namespace: group) }
it 'removes repository' do
expect(gitlab_shell.exists?(project.repository_storage_path, "#{project.disk_path}.git")).to be_falsey
@@ -149,7 +149,7 @@ describe Groups::DestroyService do
end
context 'hashed storage' do
- let!(:project) { create(:project, :hashed, :empty_repo, namespace: group) }
+ let!(:project) { create(:project, :empty_repo, namespace: group) }
it 'removes repository' do
expect(gitlab_shell.exists?(project.repository_storage_path, "#{project.disk_path}.git")).to be_falsey
diff --git a/spec/services/projects/hashed_storage/migrate_attachments_service_spec.rb b/spec/services/projects/hashed_storage/migrate_attachments_service_spec.rb
index 15699574b3a..fb6d7171ac3 100644
--- a/spec/services/projects/hashed_storage/migrate_attachments_service_spec.rb
+++ b/spec/services/projects/hashed_storage/migrate_attachments_service_spec.rb
@@ -2,7 +2,7 @@ require 'spec_helper'
describe Projects::HashedStorage::MigrateAttachmentsService do
subject(:service) { described_class.new(project) }
- let(:project) { create(:project) }
+ let(:project) { create(:project, :legacy_storage) }
let(:legacy_storage) { Storage::LegacyProject.new(project) }
let(:hashed_storage) { Storage::HashedProject.new(project) }
diff --git a/spec/services/projects/hashed_storage/migrate_repository_service_spec.rb b/spec/services/projects/hashed_storage/migrate_repository_service_spec.rb
index 7b536cc05cb..747bd4529a0 100644
--- a/spec/services/projects/hashed_storage/migrate_repository_service_spec.rb
+++ b/spec/services/projects/hashed_storage/migrate_repository_service_spec.rb
@@ -2,7 +2,7 @@ require 'spec_helper'
describe Projects::HashedStorage::MigrateRepositoryService do
let(:gitlab_shell) { Gitlab::Shell.new }
- let(:project) { create(:project, :repository, :wiki_repo) }
+ let(:project) { create(:project, :legacy_storage, :repository, :wiki_repo) }
let(:service) { described_class.new(project) }
let(:legacy_storage) { Storage::LegacyProject.new(project) }
let(:hashed_storage) { Storage::HashedProject.new(project) }
diff --git a/spec/services/projects/hashed_storage_migration_service_spec.rb b/spec/services/projects/hashed_storage_migration_service_spec.rb
index 466f0b5d7c2..e8e18bb3ac0 100644
--- a/spec/services/projects/hashed_storage_migration_service_spec.rb
+++ b/spec/services/projects/hashed_storage_migration_service_spec.rb
@@ -1,7 +1,7 @@
require 'spec_helper'
describe Projects::HashedStorageMigrationService do
- let(:project) { create(:project, :empty_repo, :wiki_repo) }
+ let(:project) { create(:project, :empty_repo, :wiki_repo, :legacy_storage) }
subject(:service) { described_class.new(project) }
describe '#execute' do
diff --git a/spec/services/projects/transfer_service_spec.rb b/spec/services/projects/transfer_service_spec.rb
index ef68742a463..ae0e22e3dc0 100644
--- a/spec/services/projects/transfer_service_spec.rb
+++ b/spec/services/projects/transfer_service_spec.rb
@@ -4,7 +4,7 @@ describe Projects::TransferService do
let(:gitlab_shell) { Gitlab::Shell.new }
let(:user) { create(:user) }
let(:group) { create(:group) }
- let(:project) { create(:project, :repository, namespace: user.namespace) }
+ let(:project) { create(:project, :repository, :legacy_storage, namespace: user.namespace) }
context 'namespace -> namespace' do
before do
@@ -214,7 +214,7 @@ describe Projects::TransferService do
end
context 'when hashed storage in use' do
- let(:hashed_project) { create(:project, :repository, :hashed, namespace: user.namespace) }
+ let(:hashed_project) { create(:project, :repository, namespace: user.namespace) }
before do
group.add_owner(user)
diff --git a/spec/services/projects/update_service_spec.rb b/spec/services/projects/update_service_spec.rb
index fc6aa713d6f..a0b97ceead9 100644
--- a/spec/services/projects/update_service_spec.rb
+++ b/spec/services/projects/update_service_spec.rb
@@ -150,6 +150,8 @@ describe Projects::UpdateService do
let(:repository_storage_path) { Gitlab.config.repositories.storages[repository_storage]['path'] }
context 'with legacy storage' do
+ let(:project) { create(:project, :legacy_storage, :repository, creator: user, namespace: user.namespace) }
+
before do
gitlab_shell.add_repository(repository_storage, "#{user.namespace.full_path}/existing")
end
diff --git a/spec/services/search/snippet_service_spec.rb b/spec/services/search/snippet_service_spec.rb
index bc7885b03d9..8ad162ad66e 100644
--- a/spec/services/search/snippet_service_spec.rb
+++ b/spec/services/search/snippet_service_spec.rb
@@ -2,7 +2,7 @@ require 'spec_helper'
describe Search::SnippetService do
let(:author) { create(:author) }
- let(:project) { create(:project) }
+ let(:project) { create(:project, :public) }
let!(:public_snippet) { create(:snippet, :public, content: 'password: XXX') }
let!(:internal_snippet) { create(:snippet, :internal, content: 'password: XXX') }
diff --git a/spec/services/users/destroy_service_spec.rb b/spec/services/users/destroy_service_spec.rb
index bb3d73edf8e..11c75ddfcf8 100644
--- a/spec/services/users/destroy_service_spec.rb
+++ b/spec/services/users/destroy_service_spec.rb
@@ -173,7 +173,7 @@ describe Users::DestroyService do
end
context 'legacy storage' do
- let!(:project) { create(:project, :empty_repo, namespace: user.namespace) }
+ let!(:project) { create(:project, :empty_repo, :legacy_storage, namespace: user.namespace) }
it 'removes repository' do
expect(gitlab_shell.exists?(project.repository_storage_path, "#{project.disk_path}.git")).to be_falsey
@@ -181,7 +181,7 @@ describe Users::DestroyService do
end
context 'hashed storage' do
- let!(:project) { create(:project, :empty_repo, :hashed, namespace: user.namespace) }
+ let!(:project) { create(:project, :empty_repo, namespace: user.namespace) }
it 'removes repository' do
expect(gitlab_shell.exists?(project.repository_storage_path, "#{project.disk_path}.git")).to be_falsey
diff --git a/spec/support/controllers/githubish_import_controller_shared_examples.rb b/spec/support/controllers/githubish_import_controller_shared_examples.rb
index a0839eefe6c..3321f920666 100644
--- a/spec/support/controllers/githubish_import_controller_shared_examples.rb
+++ b/spec/support/controllers/githubish_import_controller_shared_examples.rb
@@ -92,6 +92,7 @@ end
shared_examples 'a GitHub-ish import controller: POST create' do
let(:user) { create(:user) }
+ let(:project) { create(:project) }
let(:provider_username) { user.username }
let(:provider_user) { OpenStruct.new(login: provider_username) }
let(:provider_repo) do
@@ -107,14 +108,34 @@ shared_examples 'a GitHub-ish import controller: POST create' do
assign_session_token(provider)
end
+ it 'returns 200 response when the project is imported successfully' do
+ allow(Gitlab::LegacyGithubImport::ProjectCreator)
+ .to receive(:new).with(provider_repo, provider_repo.name, user.namespace, user, access_params, type: provider)
+ .and_return(double(execute: project))
+
+ post :create, format: :json
+
+ expect(response).to have_gitlab_http_status(200)
+ end
+
+ it 'returns 422 response when the project could not be imported' do
+ allow(Gitlab::LegacyGithubImport::ProjectCreator)
+ .to receive(:new).with(provider_repo, provider_repo.name, user.namespace, user, access_params, type: provider)
+ .and_return(double(execute: build(:project)))
+
+ post :create, format: :json
+
+ expect(response).to have_gitlab_http_status(422)
+ end
+
context "when the repository owner is the provider user" do
context "when the provider user and GitLab user's usernames match" do
it "takes the current user's namespace" do
expect(Gitlab::LegacyGithubImport::ProjectCreator)
.to receive(:new).with(provider_repo, provider_repo.name, user.namespace, user, access_params, type: provider)
- .and_return(double(execute: true))
+ .and_return(double(execute: project))
- post :create, format: :js
+ post :create, format: :json
end
end
@@ -124,9 +145,9 @@ shared_examples 'a GitHub-ish import controller: POST create' do
it "takes the current user's namespace" do
expect(Gitlab::LegacyGithubImport::ProjectCreator)
.to receive(:new).with(provider_repo, provider_repo.name, user.namespace, user, access_params, type: provider)
- .and_return(double(execute: true))
+ .and_return(double(execute: project))
- post :create, format: :js
+ post :create, format: :json
end
end
end
@@ -151,9 +172,9 @@ shared_examples 'a GitHub-ish import controller: POST create' do
it "takes the existing namespace" do
expect(Gitlab::LegacyGithubImport::ProjectCreator)
.to receive(:new).with(provider_repo, provider_repo.name, existing_namespace, user, access_params, type: provider)
- .and_return(double(execute: true))
+ .and_return(double(execute: project))
- post :create, format: :js
+ post :create, format: :json
end
end
@@ -163,9 +184,9 @@ shared_examples 'a GitHub-ish import controller: POST create' do
expect(Gitlab::LegacyGithubImport::ProjectCreator)
.to receive(:new).with(provider_repo, provider_repo.name, user.namespace, user, access_params, type: provider)
- .and_return(double(execute: true))
+ .and_return(double(execute: project))
- post :create, format: :js
+ post :create, format: :json
end
end
end
@@ -174,17 +195,17 @@ shared_examples 'a GitHub-ish import controller: POST create' do
context "when current user can create namespaces" do
it "creates the namespace" do
expect(Gitlab::LegacyGithubImport::ProjectCreator)
- .to receive(:new).and_return(double(execute: true))
+ .to receive(:new).and_return(double(execute: project))
- expect { post :create, target_namespace: provider_repo.name, format: :js }.to change(Namespace, :count).by(1)
+ expect { post :create, target_namespace: provider_repo.name, format: :json }.to change(Namespace, :count).by(1)
end
it "takes the new namespace" do
expect(Gitlab::LegacyGithubImport::ProjectCreator)
.to receive(:new).with(provider_repo, provider_repo.name, an_instance_of(Group), user, access_params, type: provider)
- .and_return(double(execute: true))
+ .and_return(double(execute: project))
- post :create, target_namespace: provider_repo.name, format: :js
+ post :create, target_namespace: provider_repo.name, format: :json
end
end
@@ -195,17 +216,17 @@ shared_examples 'a GitHub-ish import controller: POST create' do
it "doesn't create the namespace" do
expect(Gitlab::LegacyGithubImport::ProjectCreator)
- .to receive(:new).and_return(double(execute: true))
+ .to receive(:new).and_return(double(execute: project))
- expect { post :create, format: :js }.not_to change(Namespace, :count)
+ expect { post :create, format: :json }.not_to change(Namespace, :count)
end
it "takes the current user's namespace" do
expect(Gitlab::LegacyGithubImport::ProjectCreator)
.to receive(:new).with(provider_repo, provider_repo.name, user.namespace, user, access_params, type: provider)
- .and_return(double(execute: true))
+ .and_return(double(execute: project))
- post :create, format: :js
+ post :create, format: :json
end
end
end
@@ -221,21 +242,21 @@ shared_examples 'a GitHub-ish import controller: POST create' do
it 'takes the selected namespace and name' do
expect(Gitlab::LegacyGithubImport::ProjectCreator)
.to receive(:new).with(provider_repo, test_name, test_namespace, user, access_params, type: provider)
- .and_return(double(execute: true))
+ .and_return(double(execute: project))
- post :create, { target_namespace: test_namespace.name, new_name: test_name, format: :js }
+ post :create, { target_namespace: test_namespace.name, new_name: test_name, format: :json }
end
it 'takes the selected name and default namespace' do
expect(Gitlab::LegacyGithubImport::ProjectCreator)
.to receive(:new).with(provider_repo, test_name, user.namespace, user, access_params, type: provider)
- .and_return(double(execute: true))
+ .and_return(double(execute: project))
- post :create, { new_name: test_name, format: :js }
+ post :create, { new_name: test_name, format: :json }
end
end
- context 'user has chosen an existing nested namespace and name for the project' do
+ context 'user has chosen an existing nested namespace and name for the project', :postgresql do
let(:parent_namespace) { create(:group, name: 'foo', owner: user) }
let(:nested_namespace) { create(:group, name: 'bar', parent: parent_namespace) }
let(:test_name) { 'test_name' }
@@ -247,63 +268,124 @@ shared_examples 'a GitHub-ish import controller: POST create' do
it 'takes the selected namespace and name' do
expect(Gitlab::LegacyGithubImport::ProjectCreator)
.to receive(:new).with(provider_repo, test_name, nested_namespace, user, access_params, type: provider)
- .and_return(double(execute: true))
+ .and_return(double(execute: project))
- post :create, { target_namespace: nested_namespace.full_path, new_name: test_name, format: :js }
+ post :create, { target_namespace: nested_namespace.full_path, new_name: test_name, format: :json }
end
end
- context 'user has chosen a non-existent nested namespaces and name for the project' do
+ context 'user has chosen a non-existent nested namespaces and name for the project', :postgresql do
let(:test_name) { 'test_name' }
it 'takes the selected namespace and name' do
expect(Gitlab::LegacyGithubImport::ProjectCreator)
.to receive(:new).with(provider_repo, test_name, kind_of(Namespace), user, access_params, type: provider)
- .and_return(double(execute: true))
+ .and_return(double(execute: project))
- post :create, { target_namespace: 'foo/bar', new_name: test_name, format: :js }
+ post :create, { target_namespace: 'foo/bar', new_name: test_name, format: :json }
end
it 'creates the namespaces' do
allow(Gitlab::LegacyGithubImport::ProjectCreator)
.to receive(:new).with(provider_repo, test_name, kind_of(Namespace), user, access_params, type: provider)
- .and_return(double(execute: true))
+ .and_return(double(execute: project))
- expect { post :create, { target_namespace: 'foo/bar', new_name: test_name, format: :js } }
+ expect { post :create, { target_namespace: 'foo/bar', new_name: test_name, format: :json } }
.to change { Namespace.count }.by(2)
end
it 'new namespace has the right parent' do
allow(Gitlab::LegacyGithubImport::ProjectCreator)
.to receive(:new).with(provider_repo, test_name, kind_of(Namespace), user, access_params, type: provider)
- .and_return(double(execute: true))
+ .and_return(double(execute: project))
- post :create, { target_namespace: 'foo/bar', new_name: test_name, format: :js }
+ post :create, { target_namespace: 'foo/bar', new_name: test_name, format: :json }
expect(Namespace.find_by_path_or_name('bar').parent.path).to eq('foo')
end
end
- context 'user has chosen existent and non-existent nested namespaces and name for the project' do
+ context 'user has chosen existent and non-existent nested namespaces and name for the project', :postgresql do
let(:test_name) { 'test_name' }
let!(:parent_namespace) { create(:group, name: 'foo', owner: user) }
+ before do
+ parent_namespace.add_owner(user)
+ end
+
it 'takes the selected namespace and name' do
expect(Gitlab::LegacyGithubImport::ProjectCreator)
.to receive(:new).with(provider_repo, test_name, kind_of(Namespace), user, access_params, type: provider)
- .and_return(double(execute: true))
+ .and_return(double(execute: project))
- post :create, { target_namespace: 'foo/foobar/bar', new_name: test_name, format: :js }
+ post :create, { target_namespace: 'foo/foobar/bar', new_name: test_name, format: :json }
end
it 'creates the namespaces' do
allow(Gitlab::LegacyGithubImport::ProjectCreator)
.to receive(:new).with(provider_repo, test_name, kind_of(Namespace), user, access_params, type: provider)
- .and_return(double(execute: true))
+ .and_return(double(execute: project))
- expect { post :create, { target_namespace: 'foo/foobar/bar', new_name: test_name, format: :js } }
+ expect { post :create, { target_namespace: 'foo/foobar/bar', new_name: test_name, format: :json } }
.to change { Namespace.count }.by(2)
end
+
+ it 'does not create a new namespace under the user namespace' do
+ expect(Gitlab::LegacyGithubImport::ProjectCreator)
+ .to receive(:new).with(provider_repo, test_name, user.namespace, user, access_params, type: provider)
+ .and_return(double(execute: build_stubbed(:project)))
+
+ expect { post :create, { target_namespace: "#{user.namespace_path}/test_group", new_name: test_name, format: :js } }
+ .not_to change { Namespace.count }
+ end
+ end
+
+ context 'user cannot create a subgroup inside a group is not a member of' do
+ let(:test_name) { 'test_name' }
+ let!(:parent_namespace) { create(:group, name: 'foo') }
+
+ it 'does not take the selected namespace and name' do
+ expect(Gitlab::LegacyGithubImport::ProjectCreator)
+ .to receive(:new).with(provider_repo, test_name, user.namespace, user, access_params, type: provider)
+ .and_return(double(execute: build_stubbed(:project)))
+
+ post :create, { target_namespace: 'foo/foobar/bar', new_name: test_name, format: :js }
+ end
+
+ it 'does not create the namespaces' do
+ allow(Gitlab::LegacyGithubImport::ProjectCreator)
+ .to receive(:new).with(provider_repo, test_name, kind_of(Namespace), user, access_params, type: provider)
+ .and_return(double(execute: build_stubbed(:project)))
+
+ expect { post :create, { target_namespace: 'foo/foobar/bar', new_name: test_name, format: :js } }
+ .not_to change { Namespace.count }
+ end
+ end
+
+ context 'user can use a group without having permissions to create a group' do
+ let(:test_name) { 'test_name' }
+ let!(:group) { create(:group, name: 'foo') }
+
+ it 'takes the selected namespace and name' do
+ group.add_owner(user)
+ user.update!(can_create_group: false)
+
+ expect(Gitlab::LegacyGithubImport::ProjectCreator)
+ .to receive(:new).with(provider_repo, test_name, group, user, access_params, type: provider)
+ .and_return(double(execute: build_stubbed(:project)))
+
+ post :create, { target_namespace: 'foo', new_name: test_name, format: :js }
+ end
+ end
+
+ context 'when user can not create projects in the chosen namespace' do
+ it 'returns 422 response' do
+ other_namespace = create(:group, name: 'other_namespace')
+
+ post :create, { target_namespace: other_namespace.name, format: :json }
+
+ expect(response).to have_gitlab_http_status(422)
+ end
end
end
end
diff --git a/spec/support/features/variable_list_shared_examples.rb b/spec/support/features/variable_list_shared_examples.rb
index 83bf06b6727..4315bf5d037 100644
--- a/spec/support/features/variable_list_shared_examples.rb
+++ b/spec/support/features/variable_list_shared_examples.rb
@@ -41,13 +41,13 @@ shared_examples 'variable list' do
end
end
- it 'adds new unprotected variable' do
+ it 'adds new protected variable' do
page.within('.js-ci-variable-list-section .js-row:last-child') do
find('.js-ci-variable-input-key').set('key')
find('.js-ci-variable-input-value').set('key value')
find('.ci-variable-protected-item .js-project-feature-toggle').click
- expect(find('.js-ci-variable-input-protected', visible: false).value).to eq('false')
+ expect(find('.js-ci-variable-input-protected', visible: false).value).to eq('true')
end
click_button('Save variables')
@@ -59,7 +59,7 @@ shared_examples 'variable list' do
page.within('.js-ci-variable-list-section .js-row:nth-child(1)') do
expect(find('.js-ci-variable-input-key').value).to eq('key')
expect(find('.js-ci-variable-input-value', visible: false).value).to eq('key value')
- expect(find('.js-ci-variable-input-protected', visible: false).value).to eq('false')
+ expect(find('.js-ci-variable-input-protected', visible: false).value).to eq('true')
end
end
@@ -143,7 +143,6 @@ shared_examples 'variable list' do
page.within('.js-ci-variable-list-section .js-row:last-child') do
find('.js-ci-variable-input-key').set('unprotected_key')
find('.js-ci-variable-input-value').set('unprotected_value')
- find('.ci-variable-protected-item .js-project-feature-toggle').click
expect(find('.js-ci-variable-input-protected', visible: false).value).to eq('false')
end
@@ -178,6 +177,7 @@ shared_examples 'variable list' do
page.within('.js-ci-variable-list-section .js-row:last-child') do
find('.js-ci-variable-input-key').set('protected_key')
find('.js-ci-variable-input-value').set('protected_value')
+ find('.ci-variable-protected-item .js-project-feature-toggle').click
expect(find('.js-ci-variable-input-protected', visible: false).value).to eq('true')
end
diff --git a/spec/support/migrations_helpers.rb b/spec/support/migrations_helpers.rb
index ba4a1bee089..06322aa0586 100644
--- a/spec/support/migrations_helpers.rb
+++ b/spec/support/migrations_helpers.rb
@@ -25,14 +25,19 @@ module MigrationsHelpers
clear_schema_cache!
# Reset column information for the most offending classes **after** we
- # migrated the schema up, otherwise, column information could be outdated
- ActiveRecord::Base.descendants.each { |klass| klass.reset_column_information }
+ # migrated the schema up, otherwise, column information could be
+ # outdated. We have a separate method for this so we can override it in EE.
+ ActiveRecord::Base.descendants.each(&method(:reset_column_information))
# Without that, we get errors because of missing attributes, e.g.
# super: no superclass method `elasticsearch_indexing' for #<ApplicationSetting:0x00007f85628508d8>
ApplicationSetting.define_attribute_methods
end
+ def reset_column_information(klass)
+ klass.reset_column_information
+ end
+
def previous_migration
migrations.each_cons(2) do |previous, migration|
break previous if migration.name == described_class.name
diff --git a/spec/support/snippet_visibility.rb b/spec/support/snippet_visibility.rb
new file mode 100644
index 00000000000..1cb904823d2
--- /dev/null
+++ b/spec/support/snippet_visibility.rb
@@ -0,0 +1,304 @@
+RSpec.shared_examples 'snippet visibility' do
+ let!(:author) { create(:user) }
+ let!(:member) { create(:user) }
+ let!(:external) { create(:user, :external) }
+
+ let!(:snippet_type_visibilities) do
+ {
+ public: Snippet::PUBLIC,
+ internal: Snippet::INTERNAL,
+ private: Snippet::PRIVATE
+ }
+ end
+
+ context "For project snippets" do
+ let!(:users) do
+ {
+ unauthenticated: nil,
+ external: external,
+ non_member: create(:user),
+ member: member,
+ author: author
+ }
+ end
+
+ let!(:project_type_visibilities) do
+ {
+ public: Gitlab::VisibilityLevel::PUBLIC,
+ internal: Gitlab::VisibilityLevel::INTERNAL,
+ private: Gitlab::VisibilityLevel::PRIVATE
+ }
+ end
+
+ let(:project_feature_visibilities) do
+ {
+ enabled: ProjectFeature::ENABLED,
+ private: ProjectFeature::PRIVATE,
+ disabled: ProjectFeature::DISABLED
+ }
+ end
+
+ where(:project_type, :feature_visibility, :user_type, :snippet_type, :outcome) do
+ [
+ # Public projects
+ [:public, :enabled, :unauthenticated, :public, true],
+ [:public, :enabled, :unauthenticated, :internal, false],
+ [:public, :enabled, :unauthenticated, :private, false],
+
+ [:public, :enabled, :external, :public, true],
+ [:public, :enabled, :external, :internal, false],
+ [:public, :enabled, :external, :private, false],
+
+ [:public, :enabled, :non_member, :public, true],
+ [:public, :enabled, :non_member, :internal, true],
+ [:public, :enabled, :non_member, :private, false],
+
+ [:public, :enabled, :member, :public, true],
+ [:public, :enabled, :member, :internal, true],
+ [:public, :enabled, :member, :private, true],
+
+ [:public, :enabled, :author, :public, true],
+ [:public, :enabled, :author, :internal, true],
+ [:public, :enabled, :author, :private, true],
+
+ [:public, :private, :unauthenticated, :public, false],
+ [:public, :private, :unauthenticated, :internal, false],
+ [:public, :private, :unauthenticated, :private, false],
+
+ [:public, :private, :external, :public, false],
+ [:public, :private, :external, :internal, false],
+ [:public, :private, :external, :private, false],
+
+ [:public, :private, :non_member, :public, false],
+ [:public, :private, :non_member, :internal, false],
+ [:public, :private, :non_member, :private, false],
+
+ [:public, :private, :member, :public, true],
+ [:public, :private, :member, :internal, true],
+ [:public, :private, :member, :private, true],
+
+ [:public, :private, :author, :public, true],
+ [:public, :private, :author, :internal, true],
+ [:public, :private, :author, :private, true],
+
+ [:public, :disabled, :unauthenticated, :public, false],
+ [:public, :disabled, :unauthenticated, :internal, false],
+ [:public, :disabled, :unauthenticated, :private, false],
+
+ [:public, :disabled, :external, :public, false],
+ [:public, :disabled, :external, :internal, false],
+ [:public, :disabled, :external, :private, false],
+
+ [:public, :disabled, :non_member, :public, false],
+ [:public, :disabled, :non_member, :internal, false],
+ [:public, :disabled, :non_member, :private, false],
+
+ [:public, :disabled, :member, :public, false],
+ [:public, :disabled, :member, :internal, false],
+ [:public, :disabled, :member, :private, false],
+
+ [:public, :disabled, :author, :public, false],
+ [:public, :disabled, :author, :internal, false],
+ [:public, :disabled, :author, :private, false],
+
+ # Internal projects
+ [:internal, :enabled, :unauthenticated, :public, false],
+ [:internal, :enabled, :unauthenticated, :internal, false],
+ [:internal, :enabled, :unauthenticated, :private, false],
+
+ [:internal, :enabled, :external, :public, false],
+ [:internal, :enabled, :external, :internal, false],
+ [:internal, :enabled, :external, :private, false],
+
+ [:internal, :enabled, :non_member, :public, true],
+ [:internal, :enabled, :non_member, :internal, true],
+ [:internal, :enabled, :non_member, :private, false],
+
+ [:internal, :enabled, :member, :public, true],
+ [:internal, :enabled, :member, :internal, true],
+ [:internal, :enabled, :member, :private, true],
+
+ [:internal, :enabled, :author, :public, true],
+ [:internal, :enabled, :author, :internal, true],
+ [:internal, :enabled, :author, :private, true],
+
+ [:internal, :private, :unauthenticated, :public, false],
+ [:internal, :private, :unauthenticated, :internal, false],
+ [:internal, :private, :unauthenticated, :private, false],
+
+ [:internal, :private, :external, :public, false],
+ [:internal, :private, :external, :internal, false],
+ [:internal, :private, :external, :private, false],
+
+ [:internal, :private, :non_member, :public, false],
+ [:internal, :private, :non_member, :internal, false],
+ [:internal, :private, :non_member, :private, false],
+
+ [:internal, :private, :member, :public, true],
+ [:internal, :private, :member, :internal, true],
+ [:internal, :private, :member, :private, true],
+
+ [:internal, :private, :author, :public, true],
+ [:internal, :private, :author, :internal, true],
+ [:internal, :private, :author, :private, true],
+
+ [:internal, :disabled, :unauthenticated, :public, false],
+ [:internal, :disabled, :unauthenticated, :internal, false],
+ [:internal, :disabled, :unauthenticated, :private, false],
+
+ [:internal, :disabled, :external, :public, false],
+ [:internal, :disabled, :external, :internal, false],
+ [:internal, :disabled, :external, :private, false],
+
+ [:internal, :disabled, :non_member, :public, false],
+ [:internal, :disabled, :non_member, :internal, false],
+ [:internal, :disabled, :non_member, :private, false],
+
+ [:internal, :disabled, :member, :public, false],
+ [:internal, :disabled, :member, :internal, false],
+ [:internal, :disabled, :member, :private, false],
+
+ [:internal, :disabled, :author, :public, false],
+ [:internal, :disabled, :author, :internal, false],
+ [:internal, :disabled, :author, :private, false],
+
+ # Private projects
+ [:private, :enabled, :unauthenticated, :public, false],
+ [:private, :enabled, :unauthenticated, :internal, false],
+ [:private, :enabled, :unauthenticated, :private, false],
+
+ [:private, :enabled, :external, :public, true],
+ [:private, :enabled, :external, :internal, true],
+ [:private, :enabled, :external, :private, true],
+
+ [:private, :enabled, :non_member, :public, false],
+ [:private, :enabled, :non_member, :internal, false],
+ [:private, :enabled, :non_member, :private, false],
+
+ [:private, :enabled, :member, :public, true],
+ [:private, :enabled, :member, :internal, true],
+ [:private, :enabled, :member, :private, true],
+
+ [:private, :enabled, :author, :public, true],
+ [:private, :enabled, :author, :internal, true],
+ [:private, :enabled, :author, :private, true],
+
+ [:private, :private, :unauthenticated, :public, false],
+ [:private, :private, :unauthenticated, :internal, false],
+ [:private, :private, :unauthenticated, :private, false],
+
+ [:private, :private, :external, :public, true],
+ [:private, :private, :external, :internal, true],
+ [:private, :private, :external, :private, true],
+
+ [:private, :private, :non_member, :public, false],
+ [:private, :private, :non_member, :internal, false],
+ [:private, :private, :non_member, :private, false],
+
+ [:private, :private, :member, :public, true],
+ [:private, :private, :member, :internal, true],
+ [:private, :private, :member, :private, true],
+
+ [:private, :private, :author, :public, true],
+ [:private, :private, :author, :internal, true],
+ [:private, :private, :author, :private, true],
+
+ [:private, :disabled, :unauthenticated, :public, false],
+ [:private, :disabled, :unauthenticated, :internal, false],
+ [:private, :disabled, :unauthenticated, :private, false],
+
+ [:private, :disabled, :external, :public, false],
+ [:private, :disabled, :external, :internal, false],
+ [:private, :disabled, :external, :private, false],
+
+ [:private, :disabled, :non_member, :public, false],
+ [:private, :disabled, :non_member, :internal, false],
+ [:private, :disabled, :non_member, :private, false],
+
+ [:private, :disabled, :member, :public, false],
+ [:private, :disabled, :member, :internal, false],
+ [:private, :disabled, :member, :private, false],
+
+ [:private, :disabled, :author, :public, false],
+ [:private, :disabled, :author, :internal, false],
+ [:private, :disabled, :author, :private, false]
+ ]
+ end
+
+ with_them do
+ let!(:project) { create(:project, visibility_level: project_type_visibilities[project_type]) }
+ let!(:project_feature) { project.project_feature.update_column(:snippets_access_level, project_feature_visibilities[feature_visibility]) }
+ let!(:user) { users[user_type] }
+ let!(:snippet) { create(:project_snippet, visibility_level: snippet_type_visibilities[snippet_type], project: project, author: author) }
+ let!(:members) do
+ project.add_developer(author)
+ project.add_developer(member)
+ project.add_developer(external) if project.private?
+ end
+
+ context "For #{params[:project_type]} project and #{params[:user_type]} users" do
+ it 'should agree with the read_project_snippet policy' do
+ expect(can?(user, :read_project_snippet, snippet)).to eq(outcome)
+ end
+
+ it 'should return proper outcome' do
+ results = described_class.new(user, project: project).execute
+ expect(results.include?(snippet)).to eq(outcome)
+ end
+ end
+
+ context "Without a given project and #{params[:user_type]} users" do
+ it 'should return proper outcome' do
+ results = described_class.new(user).execute
+ expect(results.include?(snippet)).to eq(outcome)
+ end
+ end
+ end
+ end
+
+ context 'For personal snippets' do
+ let!(:users) do
+ {
+ unauthenticated: nil,
+ external: external,
+ non_member: create(:user),
+ author: author
+ }
+ end
+
+ where(:snippet_visibility, :user_type, :outcome) do
+ [
+ [:public, :unauthenticated, true],
+ [:public, :external, true],
+ [:public, :non_member, true],
+ [:public, :author, true],
+
+ [:internal, :unauthenticated, false],
+ [:internal, :external, false],
+ [:internal, :non_member, true],
+ [:internal, :author, true],
+
+ [:private, :unauthenticated, false],
+ [:private, :external, false],
+ [:private, :non_member, false],
+ [:private, :author, true]
+ ]
+ end
+
+ with_them do
+ let!(:user) { users[user_type] }
+ let!(:snippet) { create(:personal_snippet, visibility_level: snippet_type_visibilities[snippet_visibility], author: author) }
+
+ context "For personal and #{params[:snippet_visibility]} snippets with #{params[:user_type]} user" do
+ it 'should agree with read_personal_snippet policy' do
+ expect(can?(user, :read_personal_snippet, snippet)).to eq(outcome)
+ end
+
+ it 'should return proper outcome' do
+ results = described_class.new(user).execute
+ expect(results.include?(snippet)).to eq(outcome)
+ end
+ end
+ end
+ end
+end
diff --git a/spec/uploaders/file_uploader_spec.rb b/spec/uploaders/file_uploader_spec.rb
index 6a92e7fae51..b42ce982b27 100644
--- a/spec/uploaders/file_uploader_spec.rb
+++ b/spec/uploaders/file_uploader_spec.rb
@@ -2,7 +2,7 @@ require 'spec_helper'
describe FileUploader do
let(:group) { create(:group, name: 'awesome') }
- let(:project) { create(:project, namespace: group, name: 'project') }
+ let(:project) { create(:project, :legacy_storage, namespace: group, name: 'project') }
let(:uploader) { described_class.new(project) }
let(:upload) { double(model: project, path: 'secret/foo.jpg') }
@@ -16,12 +16,12 @@ describe FileUploader do
shared_examples 'uses hashed storage' do
context 'when rolled out attachments' do
+ let(:project) { build_stubbed(:project, namespace: group, name: 'project') }
+
before do
allow(project).to receive(:disk_path).and_return('ca/fe/fe/ed')
end
- let(:project) { build_stubbed(:project, :hashed, namespace: group, name: 'project') }
-
it_behaves_like 'builds correct paths',
store_dir: %r{ca/fe/fe/ed/\h+},
absolute_path: %r{#{described_class.root}/ca/fe/fe/ed/secret/foo.jpg}
diff --git a/spec/workers/repository_fork_worker_spec.rb b/spec/workers/repository_fork_worker_spec.rb
index 4912baa348c..6c66658d8c3 100644
--- a/spec/workers/repository_fork_worker_spec.rb
+++ b/spec/workers/repository_fork_worker_spec.rb
@@ -68,7 +68,7 @@ describe RepositoryForkWorker do
end
it "handles bad fork" do
- error_message = "Unable to fork project #{fork_project.id} for repository #{project.full_path} -> #{fork_project.full_path}"
+ error_message = "Unable to fork project #{fork_project.id} for repository #{project.disk_path} -> #{fork_project.disk_path}"
expect_fork_repository.and_return(false)
diff --git a/spec/workers/storage_migrator_worker_spec.rb b/spec/workers/storage_migrator_worker_spec.rb
index 8619ff2f7da..ff625164142 100644
--- a/spec/workers/storage_migrator_worker_spec.rb
+++ b/spec/workers/storage_migrator_worker_spec.rb
@@ -2,7 +2,7 @@ require 'spec_helper'
describe StorageMigratorWorker do
subject(:worker) { described_class.new }
- let(:projects) { create_list(:project, 2) }
+ let(:projects) { create_list(:project, 2, :legacy_storage) }
describe '#perform' do
let(:ids) { projects.map(&:id) }
diff --git a/vendor/assets/javascripts/jquery.waitforimages.js b/vendor/assets/javascripts/jquery.waitforimages.js
deleted file mode 100644
index 95b39c2e074..00000000000
--- a/vendor/assets/javascripts/jquery.waitforimages.js
+++ /dev/null
@@ -1,144 +0,0 @@
-/*
- * waitForImages 1.4
- * -----------------
- * Provides a callback when all images have loaded in your given selector.
- * http://www.alexanderdickson.com/
- *
- *
- * Copyright (c) 2011 Alex Dickson
- * Licensed under the MIT licenses.
- * See website for more info.
- *
- */
-
-;(function($) {
- // Namespace all events.
- var eventNamespace = 'waitForImages';
-
- // CSS properties which contain references to images.
- $.waitForImages = {
- hasImageProperties: [
- 'backgroundImage',
- 'listStyleImage',
- 'borderImage',
- 'borderCornerImage'
- ]
- };
-
- // Custom selector to find `img` elements that have a valid `src` attribute and have not already loaded.
- $.expr[':'].uncached = function(obj) {
- // Ensure we are dealing with an `img` element with a valid `src` attribute.
- if ( ! $(obj).is('img[src!=""]')) {
- return false;
- }
-
- // Firefox's `complete` property will always be`true` even if the image has not been downloaded.
- // Doing it this way works in Firefox.
- var img = document.createElement('img');
- img.src = obj.src;
- return ! img.complete;
- };
-
- $.fn.waitForImages = function(finishedCallback, eachCallback, waitForAll) {
-
- // Handle options object.
- if ($.isPlainObject(arguments[0])) {
- eachCallback = finishedCallback.each;
- waitForAll = finishedCallback.waitForAll;
- finishedCallback = finishedCallback.finished;
- }
-
- // Handle missing callbacks.
- finishedCallback = finishedCallback || $.noop;
- eachCallback = eachCallback || $.noop;
-
- // Convert waitForAll to Boolean
- waitForAll = !! waitForAll;
-
- // Ensure callbacks are functions.
- if (!$.isFunction(finishedCallback) || !$.isFunction(eachCallback)) {
- throw new TypeError('An invalid callback was supplied.');
- };
-
- return this.each(function() {
- // Build a list of all imgs, dependent on what images will be considered.
- var obj = $(this),
- allImgs = [];
-
- if (waitForAll) {
- // CSS properties which may contain an image.
- var hasImgProperties = $.waitForImages.hasImageProperties || [],
- matchUrl = /url\((['"]?)(.*?)\1\)/g;
-
- // Get all elements, as any one of them could have a background image.
- obj.find('*').each(function() {
- var element = $(this);
-
- // If an `img` element, add it. But keep iterating in case it has a background image too.
- if (element.is('img:uncached')) {
- allImgs.push({
- src: element.attr('src'),
- element: element[0]
- });
- }
-
- $.each(hasImgProperties, function(i, property) {
- var propertyValue = element.css(property);
- // If it doesn't contain this property, skip.
- if ( ! propertyValue) {
- return true;
- }
-
- // Get all url() of this element.
- var match;
- while (match = matchUrl.exec(propertyValue)) {
- allImgs.push({
- src: match[2],
- element: element[0]
- });
- };
- });
- });
- } else {
- // For images only, the task is simpler.
- obj
- .find('img:uncached')
- .each(function() {
- allImgs.push({
- src: this.src,
- element: this
- });
- });
- };
-
- var allImgsLength = allImgs.length,
- allImgsLoaded = 0;
-
- // If no images found, don't bother.
- if (allImgsLength == 0) {
- finishedCallback.call(obj[0]);
- };
-
- $.each(allImgs, function(i, img) {
-
- var image = new Image;
-
- // Handle the image loading and error with the same callback.
- $(image).bind('load.' + eventNamespace + ' error.' + eventNamespace, function(event) {
- allImgsLoaded++;
-
- // If an error occurred with loading the image, set the third argument accordingly.
- eachCallback.call(img.element, allImgsLoaded, allImgsLength, event.type == 'load');
-
- if (allImgsLoaded == allImgsLength) {
- finishedCallback.call(obj[0]);
- return false;
- };
-
- });
-
- image.src = img.src;
- });
- });
- };
-})(jQuery);
diff --git a/vendor/gitignore/Android.gitignore b/vendor/gitignore/Android.gitignore
index addf405e4f5..d57137223ed 100644
--- a/vendor/gitignore/Android.gitignore
+++ b/vendor/gitignore/Android.gitignore
@@ -54,3 +54,10 @@ google-services.json
freeline.py
freeline/
freeline_project_description.json
+
+# fastlane
+fastlane/report.xml
+fastlane/Preview.html
+fastlane/screenshots
+fastlane/test_output
+fastlane/readme.md
diff --git a/vendor/gitignore/Dart.gitignore b/vendor/gitignore/Dart.gitignore
index 4d2a4d6db7c..58950beb4fa 100644
--- a/vendor/gitignore/Dart.gitignore
+++ b/vendor/gitignore/Dart.gitignore
@@ -1,6 +1,7 @@
# See https://www.dartlang.org/tools/private-files.html
# Files and directories created by pub
+.dart_tool/
.packages
.pub/
build/
diff --git a/vendor/gitignore/Global/JetBrains.gitignore b/vendor/gitignore/Global/JetBrains.gitignore
index a30eacf1d98..9c01e12b050 100644
--- a/vendor/gitignore/Global/JetBrains.gitignore
+++ b/vendor/gitignore/Global/JetBrains.gitignore
@@ -1,4 +1,4 @@
-# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm
+# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and WebStorm
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
# User-specific stuff:
@@ -9,7 +9,6 @@
# Sensitive or high-churn files:
.idea/**/dataSources/
.idea/**/dataSources.ids
-.idea/**/dataSources.xml
.idea/**/dataSources.local.xml
.idea/**/sqlDataSources.xml
.idea/**/dynamic.xml
diff --git a/vendor/gitignore/Python.gitignore b/vendor/gitignore/Python.gitignore
index af2f537516d..b989be6ca15 100644
--- a/vendor/gitignore/Python.gitignore
+++ b/vendor/gitignore/Python.gitignore
@@ -45,6 +45,7 @@ nosetests.xml
coverage.xml
*.cover
.hypothesis/
+.pytest_cache/
# Translations
*.mo
diff --git a/vendor/gitignore/ROS.gitignore b/vendor/gitignore/ROS.gitignore
index 425641f2c3a..35d74bb771f 100644
--- a/vendor/gitignore/ROS.gitignore
+++ b/vendor/gitignore/ROS.gitignore
@@ -13,6 +13,8 @@ msg/*Feedback.msg
msg/*Goal.msg
msg/*Result.msg
msg/_*.py
+build_isolated/
+devel_isolated/
# Generated by dynamic reconfigure
*.cfgc
diff --git a/vendor/gitignore/TeX.gitignore b/vendor/gitignore/TeX.gitignore
index 9bb63365618..5359e544bcf 100644
--- a/vendor/gitignore/TeX.gitignore
+++ b/vendor/gitignore/TeX.gitignore
@@ -10,6 +10,7 @@
*.fot
*.cb
*.cb2
+.*.lb
## Intermediate documents:
*.dvi
diff --git a/vendor/gitignore/VisualStudio.gitignore b/vendor/gitignore/VisualStudio.gitignore
index d3d5371b415..c49041ff7d2 100644
--- a/vendor/gitignore/VisualStudio.gitignore
+++ b/vendor/gitignore/VisualStudio.gitignore
@@ -237,6 +237,7 @@ _UpgradeReport_Files/
Backup*/
UpgradeLog*.XML
UpgradeLog*.htm
+ServiceFabricBackup/
# SQL Server files
*.mdf
diff --git a/vendor/gitlab-ci-yml/Auto-DevOps.gitlab-ci.yml b/vendor/gitlab-ci-yml/Auto-DevOps.gitlab-ci.yml
index b2439d96e00..094d6791505 100644
--- a/vendor/gitlab-ci-yml/Auto-DevOps.gitlab-ci.yml
+++ b/vendor/gitlab-ci-yml/Auto-DevOps.gitlab-ci.yml
@@ -110,12 +110,15 @@ performance:
kubernetes: active
sast:
- image: registry.gitlab.com/gitlab-org/gl-sast:latest
+ image: docker:latest
variables:
- POSTGRES_DB: "false"
+ DOCKER_DRIVER: overlay2
allow_failure: true
+ services:
+ - docker:dind
script:
- - sast .
+ - setup_docker
+ - sast
artifacts:
paths: [gl-sast-report.json]
@@ -285,6 +288,12 @@ production:
export TILLER_NAMESPACE=$KUBE_NAMESPACE
function sast_container() {
+ if [[ -n "$CI_REGISTRY_USER" ]]; then
+ echo "Logging to GitLab Container Registry with CI credentials..."
+ docker login -u "$CI_REGISTRY_USER" -p "$CI_REGISTRY_PASSWORD" "$CI_REGISTRY"
+ echo ""
+ fi
+
docker run -d --name db arminc/clair-db:latest
docker run -p 6060:6060 --link db:postgres -d --name clair arminc/clair-local-scan:v2.0.1
apk add -U wget ca-certificates
@@ -309,7 +318,12 @@ production:
function sast() {
case "$CI_SERVER_VERSION" in
*-ee)
- /app/bin/run "$@"
+ # Extract "MAJOR.MINOR" from CI_SERVER_VERSION and generate "MAJOR-MINOR-stable"
+ SAST_VERSION=$(echo "$CI_SERVER_VERSION" | sed 's/^\([0-9]*\)\.\([0-9]*\).*/\1-\2-stable/')
+
+ docker run --volume "$PWD:/code" \
+ --volume /var/run/docker.sock:/var/run/docker.sock \
+ "registry.gitlab.com/gitlab-org/security-products/sast:$SAST_VERSION" /app/bin/run /code
;;
*)
echo "GitLab EE is required"
@@ -346,6 +360,12 @@ production:
replicas="$new_replicas"
fi
+ if [[ "$CI_PROJECT_VISIBILITY" != "public" ]]; then
+ secret_name='gitlab-registry'
+ else
+ secret_name=''
+ fi
+
helm upgrade --install \
--wait \
--set service.enabled="$service_enabled" \
@@ -353,6 +373,7 @@ production:
--set image.repository="$CI_APPLICATION_REPOSITORY" \
--set image.tag="$CI_APPLICATION_TAG" \
--set image.pullPolicy=IfNotPresent \
+ --set image.secrets[0].name="$secret_name" \
--set application.track="$track" \
--set application.database_url="$DATABASE_URL" \
--set service.url="$CI_ENVIRONMENT_URL" \
@@ -482,6 +503,9 @@ production:
function create_secret() {
echo "Create secret..."
+ if [[ "$CI_PROJECT_VISIBILITY" == "public" ]]; then
+ return
+ fi
kubectl create secret -n "$KUBE_NAMESPACE" \
docker-registry gitlab-registry \
diff --git a/vendor/licenses.csv b/vendor/licenses.csv
index e3ccf080f74..8f127468e25 100644
--- a/vendor/licenses.csv
+++ b/vendor/licenses.csv
@@ -1,5 +1,22 @@
+@babel/code-frame,7.0.0-beta.32,MIT
+@babel/helper-function-name,7.0.0-beta.32,MIT
+@babel/helper-get-function-arity,7.0.0-beta.32,MIT
+@babel/template,7.0.0-beta.32,MIT
+@babel/traverse,7.0.0-beta.32,MIT
+@babel/types,7.0.0-beta.32,MIT
+@gitlab-org/gitlab-svgs,1.8.0,SEE LICENSE IN LICENSE
+@types/jquery,2.0.48,MIT
+JSONStream,1.3.2,MIT
RedCloth,4.3.2,MIT
+abbrev,1.0.9,ISC
+accepts,1.3.3,MIT
ace-rails-ap,4.1.2,MIT
+acorn,3.3.0,MIT
+acorn,4.0.13,MIT
+acorn,5.1.1,MIT
+acorn,5.3.0,MIT
+acorn-dynamic-import,2.0.2,MIT
+acorn-jsx,3.0.1,MIT
actionmailer,4.2.10,MIT
actionpack,4.2.10,MIT
actionview,4.2.10,MIT
@@ -9,70 +26,518 @@ activerecord,4.2.10,MIT
activesupport,4.2.10,MIT
acts-as-taggable-on,4.0.0,MIT
addressable,2.5.2,Apache 2.0
+addressparser,1.0.1,MIT
+after,0.8.2,MIT
+agent-base,2.1.1,MIT
+ajv,4.11.8,MIT
+ajv,5.2.2,MIT
+ajv,5.5.2,MIT
+ajv-keywords,1.5.1,MIT
+ajv-keywords,2.1.0,MIT
akismet,2.0.0,MIT
+align-text,0.1.4,MIT
allocations,1.0.5,MIT
+alphanum-sort,1.0.2,MIT
+amdefine,1.0.1,BSD-3-Clause OR MIT
+ansi-escapes,1.4.0,MIT
+ansi-html,0.0.5,"Apache, Version 2.0"
+ansi-html,0.0.7,Apache 2.0
+ansi-regex,2.1.1,MIT
+ansi-regex,3.0.0,MIT
+ansi-styles,2.2.1,MIT
+ansi-styles,3.2.0,MIT
+anymatch,1.3.2,ISC
+append-transform,0.4.0,MIT
+aproba,1.1.2,ISC
+are-we-there-yet,1.1.4,ISC
arel,6.0.4,MIT
+argparse,1.0.9,MIT
+arr-diff,2.0.0,MIT
+arr-flatten,1.0.1,MIT
+array-filter,0.0.1,MIT
+array-find,1.0.0,MIT
+array-find-index,1.0.2,MIT
+array-flatten,1.1.1,MIT
+array-flatten,2.1.1,MIT
+array-map,0.0.0,MIT
+array-reduce,0.0.0,MIT
+array-slice,0.2.3,MIT
+array-union,1.0.2,MIT
+array-uniq,1.0.3,MIT
+array-unique,0.2.1,MIT
+arraybuffer.slice,0.0.7,MIT
+arrify,1.0.1,MIT
asana,0.6.0,MIT
asciidoctor,1.5.3,MIT
asciidoctor-plantuml,0.0.7,MIT
+asn1,0.2.3,MIT
+asn1.js,4.9.1,MIT
+assert,1.4.1,MIT
+assert-plus,0.2.0,MIT
+assert-plus,1.0.0,MIT
asset_sync,2.2.0,MIT
+ast-types,0.10.1,MIT
+astw,2.2.0,MIT
+async,0.9.2,MIT
+async,1.5.2,MIT
+async,2.1.5,MIT
+async,2.4.1,MIT
+async-each,1.0.1,MIT
+async-limiter,1.0.0,MIT
+asynckit,0.4.0,MIT
atomic,1.1.99,Apache 2.0
attr_encrypted,3.0.3,MIT
attr_required,1.0.0,MIT
+autoprefixer,6.7.7,MIT
autoprefixer-rails,6.2.3,MIT
+autosize,4.0.0,MIT
+aws-sign2,0.6.0,Apache 2.0
+aws-sign2,0.7.0,Apache 2.0
+aws4,1.6.0,MIT
axiom-types,0.1.1,MIT
+axios,0.15.3,MIT
+axios,0.17.1,MIT
+axios-mock-adapter,1.10.0,MIT
+babel-code-frame,6.26.0,MIT
+babel-core,6.26.0,MIT
+babel-eslint,8.0.2,MIT
+babel-generator,6.26.0,MIT
+babel-helper-bindify-decorators,6.24.1,MIT
+babel-helper-builder-binary-assignment-operator-visitor,6.24.1,MIT
+babel-helper-call-delegate,6.24.1,MIT
+babel-helper-define-map,6.26.0,MIT
+babel-helper-explode-assignable-expression,6.24.1,MIT
+babel-helper-explode-class,6.24.1,MIT
+babel-helper-function-name,6.24.1,MIT
+babel-helper-get-function-arity,6.24.1,MIT
+babel-helper-hoist-variables,6.24.1,MIT
+babel-helper-optimise-call-expression,6.24.1,MIT
+babel-helper-regex,6.26.0,MIT
+babel-helper-remap-async-to-generator,6.24.1,MIT
+babel-helper-replace-supers,6.24.1,MIT
+babel-helpers,6.24.1,MIT
+babel-loader,7.1.2,MIT
+babel-messages,6.23.0,MIT
+babel-plugin-check-es2015-constants,6.22.0,MIT
+babel-plugin-istanbul,4.1.5,New BSD
+babel-plugin-syntax-async-functions,6.13.0,MIT
+babel-plugin-syntax-async-generators,6.13.0,MIT
+babel-plugin-syntax-class-properties,6.13.0,MIT
+babel-plugin-syntax-decorators,6.13.0,MIT
+babel-plugin-syntax-dynamic-import,6.18.0,MIT
+babel-plugin-syntax-exponentiation-operator,6.13.0,MIT
+babel-plugin-syntax-object-rest-spread,6.13.0,MIT
+babel-plugin-syntax-trailing-function-commas,6.22.0,MIT
+babel-plugin-transform-async-generator-functions,6.24.1,MIT
+babel-plugin-transform-async-to-generator,6.24.1,MIT
+babel-plugin-transform-class-properties,6.24.1,MIT
+babel-plugin-transform-decorators,6.24.1,MIT
+babel-plugin-transform-define,1.3.0,MIT
+babel-plugin-transform-es2015-arrow-functions,6.22.0,MIT
+babel-plugin-transform-es2015-block-scoped-functions,6.22.0,MIT
+babel-plugin-transform-es2015-block-scoping,6.26.0,MIT
+babel-plugin-transform-es2015-classes,6.24.1,MIT
+babel-plugin-transform-es2015-computed-properties,6.24.1,MIT
+babel-plugin-transform-es2015-destructuring,6.23.0,MIT
+babel-plugin-transform-es2015-duplicate-keys,6.24.1,MIT
+babel-plugin-transform-es2015-for-of,6.23.0,MIT
+babel-plugin-transform-es2015-function-name,6.24.1,MIT
+babel-plugin-transform-es2015-literals,6.22.0,MIT
+babel-plugin-transform-es2015-modules-amd,6.24.1,MIT
+babel-plugin-transform-es2015-modules-commonjs,6.26.0,MIT
+babel-plugin-transform-es2015-modules-systemjs,6.24.1,MIT
+babel-plugin-transform-es2015-modules-umd,6.24.1,MIT
+babel-plugin-transform-es2015-object-super,6.24.1,MIT
+babel-plugin-transform-es2015-parameters,6.24.1,MIT
+babel-plugin-transform-es2015-shorthand-properties,6.24.1,MIT
+babel-plugin-transform-es2015-spread,6.22.0,MIT
+babel-plugin-transform-es2015-sticky-regex,6.24.1,MIT
+babel-plugin-transform-es2015-template-literals,6.22.0,MIT
+babel-plugin-transform-es2015-typeof-symbol,6.23.0,MIT
+babel-plugin-transform-es2015-unicode-regex,6.24.1,MIT
+babel-plugin-transform-exponentiation-operator,6.24.1,MIT
+babel-plugin-transform-object-rest-spread,6.23.0,MIT
+babel-plugin-transform-regenerator,6.26.0,MIT
+babel-plugin-transform-strict-mode,6.24.1,MIT
+babel-preset-es2015,6.24.1,MIT
+babel-preset-es2016,6.24.1,MIT
+babel-preset-es2017,6.24.1,MIT
+babel-preset-latest,6.24.1,MIT
+babel-preset-stage-2,6.24.1,MIT
+babel-preset-stage-3,6.24.1,MIT
+babel-register,6.26.0,MIT
+babel-runtime,6.26.0,MIT
+babel-template,6.26.0,MIT
+babel-traverse,6.26.0,MIT
+babel-types,6.26.0,MIT
babosa,1.0.2,MIT
+babylon,6.18.0,MIT
+babylon,7.0.0-beta.32,MIT
+backo2,1.0.2,MIT
+balanced-match,0.4.2,MIT
+balanced-match,1.0.0,MIT
base32,0.3.2,MIT
+base64-arraybuffer,0.1.5,MIT
+base64-js,1.2.0,MIT
+base64id,1.0.0,MIT
+batch,0.6.1,MIT
batch-loader,1.2.1,MIT
bcrypt,3.1.11,MIT
+bcrypt-pbkdf,1.0.1,New BSD
bcrypt_pbkdf,1.0.0,MIT
+better-assert,1.0.2,MIT
+big.js,3.1.3,MIT
+binary-extensions,1.10.0,MIT
bindata,2.4.1,ruby
+bl,1.1.2,MIT
+blackst0ne-mermaid,7.1.0-fixed,MIT
+blob,0.0.4,MIT*
+block-stream,0.0.9,ISC
+bluebird,2.11.0,MIT
+bluebird,3.5.0,MIT
+bn.js,4.11.6,MIT
+body-parser,1.17.2,MIT
+bonjour,3.5.0,MIT
+boom,2.10.1,New BSD
+boom,4.3.1,New BSD
+boom,5.2.0,New BSD
bootstrap-sass,3.3.6,MIT
bootstrap_form,2.7.0,MIT
+brace-expansion,1.1.8,MIT
+braces,0.1.5,MIT
+braces,1.8.5,MIT
+brorand,1.0.7,MIT
browser,2.2.0,MIT
+browser-pack,6.0.2,MIT
+browser-resolve,1.11.2,MIT
+browserify,14.5.0,MIT
+browserify-aes,1.0.6,MIT
+browserify-cipher,1.0.0,MIT
+browserify-des,1.0.0,MIT
+browserify-rsa,4.0.1,MIT
+browserify-sign,4.0.0,ISC
+browserify-zlib,0.1.4,MIT
+browserify-zlib,0.2.0,MIT
+browserslist,1.7.7,MIT
+buffer,4.9.1,MIT
+buffer,5.0.8,MIT
+buffer-indexof,1.1.0,MIT
+buffer-xor,1.0.3,MIT
builder,3.2.3,MIT
+buildmail,4.0.1,MIT
+builtin-modules,1.1.1,MIT
+builtin-status-codes,3.0.0,MIT
+bytes,2.4.0,MIT
+bytes,2.5.0,MIT
+bytes,3.0.0,MIT
+cached-path-relative,1.0.1,MIT
+caller-path,0.1.0,MIT
+callsite,1.0.0,MIT*
+callsites,0.2.0,MIT
+camelcase,1.2.1,MIT
+camelcase,2.1.1,MIT
+camelcase,3.0.0,MIT
+camelcase,4.1.0,MIT
+camelcase-keys,2.1.0,MIT
+caniuse-api,1.6.1,MIT
+caniuse-db,1.0.30000649,CC-BY-4.0
carrierwave,1.2.1,MIT
+caseless,0.11.0,Apache 2.0
+caseless,0.12.0,Apache 2.0
cause,0.1,MIT
+center-align,0.1.3,MIT
+chalk,1.1.3,MIT
+chalk,2.3.0,MIT
charlock_holmes,0.7.5,MIT
+chokidar,1.7.0,MIT
chronic,0.10.2,MIT
chronic_duration,0.10.6,MIT
chunky_png,1.3.5,MIT
+cipher-base,1.0.3,MIT
+circular-json,0.3.3,MIT
+circular-json,0.4.0,MIT
citrus,3.0.2,MIT
+clap,1.1.3,MIT
+classlist-polyfill,1.2.0,Unlicense
+cli-cursor,1.0.2,MIT
+cli-width,2.1.0,ISC
+clipboard,1.7.1,MIT
+cliui,2.1.0,ISC
+cliui,3.2.0,ISC
+clone,1.0.2,MIT
+co,3.0.6,MIT
+co,4.6.0,MIT
+coa,1.0.1,MIT
+code-point-at,1.1.0,MIT
coercible,1.0.0,MIT
+color,0.11.4,MIT
+color-convert,1.9.1,MIT
+color-name,1.1.2,MIT
+color-string,0.3.0,MIT
+colormin,1.1.2,MIT
+colors,1.1.2,MIT
+combine-lists,1.0.1,MIT
+combine-source-map,0.7.2,MIT
+combined-stream,1.0.5,MIT
+commander,2.9.0,MIT
+commondir,1.0.1,MIT
+component-bind,1.0.0,MIT*
+component-emitter,1.2.1,MIT
+component-inherit,0.0.3,MIT*
+compressible,2.0.11,MIT
+compression,1.7.0,MIT
+compression-webpack-plugin,1.0.0,MIT
+concat-map,0.0.1,MIT
+concat-stream,1.5.2,MIT
+concat-stream,1.6.0,MIT
concurrent-ruby-ext,1.0.5,MIT
+configstore,1.4.0,Simplified BSD
+connect,3.6.3,MIT
+connect-history-api-fallback,1.3.0,MIT
connection_pool,2.2.1,MIT
+console-browserify,1.1.0,MIT
+console-control-strings,1.1.0,ISC
+consolidate,0.14.5,MIT
+constants-browserify,1.0.0,MIT
+contains-path,0.1.0,MIT
+content-disposition,0.5.2,MIT
+content-type,1.0.2,MIT
+convert-source-map,1.1.3,MIT
+convert-source-map,1.5.0,MIT
+cookie,0.3.1,MIT
+cookie-signature,1.0.6,MIT
+copy-webpack-plugin,4.0.1,MIT
+core-js,2.3.0,MIT
+core-js,2.4.1,MIT
+core-js,2.5.1,MIT
+core-util-is,1.0.2,MIT
+cosmiconfig,2.1.1,MIT
crack,0.4.3,MIT
+create-ecdh,4.0.0,MIT
+create-hash,1.1.2,MIT
+create-hmac,1.1.4,MIT
creole,0.5.0,ruby
+cropper,2.3.0,MIT
+cross-spawn,5.1.0,MIT
+cryptiles,2.0.5,New BSD
+cryptiles,3.1.2,New BSD
+crypto-browserify,3.11.0,MIT
+crypto-browserify,3.12.0,MIT
+css-color-names,0.0.4,MIT
+css-loader,0.28.0,MIT
+css-selector-tokenizer,0.6.0,MIT
+css-selector-tokenizer,0.7.0,MIT
css_parser,1.5.0,MIT
+cssesc,0.1.0,MIT
+cssnano,3.10.0,MIT
+csso,2.3.2,MIT
+currently-unhandled,0.4.1,MIT
+custom-event,1.0.1,MIT
+d,0.1.1,MIT
+d,1.0.0,MIT
+d3,3.5.17,New BSD
+d3-array,1.2.1,New BSD
+d3-axis,1.0.8,New BSD
+d3-brush,1.0.4,New BSD
+d3-collection,1.0.4,New BSD
+d3-color,1.0.3,New BSD
+d3-dispatch,1.0.3,New BSD
+d3-drag,1.2.1,New BSD
+d3-ease,1.0.3,New BSD
+d3-format,1.2.1,New BSD
+d3-interpolate,1.1.6,New BSD
+d3-path,1.0.5,New BSD
+d3-scale,1.0.7,New BSD
+d3-selection,1.2.0,New BSD
+d3-shape,1.2.0,New BSD
+d3-time,1.0.8,New BSD
+d3-time-format,2.1.1,New BSD
+d3-timer,1.0.7,New BSD
+d3-transition,1.1.1,New BSD
d3_rails,3.5.11,MIT
+dagre-d3-renderer,0.4.24,MIT
+dagre-layout,0.8.0,MIT
+dashdash,1.14.1,MIT
+data-uri-to-buffer,1.2.0,MIT
+date-format,1.2.0,MIT
+date-now,0.1.4,MIT
+de-indent,1.0.2,MIT
+debug,2.2.0,MIT
+debug,2.6.7,MIT
+debug,2.6.8,MIT
+debug,2.6.9,MIT
+debug,3.1.0,MIT
debugger-ruby_core_source,1.3.8,MIT
+decamelize,1.2.0,MIT
deckar01-task_list,2.0.0,MIT
declarative,0.0.10,MIT
declarative-option,0.1.0,MIT
+decompress-response,3.3.0,MIT
+deep-equal,1.0.1,MIT
+deep-extend,0.4.2,MIT
+deep-is,0.1.3,MIT
+default-require-extensions,1.0.0,MIT
default_value_for,3.0.2,MIT
+define-properties,1.1.2,MIT
+defined,1.0.0,MIT
+degenerator,1.0.4,MIT
+del,2.2.2,MIT
+del,3.0.0,MIT
+delayed-stream,1.0.0,MIT
+delegate,3.1.2,MIT
+delegates,1.0.0,MIT
+depd,1.1.0,MIT
+depd,1.1.1,MIT
+deps-sort,2.0.0,MIT
+des.js,1.0.0,MIT
descendants_tracker,0.0.4,MIT
+destroy,1.0.4,MIT
+detect-indent,4.0.0,MIT
+detect-node,2.0.3,ISC
+detective,4.7.1,MIT
devise,4.2.0,MIT
devise-two-factor,3.0.0,MIT
+di,0.0.1,MIT
+diff,3.4.0,New BSD
diff-lcs,1.3,"MIT,Artistic-2.0,GPL-2.0+"
+diffie-hellman,5.0.2,MIT
diffy,3.1.0,MIT
+dns-equal,1.0.0,MIT
+dns-packet,1.2.2,MIT
+dns-txt,2.0.2,MIT
+doctrine,1.5.0,Simplified BSD
+doctrine,2.0.0,Apache 2.0
+document-register-element,1.3.0,MIT
+dom-serialize,2.2.1,MIT
+dom-serializer,0.1.0,MIT
+domain-browser,1.1.7,MIT
domain_name,0.5.20161021,"Simplified BSD,New BSD,Mozilla Public License 2.0"
+domelementtype,1.1.3,Simplified BSD
+domelementtype,1.3.0,Simplified BSD
+domhandler,2.4.1,Simplified BSD
+domutils,1.6.2,Simplified BSD
doorkeeper,4.2.6,MIT
doorkeeper-openid_connect,1.2.0,MIT
+double-ended-queue,2.1.0-0,MIT
+dropzone,4.2.0,MIT
dropzonejs-rails,0.7.2,MIT
+duplexer,0.1.1,MIT
+duplexer2,0.1.4,New BSD
+duplexer3,0.1.4,New BSD
+duplexify,3.5.1,MIT
+ecc-jsbn,0.1.1,MIT
+ee-first,1.1.1,MIT
+ejs,2.5.6,Apache 2.0
+electron-to-chromium,1.3.3,ISC
+elliptic,6.3.3,MIT
email_reply_trimmer,0.1.6,MIT
+emoji-unicode-version,0.2.1,MIT
+emojis-list,2.1.0,MIT
+encodeurl,1.0.1,MIT
encryptor,3.0.0,MIT
+end-of-stream,1.4.0,MIT
+engine.io,3.1.4,MIT
+engine.io-client,3.1.4,MIT
+engine.io-parser,2.1.2,MIT
+enhanced-resolve,0.9.1,MIT
+enhanced-resolve,3.4.1,MIT
+ent,2.2.0,MIT
+entities,1.1.1,Simplified BSD
equalizer,0.0.11,MIT
+errno,0.1.4,MIT
+error-ex,1.3.0,MIT
erubis,2.7.0,MIT
+es-abstract,1.8.2,MIT
+es-to-primitive,1.1.1,MIT
+es5-ext,0.10.24,MIT
+es6-iterator,2.0.1,MIT
+es6-map,0.1.5,MIT
+es6-promise,3.0.2,MIT
+es6-set,0.1.5,MIT
+es6-symbol,3.1.1,MIT
+es6-weak-map,2.0.1,MIT
+escape-html,1.0.3,MIT
+escape-string-regexp,1.0.5,MIT
escape_utils,1.1.1,MIT
+escodegen,1.8.1,Simplified BSD
+escodegen,1.9.0,Simplified BSD
+escope,3.6.0,Simplified BSD
+eslint,3.19.0,MIT
+eslint-config-airbnb-base,10.0.1,MIT
+eslint-import-resolver-node,0.2.3,MIT
+eslint-import-resolver-webpack,0.8.3,MIT
+eslint-module-utils,2.0.0,MIT
+eslint-plugin-filenames,1.1.0,MIT
+eslint-plugin-html,2.0.1,ISC
+eslint-plugin-import,2.2.0,MIT
+eslint-plugin-jasmine,2.2.0,MIT
+eslint-plugin-promise,3.5.0,ISC
+eslint-plugin-vue,4.0.1,MIT
+eslint-scope,3.7.1,Simplified BSD
+eslint-visitor-keys,1.0.0,Apache 2.0
+espree,3.5.0,Simplified BSD
+espree,3.5.2,Simplified BSD
+esprima,2.7.3,Simplified BSD
+esprima,3.1.3,Simplified BSD
+esprima,4.0.0,Simplified BSD
+esquery,1.0.0,New BSD
+esrecurse,4.1.0,Simplified BSD
+estraverse,1.9.3,Simplified BSD
+estraverse,4.1.1,Simplified BSD
+estraverse,4.2.0,Simplified BSD
+esutils,2.0.2,Simplified BSD
et-orbi,1.0.3,MIT
+etag,1.8.0,MIT
+eve-raphael,0.5.0,Apache 2.0
+event-emitter,0.3.5,MIT
+event-stream,3.3.4,MIT
+eventemitter3,1.2.0,MIT
+events,1.1.1,MIT
+eventsource,0.1.6,MIT
+evp_bytestokey,1.0.0,MIT
excon,0.57.1,MIT
+execa,0.7.0,MIT
execjs,2.6.0,MIT
+exit-hook,1.1.1,MIT
+expand-braces,0.1.2,MIT
+expand-brackets,0.1.5,MIT
+expand-range,0.1.1,MIT
+expand-range,1.8.2,MIT
+exports-loader,0.6.4,MIT
+express,4.15.4,MIT
expression_parser,0.9.0,MIT
+extend,3.0.1,MIT
+extglob,0.3.2,MIT
+extsprintf,1.3.0,MIT
faraday,0.12.2,MIT
faraday_middleware,0.11.0.1,MIT
faraday_middleware-multi_json,0.0.6,MIT
+fast-deep-equal,1.0.0,MIT
+fast-json-stable-stringify,2.0.0,MIT
+fast-levenshtein,2.0.6,MIT
+fast_blank,1.0.0,MIT
fast_gettext,1.4.0,"MIT,ruby"
+fastparse,1.1.1,MIT
+faye-websocket,0.10.0,MIT
+faye-websocket,0.11.1,MIT
+faye-websocket,0.7.3,MIT
ffi,1.9.18,New BSD
+figures,1.7.0,MIT
+file-entry-cache,2.0.0,MIT
+file-loader,0.11.1,MIT
+file-uri-to-path,1.0.0,MIT
+filename-regex,2.0.0,MIT
+fileset,2.0.3,MIT
+filesize,3.3.0,New BSD
+filesize,3.5.10,New BSD
+fill-range,2.2.3,MIT
+finalhandler,1.0.4,MIT
+find-cache-dir,1.0.0,MIT
+find-root,0.1.2,MIT
+find-up,1.1.2,MIT
+find-up,2.1.0,MIT
+flat-cache,1.2.2,MIT
+flatten,1.0.2,MIT
flipper,0.11.0,MIT
flipper-active_record,0.11.0,MIT
flipper-active_support_cache_store,0.11.0,MIT
@@ -86,93 +551,452 @@ fog-local,0.3.1,MIT
fog-openstack,0.1.21,MIT
fog-rackspace,0.1.1,MIT
fog-xml,0.1.3,MIT
+follow-redirects,1.0.0,MIT
+follow-redirects,1.2.6,MIT
font-awesome-rails,4.7.0.1,"MIT,SIL Open Font License"
+for-each,0.3.2,MIT
+for-in,0.1.6,MIT
+for-own,0.1.4,MIT
+foreach,2.0.5,MIT
+forever-agent,0.6.1,Apache 2.0
+form-data,2.0.0,MIT
+form-data,2.1.4,MIT
+form-data,2.3.1,MIT
formatador,0.2.5,MIT
+forwarded,0.1.0,MIT
+fresh,0.5.0,MIT
+from,0.1.7,MIT
+fs-access,1.0.1,MIT
+fs-extra,0.26.7,MIT
+fs.realpath,1.0.0,ISC
+fsevents,1.1.2,MIT
+fstream,1.0.11,ISC
+fstream-ignore,1.0.5,ISC
+ftp,0.3.10,MIT
+function-bind,1.1.0,MIT
+function-bind,1.1.1,MIT
+fuzzaldrin-plus,0.5.0,MIT
+gauge,2.7.4,ISC
gemnasium-gitlab-service,0.2.6,MIT
gemojione,3.3.0,MIT
+generate-function,2.0.0,MIT
+generate-object-property,1.2.0,MIT
+get-caller-file,1.0.2,ISC
+get-stdin,4.0.1,MIT
+get-stream,3.0.0,MIT
+get-uri,2.0.1,MIT
get_process_mem,0.2.0,MIT
+getpass,0.1.7,MIT
gettext_i18n_rails,1.8.0,MIT
gettext_i18n_rails_js,1.2.0,MIT
-gitaly-proto,0.64.0,MIT
+gitaly-proto,0.84.0,MIT
github-linguist,4.7.6,MIT
github-markup,1.6.1,MIT
gitlab-flowdock-git-hook,1.0.1,MIT
gitlab-grit,2.8.2,MIT
gitlab-markup,1.6.3,MIT
gitlab_omniauth-ldap,2.0.4,MIT
+glob,5.0.15,ISC
+glob,6.0.4,ISC
+glob,7.1.1,ISC
+glob,7.1.2,ISC
+glob-base,0.3.0,MIT
+glob-parent,2.0.0,ISC
globalid,0.4.1,MIT
+globals,10.4.0,MIT
+globals,9.18.0,MIT
+globby,5.0.0,MIT
+globby,6.1.0,MIT
gollum-grit_adapter,1.0.1,MIT
gollum-lib,4.2.7,MIT
gollum-rugged_adapter,0.4.4,MIT
gon,6.1.0,MIT
+good-listener,1.2.2,MIT
google-api-client,0.13.6,Apache 2.0
-google-protobuf,3.4.1.1,New BSD
+google-protobuf,3.5.1,New BSD
+googleapis-common-protos-types,1.0.1,Apache 2.0
googleauth,0.5.3,Apache 2.0
+got,3.3.1,MIT
+got,7.1.0,MIT
gpgme,2.0.13,LGPL-2.1+
+graceful-fs,4.1.11,ISC
+graceful-readlink,1.0.1,MIT
grape,1.0.0,MIT
grape-entity,0.6.0,MIT
grape-route-helpers,2.1.0,MIT
grape_logging,1.7.0,MIT
-grpc,1.4.5,New BSD
+graphlib,2.1.1,MIT
+grpc,1.8.3,Apache 2.0
+gzip-size,3.0.0,MIT
hamlit,2.6.1,MIT
+handle-thing,1.2.5,MIT
+handlebars,4.0.6,MIT
+har-schema,1.0.5,ISC
+har-schema,2.0.0,ISC
+har-validator,2.0.6,ISC
+har-validator,4.2.1,ISC
+har-validator,5.0.3,ISC
+has,1.0.1,MIT
+has-ansi,2.0.0,MIT
+has-binary2,1.0.2,MIT
+has-cors,1.1.0,MIT
+has-flag,1.0.0,MIT
+has-flag,2.0.0,MIT
+has-symbol-support-x,1.3.0,MIT
+has-to-string-tag-x,1.3.0,MIT
+has-unicode,2.0.1,ISC
+hash-sum,1.0.2,MIT
+hash.js,1.0.3,MIT
hashie,3.5.6,MIT
hashie-forbidden_attributes,0.1.1,MIT
+hawk,3.1.3,New BSD
+hawk,6.0.2,New BSD
+he,1.1.1,MIT
health_check,2.6.0,MIT
hipchat,1.5.2,MIT
+hipchat-notifier,1.1.0,MIT
+hoek,2.16.3,New BSD
+hoek,4.2.0,New BSD
+home-or-tmp,2.0.0,MIT
+hosted-git-info,2.2.0,ISC
+hpack.js,2.1.6,MIT
+html-comment-regex,1.1.1,MIT
+html-entities,1.2.0,MIT
html-pipeline,1.11.0,MIT
html2text,0.2.0,MIT
htmlentities,4.3.4,MIT
+htmlescape,1.1.1,MIT
+htmlparser2,3.9.2,MIT
http,0.9.8,MIT
http-cookie,1.0.3,MIT
+http-deceiver,1.2.7,MIT
+http-errors,1.6.1,MIT
+http-errors,1.6.2,MIT
http-form_data,1.0.1,MIT
+http-proxy,1.16.2,MIT
+http-proxy-agent,1.0.0,MIT
+http-proxy-middleware,0.17.4,MIT
+http-signature,1.1.1,MIT
+http-signature,1.2.0,MIT
http_parser.rb,0.6.0,MIT
httparty,0.13.7,MIT
httpclient,2.8.2,ruby
+httpntlm,1.6.1,MIT
+httpreq,0.4.24,MIT
+https-browserify,0.0.1,MIT
+https-browserify,1.0.0,MIT
+https-proxy-agent,1.0.0,MIT
i18n,0.9.1,MIT
ice_nine,0.11.2,MIT
+iconv-lite,0.4.15,MIT
+iconv-lite,0.4.19,MIT
+icss-replace-symbols,1.0.2,ISC
+ieee754,1.1.8,New BSD
+ignore,3.3.3,MIT
+ignore-by-default,1.0.1,ISC
+immediate,3.0.6,MIT
+imports-loader,0.7.1,MIT
+imurmurhash,0.1.4,MIT
+indent-string,2.1.0,MIT
+indexes-of,1.0.1,MIT
+indexof,0.0.1,MIT*
+infinity-agent,2.0.3,MIT
+inflection,1.10.0,MIT
+inflection,1.3.8,MIT
+inflight,1.0.6,ISC
influxdb,0.2.3,MIT
+inherits,2.0.1,ISC
+inherits,2.0.3,ISC
+ini,1.3.4,ISC
+inline-source-map,0.6.2,MIT
+inquirer,0.12.0,MIT
+insert-module-globals,7.0.1,MIT
+internal-ip,1.2.0,MIT
+interpret,1.0.1,MIT
+invariant,2.2.2,New BSD
+invert-kv,1.0.0,MIT
+ip,1.0.1,MIT
+ip,1.1.5,MIT
+ipaddr.js,1.4.0,MIT
ipaddress,0.8.3,MIT
+is-absolute,0.2.6,MIT
+is-absolute-url,2.1.0,MIT
+is-arrayish,0.2.1,MIT
+is-binary-path,1.0.1,MIT
+is-buffer,1.1.5,MIT
+is-buffer,1.1.6,MIT
+is-builtin-module,1.0.0,MIT
+is-callable,1.1.3,MIT
+is-date-object,1.0.1,MIT
+is-dotfile,1.0.2,MIT
+is-equal-shallow,0.1.3,MIT
+is-extendable,0.1.1,MIT
+is-extglob,1.0.0,MIT
+is-extglob,2.1.1,MIT
+is-finite,1.0.2,MIT
+is-fullwidth-code-point,1.0.0,MIT
+is-fullwidth-code-point,2.0.0,MIT
+is-function,1.0.1,MIT
+is-glob,2.0.1,MIT
+is-glob,3.1.0,MIT
+is-my-json-valid,2.16.0,MIT
+is-my-json-valid,2.17.1,MIT
+is-npm,1.0.0,MIT
+is-number,0.1.1,MIT
+is-number,2.1.0,MIT
+is-object,1.0.1,MIT
+is-path-cwd,1.0.0,MIT
+is-path-in-cwd,1.0.0,MIT
+is-path-inside,1.0.0,MIT
+is-plain-obj,1.1.0,MIT
+is-posix-bracket,0.1.1,MIT
+is-primitive,2.0.0,MIT
+is-property,1.0.2,MIT
+is-redirect,1.0.0,MIT
+is-regex,1.0.4,MIT
+is-relative,0.2.1,MIT
+is-resolvable,1.0.0,MIT
+is-retry-allowed,1.1.0,MIT
+is-stream,1.1.0,MIT
+is-svg,2.1.0,MIT
+is-symbol,1.0.1,MIT
+is-typedarray,1.0.0,MIT
+is-unc-path,0.1.2,MIT
+is-utf8,0.2.1,MIT
+is-windows,0.2.0,MIT
+isarray,0.0.1,MIT
+isarray,1.0.0,MIT
+isarray,2.0.1,MIT
+isbinaryfile,3.0.2,MIT
+isexe,1.1.2,ISC
+isobject,2.1.0,MIT
+isstream,0.1.2,MIT
+istanbul,0.4.5,New BSD
+istanbul-api,1.2.1,New BSD
+istanbul-lib-coverage,1.1.1,New BSD
+istanbul-lib-hook,1.1.0,New BSD
+istanbul-lib-instrument,1.9.1,New BSD
+istanbul-lib-report,1.1.2,New BSD
+istanbul-lib-source-maps,1.2.2,New BSD
+istanbul-reports,1.1.3,New BSD
+isurl,1.0.0,MIT
+jasmine-core,2.9.0,MIT
+jasmine-jquery,2.1.1,MIT
+jed,1.1.1,MIT
jira-ruby,1.4.1,MIT
+jquery,2.2.4,MIT
jquery-atwho-rails,1.3.2,MIT
jquery-rails,4.3.1,MIT
+jquery-ujs,1.2.2,MIT
+js-base64,2.1.9,New BSD
+js-cookie,2.1.3,MIT
+js-tokens,3.0.2,MIT
+js-yaml,3.7.0,MIT
+js-yaml,3.9.1,MIT
+jsbn,0.1.1,MIT
+jsesc,0.5.0,MIT
+jsesc,1.3.0,MIT
json,1.8.6,ruby
json-jwt,1.7.2,MIT
+json-loader,0.5.7,MIT
+json-schema,0.2.3,BSD
+json-schema-traverse,0.3.1,MIT
+json-stable-stringify,0.0.1,MIT
+json-stable-stringify,1.0.1,MIT
+json-stringify-safe,5.0.1,ISC
+json3,3.3.2,MIT
+json5,0.5.1,MIT
+jsonfile,2.4.0,MIT
+jsonify,0.0.0,Public Domain
+jsonparse,1.3.1,MIT
+jsonpointer,4.0.1,MIT
+jsprim,1.4.1,MIT
+jszip,3.1.3,(MIT OR GPL-3.0)
+jszip-utils,0.0.2,MIT or GPLv3
jwt,1.5.6,MIT
kaminari,1.0.1,MIT
kaminari-actionview,1.0.1,MIT
kaminari-activerecord,1.0.1,MIT
kaminari-core,1.0.1,MIT
+karma,2.0.0,MIT
+karma-chrome-launcher,2.2.0,MIT
+karma-coverage-istanbul-reporter,1.3.3,MIT
+karma-jasmine,1.1.1,MIT
+karma-mocha-reporter,2.2.5,MIT
+karma-sourcemap-loader,0.3.7,MIT
+karma-webpack,2.0.7,MIT
kgio,2.10.0,LGPL-2.1+
+kind-of,3.1.0,MIT
+klaw,1.3.1,MIT
kubeclient,2.2.0,MIT
+labeled-stream-splicer,2.0.0,MIT
+latest-version,1.0.1,MIT
+lazy-cache,1.0.4,MIT
+lcid,1.0.0,MIT
+levn,0.3.0,MIT
+lexical-scope,1.2.0,MIT
+libbase64,0.1.0,MIT
+libmime,3.0.0,MIT
+libqp,1.1.0,MIT
licensee,8.7.0,MIT
+lie,3.1.1,MIT
little-plugger,1.1.4,MIT
+load-json-file,1.1.0,MIT
+load-json-file,2.0.0,MIT
+loader-runner,2.3.0,MIT
+loader-utils,0.2.16,MIT
+loader-utils,1.1.0,MIT
locale,2.1.2,"ruby,LGPLv3+"
+locate-path,2.0.0,MIT
+lodash,3.10.1,MIT
+lodash,4.17.4,MIT
+lodash._baseassign,3.2.0,MIT
+lodash._basecopy,3.0.1,MIT
+lodash._baseget,3.7.2,MIT
+lodash._bindcallback,3.0.1,MIT
+lodash._createassigner,3.1.1,MIT
+lodash._getnative,3.9.1,MIT
+lodash._isiterateecall,3.0.9,MIT
+lodash._topath,3.8.1,MIT
+lodash.assign,3.2.0,MIT
+lodash.camelcase,4.1.1,MIT
+lodash.camelcase,4.3.0,MIT
+lodash.capitalize,4.2.1,MIT
+lodash.clonedeep,4.5.0,MIT
+lodash.cond,4.5.2,MIT
+lodash.deburr,4.1.0,MIT
+lodash.defaults,3.1.2,MIT
+lodash.escaperegexp,4.1.2,MIT
+lodash.get,3.7.0,MIT
+lodash.isarguments,3.1.0,MIT
+lodash.isarray,3.0.4,MIT
+lodash.kebabcase,4.0.1,MIT
+lodash.keys,3.1.2,MIT
+lodash.memoize,3.0.4,MIT
+lodash.memoize,4.1.2,MIT
+lodash.mergewith,4.6.0,MIT
+lodash.restparam,3.6.1,MIT
+lodash.snakecase,4.0.1,MIT
+lodash.uniq,4.5.0,MIT
+lodash.words,4.2.0,MIT
+log-symbols,2.1.0,MIT
+log4js,2.4.1,Apache 2.0
logging,2.2.2,MIT
+loggly,1.1.1,MIT
+loglevel,1.4.1,MIT
lograge,0.5.1,MIT
+longest,1.0.1,MIT
loofah,2.0.3,MIT
+loose-envify,1.3.1,MIT
+loud-rejection,1.6.0,MIT
+lowercase-keys,1.0.0,MIT
+lru-cache,2.2.4,MIT
+lru-cache,2.6.5,ISC
+lru-cache,4.1.1,ISC
+macaddress,0.2.8,MIT
mail,2.7.0,MIT
mail_room,0.9.1,MIT
+mailcomposer,4.0.1,MIT
+mailgun-js,0.7.15,MIT
+make-dir,1.0.0,MIT
+map-obj,1.0.1,MIT
+map-stream,0.1.0,Unknown
+marked,0.3.12,MIT
+math-expression-evaluator,1.2.16,MIT
+media-typer,0.3.0,MIT
+mem,1.1.0,MIT
memoist,0.16.0,MIT
+memory-fs,0.2.0,MIT
+memory-fs,0.4.1,MIT
+meow,3.7.0,MIT
+merge-descriptors,1.0.1,MIT
method_source,0.8.2,MIT
+methods,1.1.2,MIT
+micromatch,2.3.11,MIT
+miller-rabin,4.0.0,MIT
+mime,1.3.4,MIT
+mime,1.6.0,MIT
+mime-db,1.27.0,MIT
+mime-db,1.29.0,MIT
+mime-db,1.30.0,MIT
+mime-types,2.1.15,MIT
+mime-types,2.1.17,MIT
mime-types,3.1,MIT
mime-types-data,3.2016.0521,MIT
mimemagic,0.3.0,MIT
+mimic-fn,1.1.0,MIT
+mimic-response,1.0.0,MIT
mini_mime,0.1.4,MIT
mini_portile2,2.3.0,MIT
+minimalistic-assert,1.0.0,ISC
+minimatch,3.0.3,ISC
+minimatch,3.0.4,ISC
+minimist,0.0.8,MIT
+minimist,1.2.0,MIT
+mkdirp,0.5.1,MIT
+module-deps,4.1.1,MIT
+moment,2.19.2,MIT
+monaco-editor,0.10.0,MIT
+mousetrap,1.4.6,Apache 2.0
mousetrap-rails,1.4.6,"MIT,Apache"
+ms,0.7.1,MIT
+ms,2.0.0,MIT
multi_json,1.12.2,MIT
multi_xml,0.6.0,MIT
+multicast-dns,6.1.1,MIT
+multicast-dns-service-types,1.1.0,MIT
multipart-post,2.0.0,MIT
mustermann,1.0.0,MIT
mustermann-grape,1.0.0,MIT
+mute-stream,0.0.5,ISC
mysql2,0.4.10,MIT
+name-all-modules-plugin,1.0.1,MIT
+nan,2.6.2,MIT
+natural-compare,1.4.0,MIT
+negotiator,0.6.1,MIT
+nested-error-stacks,1.0.2,MIT
net-ldap,0.16.0,MIT
net-ssh,4.1.0,MIT
+netmask,1.0.6,MIT
netrc,0.11.0,MIT
-nokogiri,1.8.1,MIT
+node-dir,0.1.17,MIT
+node-forge,0.6.33,New BSD
+node-libs-browser,1.1.1,MIT
+node-libs-browser,2.0.0,MIT
+node-pre-gyp,0.6.37,New BSD
+node-uuid,1.4.8,MIT
+nodemailer,2.7.2,MIT
+nodemailer-direct-transport,3.3.2,MIT
+nodemailer-fetch,1.6.0,MIT
+nodemailer-shared,1.1.0,MIT
+nodemailer-smtp-pool,2.8.2,MIT
+nodemailer-smtp-transport,2.7.2,MIT
+nodemailer-wellknown,0.1.10,MIT
+nodemon,1.11.0,MIT
+nokogiri,1.8.2,MIT
+nopt,1.0.10,MIT
+nopt,3.0.6,ISC
+nopt,4.0.1,ISC
+normalize-package-data,2.4.0,Simplified BSD
+normalize-path,2.1.1,MIT
+normalize-range,0.1.2,MIT
+normalize-url,1.9.1,MIT
+npm-run-path,2.0.2,MIT
+npmlog,4.1.2,ISC
+null-check,1.0.0,MIT
+num2fraction,1.2.2,MIT
+number-is-nan,1.0.1,MIT
numerizer,0.1.1,MIT
oauth,0.5.1,MIT
+oauth-sign,0.8.2,Apache 2.0
oauth2,1.4.0,MIT
+object-assign,3.0.0,MIT
+object-assign,4.1.1,MIT
+object-component,0.0.3,MIT*
+object-inspect,1.3.0,MIT
+object-keys,1.0.11,MIT
+object.omit,2.0.1,MIT
+obuf,1.1.1,MIT
octokit,4.6.2,MIT
oj,2.17.5,MIT
omniauth,1.4.2,MIT
@@ -193,10 +1017,58 @@ omniauth-saml,1.7.0,MIT
omniauth-shibboleth,1.2.1,MIT
omniauth-twitter,1.2.1,MIT
omniauth_crowd,2.2.3,MIT
+on-finished,2.3.0,MIT
+on-headers,1.0.1,MIT
+once,1.4.0,ISC
+onetime,1.1.0,MIT
+opener,1.4.3,(WTFPL OR MIT)
+opn,4.0.2,MIT
+optimist,0.6.1,MIT
+optionator,0.8.2,MIT
org-ruby,0.9.12,MIT
+original,1.0.0,MIT
orm_adapter,0.5.0,MIT
os,0.9.6,MIT
-paranoia,2.3.1,MIT
+os-browserify,0.2.1,MIT
+os-browserify,0.3.0,MIT
+os-homedir,1.0.2,MIT
+os-locale,1.4.0,MIT
+os-locale,2.1.0,MIT
+os-tmpdir,1.0.2,MIT
+osenv,0.1.4,ISC
+p-cancelable,0.3.0,MIT
+p-finally,1.0.0,MIT
+p-limit,1.1.0,MIT
+p-locate,2.0.0,MIT
+p-map,1.1.1,MIT
+p-timeout,1.2.0,MIT
+pac-proxy-agent,1.1.0,MIT
+pac-resolver,2.0.0,MIT
+package-json,1.2.0,MIT
+pako,0.2.9,MIT
+pako,1.0.5,(MIT AND Zlib)
+pako,1.0.6,(MIT AND Zlib)
+parents,1.0.1,MIT
+parse-asn1,5.0.0,ISC
+parse-glob,3.0.4,MIT
+parse-json,2.2.0,MIT
+parseqs,0.0.5,MIT
+parseuri,0.0.5,MIT
+parseurl,1.3.1,MIT
+path-browserify,0.0.0,MIT
+path-exists,2.1.0,MIT
+path-exists,3.0.0,MIT
+path-is-absolute,1.0.1,MIT
+path-is-inside,1.0.2,(WTFPL OR MIT)
+path-key,2.0.1,MIT
+path-parse,1.0.5,MIT
+path-platform,0.11.15,MIT
+path-proxy,1.0.0,MIT
+path-to-regexp,0.1.7,MIT
+path-type,1.1.0,MIT
+path-type,2.0.0,MIT
+pause-stream,0.0.11,Apache 2.0
+pbkdf2,3.0.9,MIT
peek,1.0.1,MIT
peek-gc,0.0.2,MIT
peek-host,1.0.0,MIT
@@ -206,18 +1078,98 @@ peek-pg,1.3.0,MIT
peek-rblineprof,0.2.0,MIT
peek-redis,1.2.0,MIT
peek-sidekiq,1.0.3,MIT
+performance-now,0.2.0,MIT
+performance-now,2.1.0,MIT
pg,0.18.4,"BSD,ruby,GPL"
+pify,2.3.0,MIT
+pify,3.0.0,MIT
+pikaday,1.6.1,MIT
+pinkie,2.0.4,MIT
+pinkie-promise,2.0.1,MIT
+pkg-dir,1.0.0,MIT
+pkg-dir,2.0.0,MIT
+pkg-up,1.0.0,MIT
+pluralize,1.2.1,MIT
po_to_json,1.0.1,MIT
+portfinder,1.0.13,MIT
posix-spawn,0.3.13,MIT
+postcss,5.2.16,MIT
+postcss,6.0.14,MIT
+postcss,6.0.15,MIT
+postcss-calc,5.3.1,MIT
+postcss-colormin,2.2.2,MIT
+postcss-convert-values,2.6.1,MIT
+postcss-discard-comments,2.0.4,MIT
+postcss-discard-duplicates,2.1.0,MIT
+postcss-discard-empty,2.1.0,MIT
+postcss-discard-overridden,0.1.1,MIT
+postcss-discard-unused,2.2.3,MIT
+postcss-filter-plugins,2.0.2,MIT
+postcss-load-config,1.2.0,MIT
+postcss-load-options,1.2.0,MIT
+postcss-load-plugins,2.3.0,MIT
+postcss-merge-idents,2.1.7,MIT
+postcss-merge-longhand,2.0.2,MIT
+postcss-merge-rules,2.1.2,MIT
+postcss-message-helpers,2.0.0,MIT
+postcss-minify-font-values,1.0.5,MIT
+postcss-minify-gradients,1.0.5,MIT
+postcss-minify-params,1.2.2,MIT
+postcss-minify-selectors,2.1.1,MIT
+postcss-modules-extract-imports,1.0.1,ISC
+postcss-modules-local-by-default,1.1.1,MIT
+postcss-modules-scope,1.0.2,ISC
+postcss-modules-values,1.2.2,ISC
+postcss-normalize-charset,1.1.1,MIT
+postcss-normalize-url,3.0.8,MIT
+postcss-ordered-values,2.2.3,MIT
+postcss-reduce-idents,2.4.0,MIT
+postcss-reduce-initial,1.0.1,MIT
+postcss-reduce-transforms,1.0.4,MIT
+postcss-selector-parser,2.2.3,MIT
+postcss-svgo,2.1.6,MIT
+postcss-unique-selectors,2.0.2,MIT
+postcss-value-parser,3.3.0,MIT
+postcss-zindex,2.2.0,MIT
+prelude-ls,1.1.2,MIT
premailer,1.10.4,New BSD
premailer-rails,1.9.7,MIT
-prometheus-client-mmap,0.7.0.beta44,Apache 2.0
+prepend-http,1.0.4,MIT
+preserve,0.2.0,MIT
+prettier,1.8.2,MIT
+prettier,1.9.2,MIT
+prismjs,1.6.0,MIT
+private,0.1.8,MIT
+process,0.11.9,MIT
+process-nextick-args,1.0.7,MIT
+progress,1.1.8,MIT
+prometheus-client-mmap,0.9.1,Apache 2.0
+proxy-addr,1.1.5,MIT
+proxy-agent,2.0.0,MIT
+prr,0.0.0,MIT
+ps-tree,1.1.0,MIT
+pseudomap,1.0.2,ISC
+public-encrypt,4.0.0,MIT
public_suffix,3.0.0,MIT
+punycode,1.3.2,MIT
+punycode,1.4.1,MIT
pyu-ruby-sasl,0.0.3.3,MIT
+q,1.4.1,MIT
+q,1.5.0,MIT
+qjobs,1.1.5,MIT
+qs,6.2.3,New BSD
+qs,6.4.0,New BSD
+qs,6.5.0,New BSD
+qs,6.5.1,New BSD
+query-string,4.3.2,MIT
+querystring,0.2.0,MIT
+querystring-es3,0.2.1,MIT
+querystringify,0.0.4,MIT
+querystringify,1.0.0,MIT
rack,1.6.8,MIT
rack-accept,0.4.5,MIT
rack-attack,4.4.1,MIT
-rack-cors,0.4.0,MIT
+rack-cors,1.0.2,MIT
rack-oauth2,1.2.3,MIT
rack-protection,1.5.3,MIT
rack-proxy,0.6.0,MIT
@@ -231,26 +1183,93 @@ railties,4.2.10,MIT
rainbow,2.2.2,MIT
raindrops,0.18.0,LGPL-2.1+
rake,12.3.0,MIT
+randomatic,1.1.6,MIT
+randombytes,2.0.3,MIT
+randombytes,2.0.6,MIT
+randomfill,1.0.3,MIT
+range-parser,1.2.0,MIT
+raphael,2.2.7,MIT
+raven-js,3.22.1,Simplified BSD
+raw-body,2.2.0,MIT
+raw-body,2.3.2,MIT
+raw-loader,0.5.1,MIT
+rb-fsevent,0.10.2,MIT
+rb-inotify,0.9.10,MIT
rbnacl,4.0.2,MIT
rbnacl-libsodium,1.0.11,MIT
+rc,1.2.1,(BSD-2-Clause OR MIT OR Apache-2.0)
rdoc,4.2.2,ruby
re2,1.1.1,New BSD
+react-dev-utils,0.5.2,New BSD
+read-all-stream,3.1.0,MIT
+read-only-stream,2.0.0,MIT
+read-pkg,1.1.0,MIT
+read-pkg,2.0.0,MIT
+read-pkg-up,1.0.1,MIT
+read-pkg-up,2.0.0,MIT
+readable-stream,1.1.14,MIT
+readable-stream,2.0.6,MIT
+readable-stream,2.3.3,MIT
+readdirp,2.1.0,MIT
+readline2,1.0.1,MIT
recaptcha,3.0.0,MIT
+rechoir,0.6.2,MIT
recursive-open-struct,1.0.0,MIT
+recursive-readdir,2.1.1,MIT
redcarpet,3.4.0,MIT
+redent,1.0.0,MIT
+redis,2.8.0,MIT
redis,3.3.5,MIT
redis-actionpack,5.0.2,MIT
redis-activesupport,5.0.4,MIT
+redis-commands,1.3.1,MIT
redis-namespace,1.5.2,MIT
+redis-parser,2.6.0,MIT
redis-rack,2.0.4,MIT
redis-rails,5.0.2,MIT
redis-store,1.4.1,MIT
+reduce-css-calc,1.3.0,MIT
+reduce-function-call,1.0.2,MIT
+regenerate,1.3.2,MIT
+regenerator-runtime,0.11.0,MIT
+regenerator-transform,0.10.1,BSD
+regex-cache,0.4.3,MIT
+regexpu-core,1.0.0,MIT
+regexpu-core,2.0.0,MIT
+registry-url,3.1.0,MIT
+regjsgen,0.2.0,MIT
+regjsparser,0.1.5,Simplified BSD
+remove-trailing-separator,1.1.0,ISC
+repeat-element,1.1.2,MIT
+repeat-string,0.2.2,MIT
+repeat-string,1.6.1,MIT
+repeating,1.1.3,MIT
+repeating,2.0.1,MIT
representable,3.0.4,MIT
+request,2.75.0,Apache 2.0
+request,2.81.0,Apache 2.0
+request,2.83.0,Apache 2.0
request_store,1.3.1,MIT
+requestretry,1.12.2,MIT
+require-all,2.2.0,MIT
+require-directory,2.1.1,MIT
+require-from-string,1.2.1,MIT
+require-main-filename,1.0.1,ISC
+require-uncached,1.0.3,MIT
+requires-port,1.0.0,MIT
+resolve,1.1.7,MIT
+resolve,1.4.0,MIT
+resolve,1.5.0,MIT
+resolve-from,1.0.1,MIT
responders,2.3.0,MIT
rest-client,2.0.0,MIT
+restore-cursor,1.0.1,MIT
+resumer,0.0.0,MIT
retriable,3.1.1,MIT
+right-align,0.1.3,MIT
+rimraf,2.6.1,ISC
rinku,2.0.0,ISC
+ripemd160,1.0.1,New BSD
rotp,2.1.2,MIT
rouge,2.2.1,MIT
rqrcode,0.7.0,MIT
@@ -263,51 +1282,282 @@ rubyntlm,0.6.2,MIT
rubypants,0.2.0,BSD
rufus-scheduler,3.4.0,MIT
rugged,0.26.0,MIT
+run-async,0.1.0,MIT
+rx-lite,3.1.2,Apache 2.0
+safe-buffer,5.0.1,MIT
+safe-buffer,5.1.1,MIT
safe_yaml,1.0.4,MIT
sanitize,2.1.0,MIT
-sass,3.4.22,MIT
+sanitize-html,1.16.3,MIT
+sass,3.5.5,MIT
+sass-listen,4.0.0,MIT
sass-rails,5.0.6,MIT
sawyer,0.8.1,MIT
+sax,1.2.2,ISC
+schema-utils,0.3.0,MIT
securecompare,1.0.0,MIT
-seed-fu,2.3.6,MIT
+seed-fu,2.3.7,MIT
+select,1.1.2,MIT
+select-hose,2.0.0,MIT
+select2,3.5.2-browserify,Apache*
select2-rails,3.5.9.3,MIT
+selfsigned,1.10.1,MIT
+semver,5.0.3,ISC
+semver,5.3.0,ISC
+semver-diff,2.1.0,MIT
+send,0.15.4,MIT
sentry-raven,2.5.3,Apache 2.0
+serve-index,1.9.0,MIT
+serve-static,1.12.4,MIT
+set-blocking,2.0.0,ISC
+set-immediate-shim,1.0.1,MIT
+setimmediate,1.0.5,MIT
+setprototypeof,1.0.3,ISC
settingslogic,2.0.9,MIT
sexp_processor,4.9.0,MIT
+sha.js,2.4.8,MIT
+sha.js,2.4.9,MIT
+shasum,1.0.2,MIT
+shebang-command,1.2.0,MIT
+shebang-regex,1.0.0,MIT
+shell-quote,1.6.1,MIT
+shelljs,0.7.8,New BSD
sidekiq,5.0.5,LGPL
sidekiq-cron,0.6.0,MIT
sidekiq-limit_fetch,3.4.0,MIT
+signal-exit,3.0.2,ISC
signet,0.7.3,Apache 2.0
+slack-node,0.2.0,MIT
slack-notifier,1.5.1,MIT
+slash,1.0.0,MIT
+slice-ansi,0.0.4,MIT
+slide,1.1.6,ISC
+smart-buffer,1.1.15,MIT
+smtp-connection,2.12.0,MIT
+sntp,1.0.9,BSD
+sntp,2.1.0,BSD
+socket.io,2.0.4,MIT
+socket.io-adapter,1.1.1,MIT
+socket.io-client,2.0.4,MIT
+socket.io-parser,3.1.2,MIT
+sockjs,0.3.18,MIT
+sockjs-client,1.0.1,MIT
+sockjs-client,1.1.4,MIT
+socks,1.1.10,MIT
+socks,1.1.9,MIT
+socks-proxy-agent,2.1.1,MIT
+sort-keys,1.1.2,MIT
+source-list-map,0.1.8,MIT
+source-list-map,2.0.0,MIT
+source-map,0.2.0,New BSD
+source-map,0.4.4,New BSD
+source-map,0.5.6,New BSD
+source-map,0.5.7,New BSD
+source-map,0.6.1,New BSD
+source-map-support,0.4.18,MIT
+spdx-correct,1.0.2,Apache 2.0
+spdx-expression-parse,1.0.4,(MIT AND CC-BY-3.0)
+spdx-license-ids,1.2.2,Unlicense
+spdy,3.4.7,MIT
+spdy-transport,2.0.20,MIT
+split,0.3.3,MIT
+sprintf-js,1.0.3,New BSD
sprockets,3.7.1,MIT
sprockets-rails,3.2.1,MIT
+sql.js,0.4.0,MIT
+srcset,1.0.0,MIT
+sshpk,1.13.1,MIT
state_machines,0.4.0,MIT
state_machines-activemodel,0.4.0,MIT
state_machines-activerecord,0.4.0,MIT
+statuses,1.3.1,MIT
+stream-browserify,2.0.1,MIT
+stream-combiner,0.0.4,MIT
+stream-combiner2,1.1.1,MIT
+stream-http,2.6.3,MIT
+stream-http,2.7.2,MIT
+stream-shift,1.0.0,MIT
+stream-splicer,2.0.0,MIT
+streamroller,0.7.0,MIT
+strict-uri-encode,1.1.0,MIT
+string-length,1.0.1,MIT
+string-width,1.0.2,MIT
+string-width,2.0.0,MIT
+string.prototype.trim,1.1.2,MIT
+string_decoder,0.10.31,MIT
+string_decoder,1.0.3,MIT
stringex,2.7.1,MIT
+stringstream,0.0.5,MIT
+strip-ansi,3.0.1,MIT
+strip-ansi,4.0.0,MIT
+strip-bom,2.0.0,MIT
+strip-bom,3.0.0,MIT
+strip-eof,1.0.0,MIT
+strip-indent,1.0.1,MIT
+strip-json-comments,2.0.1,MIT
+subarg,1.0.0,MIT
+supports-color,2.0.0,MIT
+supports-color,3.2.3,MIT
+supports-color,4.2.1,MIT
+supports-color,4.5.0,MIT
+supports-color,5.1.0,MIT
+svg4everybody,2.1.9,CC0-1.0
+svgo,0.7.2,MIT
+syntax-error,1.3.0,MIT
sys-filesystem,1.1.6,Artistic 2.0
+table,3.8.3,New BSD
+tapable,0.1.10,MIT
+tapable,0.2.8,MIT
+tape,4.8.0,MIT
+tar,2.2.1,ISC
+tar-pack,3.4.0,Simplified BSD
temple,0.7.7,MIT
+test-exclude,4.1.1,ISC
text,1.3.1,MIT
+text-table,0.2.0,MIT
thor,0.19.4,MIT
thread_safe,0.3.6,Apache 2.0
+three,0.84.0,MIT
+three-orbit-controls,82.1.0,MIT
+three-stl-loader,1.0.4,MIT
+through,2.3.8,MIT
+through2,2.0.3,MIT
+thunkify,2.1.2,MIT
+thunky,0.1.0,MIT*
tilt,2.0.6,MIT
+time-stamp,2.0.0,MIT
+timeago.js,3.0.2,MIT
+timed-out,2.0.0,MIT
+timed-out,4.0.1,MIT
+timers-browserify,1.4.2,MIT
+timers-browserify,2.0.4,MIT
+timespan,2.3.0,MIT
timfel-krb5-auth,0.8.3,LGPL
+tiny-emitter,2.0.2,MIT
+tmp,0.0.31,MIT
+tmp,0.0.33,MIT
+to-array,0.1.4,MIT
+to-arraybuffer,1.0.1,MIT
+to-fast-properties,1.0.3,MIT
+to-fast-properties,2.0.0,MIT
toml-rb,0.3.15,MIT
+touch,1.0.0,ISC
+tough-cookie,2.3.2,New BSD
+tough-cookie,2.3.3,New BSD
+traverse,0.6.6,MIT
+trim-newlines,1.0.0,MIT
+trim-right,1.0.1,MIT
truncato,0.7.10,MIT
+tryit,1.0.3,MIT
+tsscmp,1.0.5,MIT
+tty-browserify,0.0.0,MIT
+tunnel-agent,0.4.3,Apache 2.0
+tunnel-agent,0.6.0,Apache 2.0
+tweetnacl,0.14.5,Unlicense
+type-check,0.3.2,MIT
+type-is,1.6.15,MIT
+typedarray,0.0.6,MIT
tzinfo,1.2.4,MIT
u2f,0.2.1,MIT
uber,0.1.0,MIT
uglifier,2.7.2,MIT
+uglify-js,2.8.29,Simplified BSD
+uglify-to-browserify,1.0.2,MIT
+uglifyjs-webpack-plugin,0.4.6,MIT
+uid-number,0.0.6,ISC
+ultron,1.1.0,MIT
+umd,3.0.1,MIT
+unc-path-regex,0.1.2,MIT
+undefsafe,0.0.3,MIT / http://rem.mit-license.org
+underscore,1.7.0,MIT
+underscore,1.8.3,MIT
unf,0.1.4,BSD
unf_ext,0.0.7.4,MIT
unicorn,5.1.0,ruby
unicorn-worker-killer,0.4.4,ruby
+uniq,1.0.1,MIT
+uniqid,4.1.1,MIT
+uniqs,2.0.0,MIT
+unpipe,1.0.0,MIT
+update-notifier,0.5.0,Simplified BSD
+url,0.11.0,MIT
+url-loader,0.5.8,MIT
+url-parse,1.0.5,MIT
+url-parse,1.1.7,MIT
+url-parse,1.1.9,MIT
+url-parse-lax,1.0.0,MIT
+url-to-options,1.0.1,MIT
url_safe_base64,0.2.2,MIT
+user-home,2.0.0,MIT
+useragent,2.2.1,MIT
+util,0.10.3,MIT
+util-deprecate,1.0.2,MIT
+utils-merge,1.0.0,MIT
+uuid,2.0.3,MIT
+uuid,3.1.0,MIT
+uws,0.14.5,Zlib
+validate-npm-package-license,3.0.1,Apache 2.0
validates_hostname,1.0.6,MIT
+vary,1.1.1,MIT
+vendors,1.0.1,MIT
+verror,1.10.0,MIT
version_sorter,2.1.0,MIT
virtus,1.0.5,MIT
+visibilityjs,1.2.4,MIT
+vm-browserify,0.0.4,MIT
vmstat,2.3.0,MIT
+void-elements,2.0.1,MIT
+vue,2.5.13,MIT
+vue-eslint-parser,2.0.1,MIT
+vue-hot-reload-api,2.2.4,MIT
+vue-loader,13.7.0,MIT
+vue-resource,1.3.5,MIT
+vue-router,3.0.1,MIT
+vue-style-loader,3.0.3,MIT
+vue-template-compiler,2.5.13,MIT
+vue-template-es2015-compiler,1.6.0,MIT
+vuex,3.0.1,MIT
warden,1.2.6,MIT
+watchpack,1.4.0,MIT
+wbuf,1.7.2,MIT
+webpack,3.5.5,MIT
+webpack-bundle-analyzer,2.8.2,MIT
+webpack-dev-middleware,1.11.0,MIT
+webpack-dev-middleware,1.12.2,MIT
+webpack-dev-server,2.7.1,MIT
webpack-rails,0.9.10,MIT
+webpack-sources,1.0.1,MIT
+webpack-stats-plugin,0.1.5,MIT
+websocket-driver,0.6.5,MIT
+websocket-extensions,0.1.1,MIT
+when,3.7.8,MIT
+whet.extend,0.9.9,MIT
+which,1.2.12,ISC
+which-module,1.0.0,ISC
+which-module,2.0.0,ISC
+wide-align,1.1.2,ISC
wikicloth,0.8.1,MIT
+window-size,0.1.0,MIT
+wordwrap,0.0.2,MIT
+wordwrap,0.0.3,MIT
+wordwrap,1.0.0,MIT
+worker-loader,1.1.0,MIT
+wrap-ansi,2.1.0,MIT
+wrappy,1.0.2,ISC
+write,0.2.1,MIT
+write-file-atomic,1.3.4,ISC
+ws,2.3.1,MIT
+ws,3.3.3,MIT
+xdg-basedir,2.0.0,MIT
xml-simple,1.1.5,ruby
+xmlhttprequest-ssl,1.5.5,MIT
+xregexp,2.0.0,MIT
+xtend,4.0.1,MIT
+y18n,3.2.1,ISC
+yallist,2.1.2,ISC
+yargs,3.10.0,MIT
+yargs,6.6.0,MIT
+yargs,8.0.2,MIT
+yargs-parser,4.2.1,ISC
+yargs-parser,7.0.0,ISC
+yeast,0.1.2,MIT
diff --git a/yarn.lock b/yarn.lock
index bc5c19464fb..8e86121812d 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -4203,6 +4203,10 @@ jquery-ujs@1.2.2:
dependencies:
jquery ">=1.8.0"
+jquery.waitforimages@^2.2.0:
+ version "2.2.0"
+ resolved "https://registry.yarnpkg.com/jquery.waitforimages/-/jquery.waitforimages-2.2.0.tgz#63f23131055a1b060dc913e6d874bcc9b9e6b16b"
+
"jquery@>= 1.9.1", jquery@>=1.8.0, jquery@^2.2.4:
version "2.2.4"
resolved "https://registry.yarnpkg.com/jquery/-/jquery-2.2.4.tgz#2c89d6889b5eac522a7eea32c14521559c6cbf02"