diff options
186 files changed, 1247 insertions, 266 deletions
diff --git a/.eslintrc.yml b/.eslintrc.yml index a55e65c2678..a8cbd9731a3 100644 --- a/.eslintrc.yml +++ b/.eslintrc.yml @@ -2,6 +2,7 @@ extends: - '@gitlab' - plugin:promise/recommended - plugin:no-jquery/slim + - plugin:no-jquery/deprecated-3.4 globals: __webpack_public_path__: true gl: false @@ -48,8 +49,10 @@ rules: no-jquery/no-animate: off # all offenses of no-jquery/no-animate-toggle are false positives ( $toast.show() ) no-jquery/no-animate-toggle: off + no-jquery/no-event-shorthand: off no-jquery/no-fade: off no-jquery/no-serialize: error + no-jquery/no-sizzle: off promise/always-return: off promise/no-callback-in-promise: off overrides: diff --git a/app/assets/javascripts/diffs/components/app.vue b/app/assets/javascripts/diffs/components/app.vue index 8fc8a8d0495..8ea443814e9 100644 --- a/app/assets/javascripts/diffs/components/app.vue +++ b/app/assets/javascripts/diffs/components/app.vue @@ -220,9 +220,6 @@ export default { this.assignedDiscussions = false; this.fetchData(false); }, - isLatestVersion() { - return window.location.search.indexOf('diff_id') === -1; - }, startDiffRendering() { requestIdleCallback( () => { @@ -232,7 +229,7 @@ export default { ); }, fetchData(toggleTree = true) { - if (this.isLatestVersion() && this.glFeatures.diffsBatchLoad) { + if (this.glFeatures.diffsBatchLoad) { this.fetchDiffFilesMeta() .then(() => { if (toggleTree) this.hideTreeListIfJustOneFile(); diff --git a/app/assets/javascripts/diffs/store/actions.js b/app/assets/javascripts/diffs/store/actions.js index 44672659f56..992b45c97ac 100644 --- a/app/assets/javascripts/diffs/store/actions.js +++ b/app/assets/javascripts/diffs/store/actions.js @@ -90,14 +90,13 @@ export const fetchDiffFiles = ({ state, commit }) => { }; export const fetchDiffFilesBatch = ({ commit, state }) => { - const baseUrl = `${state.endpointBatch}?per_page=${DIFFS_PER_PAGE}`; - const url = page => (page ? `${baseUrl}&page=${page}` : baseUrl); - commit(types.SET_BATCH_LOADING, true); const getBatch = page => axios - .get(url(page)) + .get(state.endpointBatch, { + params: { page, per_page: DIFFS_PER_PAGE, w: state.showWhitespace ? '0' : '1' }, + }) .then(({ data: { pagination, diff_files } }) => { commit(types.SET_DIFF_DATA_BATCH, { diff_files }); commit(types.SET_BATCH_LOADING, false); diff --git a/app/assets/javascripts/ide/stores/getters.js b/app/assets/javascripts/ide/stores/getters.js index a176fd0aca8..bb8374b4e78 100644 --- a/app/assets/javascripts/ide/stores/getters.js +++ b/app/assets/javascripts/ide/stores/getters.js @@ -115,5 +115,30 @@ export const isOnDefaultBranch = (_state, getters) => export const canPushToBranch = (_state, getters) => getters.currentBranch && getters.currentBranch.can_push; +export const isFileDeletedAndReadded = (state, getters) => path => { + const stagedFile = getters.getStagedFile(path); + const file = state.entries[path]; + return Boolean(stagedFile && stagedFile.deleted && file.tempFile); +}; + +// checks if any diff exists in the staged or unstaged changes for this path +export const getDiffInfo = (state, getters) => path => { + const stagedFile = getters.getStagedFile(path); + const file = state.entries[path]; + const renamed = file.prevPath ? file.path !== file.prevPath : false; + const deletedAndReadded = getters.isFileDeletedAndReadded(path); + const deleted = deletedAndReadded ? false : file.deleted; + const tempFile = deletedAndReadded ? false : file.tempFile; + const changed = file.content !== (deletedAndReadded ? stagedFile.raw : file.raw); + + return { + exists: changed || renamed || deleted || tempFile, + changed, + renamed, + deleted, + tempFile, + }; +}; + // prevent babel-plugin-rewire from generating an invalid default during karma tests export default () => {}; diff --git a/app/assets/javascripts/pages/projects/snippets/show/index.js b/app/assets/javascripts/pages/projects/snippets/show/index.js index c35b9c30058..738bf08f1bf 100644 --- a/app/assets/javascripts/pages/projects/snippets/show/index.js +++ b/app/assets/javascripts/pages/projects/snippets/show/index.js @@ -3,11 +3,16 @@ import ZenMode from '~/zen_mode'; import LineHighlighter from '~/line_highlighter'; import BlobViewer from '~/blob/viewer'; import snippetEmbed from '~/snippet/snippet_embed'; +import initSnippetsApp from '~/snippets'; document.addEventListener('DOMContentLoaded', () => { - new LineHighlighter(); // eslint-disable-line no-new - new BlobViewer(); // eslint-disable-line no-new - initNotes(); - new ZenMode(); // eslint-disable-line no-new - snippetEmbed(); + if (!gon.features.snippetsVue) { + new LineHighlighter(); // eslint-disable-line no-new + new BlobViewer(); // eslint-disable-line no-new + initNotes(); + new ZenMode(); // eslint-disable-line no-new + snippetEmbed(); + } else { + initSnippetsApp(); + } }); diff --git a/app/assets/javascripts/repository/components/breadcrumbs.vue b/app/assets/javascripts/repository/components/breadcrumbs.vue index f6b9ea5d30d..e1382aa86d9 100644 --- a/app/assets/javascripts/repository/components/breadcrumbs.vue +++ b/app/assets/javascripts/repository/components/breadcrumbs.vue @@ -104,10 +104,10 @@ export default { return acc.concat({ name, path, - to: `/tree/${this.ref}${path}`, + to: `/-/tree/${this.ref}${path}`, }); }, - [{ name: this.projectShortPath, path: '/', to: `/tree/${this.ref}/` }], + [{ name: this.projectShortPath, path: '/', to: `/-/tree/${this.ref}/` }], ); }, canCreateMrFromFork() { diff --git a/app/assets/javascripts/repository/components/table/parent_row.vue b/app/assets/javascripts/repository/components/table/parent_row.vue index 3c39f404226..38aa672bc1c 100644 --- a/app/assets/javascripts/repository/components/table/parent_row.vue +++ b/app/assets/javascripts/repository/components/table/parent_row.vue @@ -15,7 +15,7 @@ export default { const splitArray = this.path.split('/'); splitArray.pop(); - return { path: `/tree/${this.commitRef}/${splitArray.join('/')}` }; + return { path: `/-/tree/${this.commitRef}/${splitArray.join('/')}` }; }, }, methods: { diff --git a/app/assets/javascripts/repository/components/table/row.vue b/app/assets/javascripts/repository/components/table/row.vue index cf0457a2abf..57dd08c2142 100644 --- a/app/assets/javascripts/repository/components/table/row.vue +++ b/app/assets/javascripts/repository/components/table/row.vue @@ -84,7 +84,7 @@ export default { }, computed: { routerLinkTo() { - return this.isFolder ? { path: `/tree/${this.ref}/${this.path}` } : null; + return this.isFolder ? { path: `/-/tree/${this.ref}/${this.path}` } : null; }, iconName() { return `fa-${getIconName(this.type, this.path)}`; diff --git a/app/assets/javascripts/repository/router.js b/app/assets/javascripts/repository/router.js index ebf0a7091ea..fa544444be8 100644 --- a/app/assets/javascripts/repository/router.js +++ b/app/assets/javascripts/repository/router.js @@ -12,7 +12,7 @@ export default function createRouter(base, baseRef) { base: joinPaths(gon.relative_url_root || '', base), routes: [ { - path: `/tree/${baseRef}(/.*)?`, + path: `/-/tree/${baseRef}(/.*)?`, name: 'treePath', component: TreePage, props: route => ({ diff --git a/app/assets/javascripts/snippets/components/app.vue b/app/assets/javascripts/snippets/components/app.vue index e3d6cdd4606..bd2cb8e4595 100644 --- a/app/assets/javascripts/snippets/components/app.vue +++ b/app/assets/javascripts/snippets/components/app.vue @@ -1,10 +1,16 @@ <script> -import getSnippet from '../queries/getSnippet.query.graphql'; +import GetSnippetQuery from '../queries/snippet.query.graphql'; +import SnippetHeader from './snippet_header.vue'; +import { GlLoadingIcon } from '@gitlab/ui'; export default { + components: { + SnippetHeader, + GlLoadingIcon, + }, apollo: { - snippetData: { - query: getSnippet, + snippet: { + query: GetSnippetQuery, variables() { return { ids: this.snippetGid, @@ -21,11 +27,24 @@ export default { }, data() { return { - snippetData: {}, + snippet: {}, }; }, + computed: { + isLoading() { + return this.$apollo.queries.snippet.loading; + }, + }, }; </script> <template> - <div class="js-snippet-view"></div> + <div class="js-snippet-view"> + <gl-loading-icon + v-if="isLoading" + :label="__('Loading snippet')" + :size="2" + class="loading-animation prepend-top-20 append-bottom-20" + /> + <snippet-header v-else :snippet="snippet" /> + </div> </template> diff --git a/app/assets/javascripts/snippets/components/snippet_header.vue b/app/assets/javascripts/snippets/components/snippet_header.vue new file mode 100644 index 00000000000..e8f1bfeaf43 --- /dev/null +++ b/app/assets/javascripts/snippets/components/snippet_header.vue @@ -0,0 +1,241 @@ +<script> +import { __ } from '~/locale'; +import { + GlAvatar, + GlIcon, + GlSprintf, + GlButton, + GlModal, + GlAlert, + GlLoadingIcon, + GlDropdown, + GlDropdownItem, +} from '@gitlab/ui'; +import TimeAgoTooltip from '~/vue_shared/components/time_ago_tooltip.vue'; + +import DeleteSnippetMutation from '../mutations/deleteSnippet.mutation.graphql'; +import CanCreatePersonalSnippet from '../queries/userPermissions.query.graphql'; +import CanCreateProjectSnippet from '../queries/projectPermissions.query.graphql'; + +export default { + components: { + GlAvatar, + GlIcon, + GlSprintf, + GlButton, + GlModal, + GlAlert, + GlLoadingIcon, + GlDropdown, + GlDropdownItem, + TimeAgoTooltip, + }, + apollo: { + canCreateSnippet: { + query() { + return this.snippet.project ? CanCreateProjectSnippet : CanCreatePersonalSnippet; + }, + variables() { + return { + fullPath: this.snippet.project ? this.snippet.project.fullPath : undefined, + }; + }, + update(data) { + return this.snippet.project + ? data.project.userPermissions.createSnippet + : data.currentUser.userPermissions.createSnippet; + }, + }, + }, + props: { + snippet: { + type: Object, + required: true, + }, + }, + data() { + return { + isDeleting: false, + errorMessage: '', + canCreateSnippet: false, + }; + }, + computed: { + personalSnippetActions() { + return [ + { + condition: this.snippet.userPermissions.updateSnippet, + text: __('Edit'), + href: this.editLink, + click: undefined, + variant: 'outline-info', + cssClass: undefined, + }, + { + condition: this.snippet.userPermissions.adminSnippet, + text: __('Delete'), + href: undefined, + click: this.showDeleteModal, + variant: 'outline-danger', + cssClass: 'btn-inverted btn-danger ml-2', + }, + { + condition: this.canCreateSnippet, + text: __('New snippet'), + href: this.snippet.project + ? `${this.snippet.project.webUrl}/snippets/new` + : '/snippets/new', + click: undefined, + variant: 'outline-success', + cssClass: 'btn-inverted btn-success ml-2', + }, + ]; + }, + editLink() { + return `${this.snippet.webUrl}/edit`; + }, + visibility() { + return this.snippet.visibilityLevel; + }, + snippetVisibilityLevelDescription() { + switch (this.visibility) { + case 'private': + return this.snippet.project !== null + ? __('The snippet is visible only to project members.') + : __('The snippet is visible only to me.'); + case 'internal': + return __('The snippet is visible to any logged in user.'); + default: + return __('The snippet can be accessed without any authentication.'); + } + }, + visibilityLevelIcon() { + switch (this.visibility) { + case 'private': + return 'lock'; + case 'internal': + return 'shield'; + default: + return 'earth'; + } + }, + }, + methods: { + redirectToSnippets() { + window.location.pathname = 'dashboard/snippets'; + }, + closeDeleteModal() { + this.$refs.deleteModal.hide(); + }, + showDeleteModal() { + this.$refs.deleteModal.show(); + }, + deleteSnippet() { + this.isDeleting = true; + this.$apollo + .mutate({ + mutation: DeleteSnippetMutation, + variables: { id: this.snippet.id }, + }) + .then(() => { + this.isDeleting = false; + this.errorMessage = undefined; + this.closeDeleteModal(); + this.redirectToSnippets(); + }) + .catch(err => { + this.isDeleting = false; + this.errorMessage = err.message; + }); + }, + }, +}; +</script> +<template> + <div class="detail-page-header"> + <div class="detail-page-header-body"> + <div + class="snippet-box qa-snippet-box has-tooltip d-flex align-items-center append-right-5 mb-1" + :title="snippetVisibilityLevelDescription" + data-container="body" + > + <span class="sr-only"> + {{ s__(`VisibilityLevel|${visibility}`) }} + </span> + <gl-icon :name="visibilityLevelIcon" :size="14" /> + </div> + <div class="creator"> + <gl-sprintf message="Authored %{timeago} by %{author}"> + <template #timeago> + <time-ago-tooltip + :time="snippet.createdAt" + tooltip-placement="bottom" + css-class="snippet_updated_ago" + /> + </template> + <template #author> + <a :href="snippet.author.webUrl" class="d-inline"> + <gl-avatar :size="24" :src="snippet.author.avatarUrl" /> + <span class="bold">{{ snippet.author.name }}</span> + </a> + </template> + </gl-sprintf> + </div> + </div> + + <div class="detail-page-header-actions"> + <div class="d-none d-sm-block"> + <template v-for="(action, index) in personalSnippetActions"> + <gl-button + v-if="action.condition" + :key="index" + :variant="action.variant" + :class="action.cssClass" + :href="action.href || undefined" + @click="action.click ? action.click() : undefined" + > + {{ action.text }} + </gl-button> + </template> + </div> + <div class="d-block d-sm-none dropdown"> + <gl-dropdown :text="__('Options')" class="w-100" toggle-class="text-center"> + <gl-dropdown-item + v-for="(action, index) in personalSnippetActions" + :key="index" + :href="action.href || undefined" + @click="action.click ? action.click() : undefined" + >{{ action.text }}</gl-dropdown-item + > + </gl-dropdown> + </div> + </div> + + <gl-modal ref="deleteModal" modal-id="delete-modal" title="Example title"> + <template #modal-title>{{ __('Delete snippet?') }}</template> + + <gl-alert v-if="errorMessage" variant="danger" class="mb-2" @dismiss="errorMessage = ''">{{ + errorMessage + }}</gl-alert> + + <gl-sprintf message="Are you sure you want to delete %{name}?"> + <template #name + ><strong>{{ snippet.title }}</strong></template + > + </gl-sprintf> + + <template #modal-footer> + <gl-button @click="closeDeleteModal">{{ __('Cancel') }}</gl-button> + <gl-button + variant="danger" + :disabled="isDeleting" + data-qa-selector="delete_snippet_button" + @click="deleteSnippet" + > + <gl-loading-icon v-if="isDeleting" inline /> + {{ __('Delete snippet') }} + </gl-button> + </template> + </gl-modal> + </div> +</template> diff --git a/app/assets/javascripts/snippets/fragments/author.fragment.graphql b/app/assets/javascripts/snippets/fragments/author.fragment.graphql new file mode 100644 index 00000000000..2684bd0fa37 --- /dev/null +++ b/app/assets/javascripts/snippets/fragments/author.fragment.graphql @@ -0,0 +1,8 @@ +fragment Author on Snippet { + author { + name, + avatarUrl, + username, + webUrl + } +}
\ No newline at end of file diff --git a/app/assets/javascripts/snippets/fragments/project.fragment.graphql b/app/assets/javascripts/snippets/fragments/project.fragment.graphql new file mode 100644 index 00000000000..7d65789c67b --- /dev/null +++ b/app/assets/javascripts/snippets/fragments/project.fragment.graphql @@ -0,0 +1,6 @@ +fragment Project on Snippet { + project { + fullPath + webUrl + } +}
\ No newline at end of file diff --git a/app/assets/javascripts/snippets/fragments/snippetBase.fragment.graphql b/app/assets/javascripts/snippets/fragments/snippetBase.fragment.graphql new file mode 100644 index 00000000000..57348a422ec --- /dev/null +++ b/app/assets/javascripts/snippets/fragments/snippetBase.fragment.graphql @@ -0,0 +1,13 @@ +fragment SnippetBase on Snippet { + id + title + description + createdAt + updatedAt + visibilityLevel + webUrl + userPermissions { + adminSnippet + updateSnippet + } +}
\ No newline at end of file diff --git a/app/assets/javascripts/snippets/mutations/deleteSnippet.mutation.graphql b/app/assets/javascripts/snippets/mutations/deleteSnippet.mutation.graphql new file mode 100644 index 00000000000..0c829cbdee6 --- /dev/null +++ b/app/assets/javascripts/snippets/mutations/deleteSnippet.mutation.graphql @@ -0,0 +1,5 @@ +mutation DeleteSnippet($id: ID!) { + destroySnippet(input: {id: $id}) { + errors + } +}
\ No newline at end of file diff --git a/app/assets/javascripts/snippets/queries/getSnippet.query.graphql b/app/assets/javascripts/snippets/queries/getSnippet.query.graphql deleted file mode 100644 index 5a5f0d05c5b..00000000000 --- a/app/assets/javascripts/snippets/queries/getSnippet.query.graphql +++ /dev/null @@ -1,13 +0,0 @@ -query getSnippet($ids: [ID!]) { - snippets(ids: $ids) { - edges { - node { - title - description - createdAt - updatedAt - visibility - } - } - } -} diff --git a/app/assets/javascripts/snippets/queries/projectPermissions.query.graphql b/app/assets/javascripts/snippets/queries/projectPermissions.query.graphql new file mode 100644 index 00000000000..288bd0889bf --- /dev/null +++ b/app/assets/javascripts/snippets/queries/projectPermissions.query.graphql @@ -0,0 +1,7 @@ +query CanCreateProjectSnippet($fullPath: ID!) { + project(fullPath: $fullPath) { + userPermissions { + createSnippet + } + } +}
\ No newline at end of file diff --git a/app/assets/javascripts/snippets/queries/snippet.query.graphql b/app/assets/javascripts/snippets/queries/snippet.query.graphql new file mode 100644 index 00000000000..1cb2c86c4d8 --- /dev/null +++ b/app/assets/javascripts/snippets/queries/snippet.query.graphql @@ -0,0 +1,15 @@ +#import '../fragments/snippetBase.fragment.graphql' +#import '../fragments/project.fragment.graphql' +#import '../fragments/author.fragment.graphql' + +query GetSnippetQuery($ids: [ID!]) { + snippets(ids: $ids) { + edges { + node { + ...SnippetBase + ...Project + ...Author + } + } + } +} diff --git a/app/assets/javascripts/snippets/queries/userPermissions.query.graphql b/app/assets/javascripts/snippets/queries/userPermissions.query.graphql new file mode 100644 index 00000000000..f5b97b3d0f0 --- /dev/null +++ b/app/assets/javascripts/snippets/queries/userPermissions.query.graphql @@ -0,0 +1,7 @@ +query CanCreatePersonalSnippet { + currentUser { + userPermissions { + createSnippet + } + } +}
\ No newline at end of file diff --git a/app/assets/javascripts/vue_shared/components/diff_viewer/diff_viewer.vue b/app/assets/javascripts/vue_shared/components/diff_viewer/diff_viewer.vue index b874bedab36..bf3c3666300 100644 --- a/app/assets/javascripts/vue_shared/components/diff_viewer/diff_viewer.vue +++ b/app/assets/javascripts/vue_shared/components/diff_viewer/diff_viewer.vue @@ -79,10 +79,10 @@ export default { return this.projectPath.indexOf('/') === 0 ? '' : `${gon.relative_url_root}/`; }, fullOldPath() { - return `${this.basePath}${this.projectPath}/raw/${this.oldSha}/${this.oldPath}`; + return `${this.basePath}${this.projectPath}/-/raw/${this.oldSha}/${this.oldPath}`; }, fullNewPath() { - return `${this.basePath}${this.projectPath}/raw/${this.newSha}/${this.newPath}`; + return `${this.basePath}${this.projectPath}/-/raw/${this.newSha}/${this.newPath}`; }, }, }; diff --git a/app/assets/stylesheets/utilities.scss b/app/assets/stylesheets/utilities.scss index 7d25b6927f9..1f4bba5fc33 100644 --- a/app/assets/stylesheets/utilities.scss +++ b/app/assets/stylesheets/utilities.scss @@ -40,12 +40,12 @@ // Classes using mixins coming from @gitlab-ui // can be removed once https://gitlab.com/gitlab-org/gitlab/merge_requests/19021 has been merged -.gl-bg-blue-500 { @include gl-bg-blue-500; } .gl-bg-red-100 { @include gl-bg-red-100; } .gl-bg-orange-100 { @include gl-bg-orange-100; } .gl-bg-gray-100 { @include gl-bg-gray-100; } .gl-bg-green-100 { @include gl-bg-green-100;} +.gl-text-blue-500 { @include gl-text-blue-500; } .gl-text-gray-900 { @include gl-text-gray-900; } .gl-text-red-700 { @include gl-text-red-700; } .gl-text-orange-700 { @include gl-text-orange-700; } diff --git a/app/helpers/submodule_helper.rb b/app/helpers/submodule_helper.rb index 4b83988e8bb..e5400652458 100644 --- a/app/helpers/submodule_helper.rb +++ b/app/helpers/submodule_helper.rb @@ -43,6 +43,8 @@ module SubmoduleHelper elsif github_dot_com_url?(url) standard_links('github.com', namespace, project, submodule_item_id) elsif gitlab_dot_com_url?(url) + # This need to be replaced with /-/tree routing once one is landed on + # GitLab.com. Issue https://gitlab.com/gitlab-org/gitlab/issues/42764 standard_links('gitlab.com', namespace, project, submodule_item_id) else [sanitize_submodule_url(url), nil] diff --git a/app/helpers/tree_helper.rb b/app/helpers/tree_helper.rb index af1919eeb40..0b50b8b1130 100644 --- a/app/helpers/tree_helper.rb +++ b/app/helpers/tree_helper.rb @@ -38,13 +38,13 @@ module TreeHelper # many paths, as with a repository tree that has thousands of items. def fast_project_blob_path(project, blob_path) ActionDispatch::Journey::Router::Utils.escape_path( - File.join(relative_url_root, project.path_with_namespace, 'blob', blob_path) + File.join(relative_url_root, project.path_with_namespace, '-', 'blob', blob_path) ) end def fast_project_tree_path(project, tree_path) ActionDispatch::Journey::Router::Utils.escape_path( - File.join(relative_url_root, project.path_with_namespace, 'tree', tree_path) + File.join(relative_url_root, project.path_with_namespace, '-', 'tree', tree_path) ) end diff --git a/app/models/clusters/applications/knative.rb b/app/models/clusters/applications/knative.rb index 89ffb72a22f..387503bee54 100644 --- a/app/models/clusters/applications/knative.rb +++ b/app/models/clusters/applications/knative.rb @@ -3,7 +3,7 @@ module Clusters module Applications class Knative < ApplicationRecord - VERSION = '0.7.0' + VERSION = '0.9.0' REPOSITORY = 'https://storage.googleapis.com/triggermesh-charts' METRICS_CONFIG = 'https://storage.googleapis.com/triggermesh-charts/istio-metrics.yaml' FETCH_IP_ADDRESS_DELAY = 30.seconds diff --git a/app/views/admin/users/_access_levels.html.haml b/app/views/admin/users/_access_levels.html.haml index bb1e22cc610..e3ab2e4f9bd 100644 --- a/app/views/admin/users/_access_levels.html.haml +++ b/app/views/admin/users/_access_levels.html.haml @@ -43,7 +43,7 @@ = f.check_box :external do External %p.light - External users cannot see internal or private projects unless access is explicitly granted. Also, external users cannot create projects or groups. + External users cannot see internal or private projects unless access is explicitly granted. Also, external users cannot create projects, groups, or personal snippets. %row.hidden#warning_external_automatically_set.hidden .badge.badge-warning.text-white = _('Automatically marked as default internal user') diff --git a/app/views/dashboard/_snippets_head.html.haml b/app/views/dashboard/_snippets_head.html.haml index 34aca40d0d1..4958cdc3745 100644 --- a/app/views/dashboard/_snippets_head.html.haml +++ b/app/views/dashboard/_snippets_head.html.haml @@ -3,7 +3,8 @@ - if current_user && current_user.snippets.any? || @snippets.any? .page-title-controls - = link_to _("New snippet"), new_snippet_path, class: "btn btn-success", title: _("New snippet") + - if can?(current_user, :create_personal_snippet) + = link_to _("New snippet"), new_snippet_path, class: "btn btn-success", title: _("New snippet") .top-area %ul.nav-links.nav.nav-tabs diff --git a/app/views/dashboard/snippets/index.html.haml b/app/views/dashboard/snippets/index.html.haml index 2caa8e0cac4..44a9270971a 100644 --- a/app/views/dashboard/snippets/index.html.haml +++ b/app/views/dashboard/snippets/index.html.haml @@ -1,6 +1,7 @@ - @hide_top_links = true - page_title "Snippets" - header_title "Snippets", dashboard_snippets_path +- button_path = new_snippet_path if can?(current_user, :create_personal_snippet) = render 'dashboard/snippets_head' - if current_user.snippets.exists? @@ -9,4 +10,4 @@ - if current_user.snippets.exists? = render partial: 'shared/snippets/list', locals: { link_project: true } - else - = render 'shared/empty_states/snippets', button_path: new_snippet_path + = render 'shared/empty_states/snippets', button_path: button_path diff --git a/app/views/profiles/accounts/_providers.html.haml b/app/views/profiles/accounts/_providers.html.haml index dc17de1b220..a87191d0fa4 100644 --- a/app/views/profiles/accounts/_providers.html.haml +++ b/app/views/profiles/accounts/_providers.html.haml @@ -16,6 +16,6 @@ %a.provider-btn = s_('Profiles|Active') - elsif link_allowed - = link_to omniauth_authorize_path(:user, provider), method: :post, class: 'provider-btn gl-bg-blue-500' do + = link_to omniauth_authorize_path(:user, provider), method: :post, class: 'provider-btn gl-text-blue-500' do = s_('Profiles|Connect') = render_if_exists 'profiles/accounts/group_saml_unlink_buttons', group_saml_identities: group_saml_identities diff --git a/app/views/projects/snippets/index.html.haml b/app/views/projects/snippets/index.html.haml index 7682d01a5a1..0ce18d83d57 100644 --- a/app/views/projects/snippets/index.html.haml +++ b/app/views/projects/snippets/index.html.haml @@ -8,8 +8,7 @@ - if can?(current_user, :create_project_snippet, @project) .nav-controls - - if can?(current_user, :create_project_snippet, @project) - = link_to _("New snippet"), new_project_snippet_path(@project), class: "btn btn-success", title: _("New snippet") + = link_to _("New snippet"), new_project_snippet_path(@project), class: "btn btn-success", title: _("New snippet") = render 'shared/snippets/list' - else diff --git a/app/views/projects/snippets/show.html.haml b/app/views/projects/snippets/show.html.haml index f495b4eaf30..768e4422206 100644 --- a/app/views/projects/snippets/show.html.haml +++ b/app/views/projects/snippets/show.html.haml @@ -3,13 +3,16 @@ - breadcrumb_title @snippet.to_reference - page_title "#{@snippet.title} (#{@snippet.to_reference})", _("Snippets") -= render 'shared/snippets/header' +- if Feature.enabled?(:snippets_vue) + #js-snippet-view{ data: {'qa-selector': 'snippet_view', 'snippet-gid': @snippet.to_global_id} } +- else + = render 'shared/snippets/header' -.project-snippets - %article.file-holder.snippet-file-content - = render 'shared/snippets/blob' + .project-snippets + %article.file-holder.snippet-file-content + = render 'shared/snippets/blob' - .row-content-block.top-block.content-component-block - = render 'award_emoji/awards_block', awardable: @snippet, inline: true + .row-content-block.top-block.content-component-block + = render 'award_emoji/awards_block', awardable: @snippet, inline: true - #notes.limited-width-notes= render "shared/notes/notes_with_form", :autocomplete => true + #notes.limited-width-notes= render "shared/notes/notes_with_form", :autocomplete => true diff --git a/app/views/shared/empty_states/_snippets.html.haml b/app/views/shared/empty_states/_snippets.html.haml index a1a16b9d067..889a470d6ec 100644 --- a/app/views/shared/empty_states/_snippets.html.haml +++ b/app/views/shared/empty_states/_snippets.html.haml @@ -11,7 +11,8 @@ %p = s_('SnippetsEmptyState|They can be either public or private.') .text-center - = link_to s_('SnippetsEmptyState|New snippet'), button_path, class: 'btn btn-success', title: s_('SnippetsEmptyState|New snippet'), id: 'new_snippet_link' + - if button_path + = link_to s_('SnippetsEmptyState|New snippet'), button_path, class: 'btn btn-success', title: s_('SnippetsEmptyState|New snippet'), id: 'new_snippet_link' - unless current_page?(dashboard_snippets_path) = link_to s_('SnippetsEmptyState|Explore public snippets'), explore_snippets_path, class: 'btn btn-default', title: s_('SnippetsEmptyState|Explore public snippets') - else diff --git a/app/views/snippets/_snippets.html.haml b/app/views/snippets/_snippets.html.haml index dab247da251..69b19c0def9 100644 --- a/app/views/snippets/_snippets.html.haml +++ b/app/views/snippets/_snippets.html.haml @@ -3,7 +3,7 @@ - current_user_empty_message_header = s_('UserProfile|You haven\'t created any snippets.') - current_user_empty_message_description = s_('UserProfile|Snippets in GitLab can either be private, internal, or public.') - primary_button_label = _('New snippet') -- primary_button_link = new_snippet_path +- primary_button_link = new_snippet_path if can?(current_user, :create_personal_snippet) - visitor_empty_message = s_('UserProfile|No snippets found.') .snippets-list-holder diff --git a/babel.config.js b/babel.config.js index 79c401ed975..91c58cf46bf 100644 --- a/babel.config.js +++ b/babel.config.js @@ -21,6 +21,7 @@ const plugins = [ '@babel/plugin-proposal-class-properties', '@babel/plugin-proposal-json-strings', '@babel/plugin-proposal-private-methods', + '@babel/plugin-proposal-optional-chaining', ]; // add code coverage tooling if necessary diff --git a/changelogs/unreleased/39498-part-1.yml b/changelogs/unreleased/39498-part-1.yml new file mode 100644 index 00000000000..fb410993424 --- /dev/null +++ b/changelogs/unreleased/39498-part-1.yml @@ -0,0 +1,5 @@ +--- +title: "!21542 Part 1: Add new utils for Web IDE store" +merge_request: 21673 +author: +type: fixed diff --git a/changelogs/unreleased/ap-14330-external-personal-snippets.yml b/changelogs/unreleased/ap-14330-external-personal-snippets.yml new file mode 100644 index 00000000000..86cd3f0ab75 --- /dev/null +++ b/changelogs/unreleased/ap-14330-external-personal-snippets.yml @@ -0,0 +1,5 @@ +--- +title: Match external user new snippet button visibility to permissions +merge_request: 21718 +author: +type: fixed diff --git a/changelogs/unreleased/dz-scope-repository-routes.yml b/changelogs/unreleased/dz-scope-repository-routes.yml new file mode 100644 index 00000000000..302227dde57 --- /dev/null +++ b/changelogs/unreleased/dz-scope-repository-routes.yml @@ -0,0 +1,5 @@ +--- +title: Move repository routes under - scope +merge_request: 20455 +author: +type: deprecated diff --git a/changelogs/unreleased/knative-0-9-update.yml b/changelogs/unreleased/knative-0-9-update.yml new file mode 100644 index 00000000000..d25e9e90efe --- /dev/null +++ b/changelogs/unreleased/knative-0-9-update.yml @@ -0,0 +1,5 @@ +--- +title: Update Knative to 0.9.0 +merge_request: 21361 +author: cab105 +type: added diff --git a/changelogs/unreleased/service-desk-name.yml b/changelogs/unreleased/service-desk-name.yml new file mode 100644 index 00000000000..f3d32e6c6cd --- /dev/null +++ b/changelogs/unreleased/service-desk-name.yml @@ -0,0 +1,5 @@ +--- +title: Added migration which adds service desk username column +merge_request: 21733 +author: +type: added diff --git a/config/prometheus/common_metrics.yml b/config/prometheus/common_metrics.yml index 795243fab49..314ee44ed71 100644 --- a/config/prometheus/common_metrics.yml +++ b/config/prometheus/common_metrics.yml @@ -209,6 +209,6 @@ panel_groups: weight: 1 metrics: - id: system_metrics_knative_function_invocation_count - query_range: 'sum(ceil(rate(istio_requests_total{destination_service_namespace="%{kube_namespace}", destination_app=~"%{function_name}.*"}[1m])*60))' + query_range: 'sum(ceil(rate(istio_requests_total{destination_service_namespace="%{kube_namespace}", destination_service=~"%{function_name}.*"}[1m])*60))' label: invocations / minute unit: requests diff --git a/config/routes/project.rb b/config/routes/project.rb index d2abc73f7cc..6c2dcafd1ab 100644 --- a/config/routes/project.rb +++ b/config/routes/project.rb @@ -554,7 +554,8 @@ constraints(::Constraints::ProjectUrlConstrainer.new) do :forks, :group_links, :import, :avatar, :mirror, :cycle_analytics, :mattermost, :variables, :triggers, :environments, :protected_environments, :error_tracking, - :serverless, :clusters, :audit_events, :wikis, :merge_requests) + :serverless, :clusters, :audit_events, :wikis, :merge_requests, + :blob, :tree, :raw, :blame, :commits, :create_dir, :find_file, :files) end # rubocop: disable Cop/PutProjectRoutesUnderScope diff --git a/config/routes/repository.rb b/config/routes/repository.rb index 4815575ba9f..e59168c6af4 100644 --- a/config/routes/repository.rb +++ b/config/routes/repository.rb @@ -65,7 +65,7 @@ scope format: false do resources :protected_tags, only: [:index, :show, :create, :update, :destroy] end - scope constraints: { id: /[^\0]+/ } do + scope path: '-', constraints: { id: /[^\0]+/ } do scope controller: :blob do get '/new/*id', action: :new, as: :new_blob post '/create/*id', action: :create, as: :create_blob diff --git a/db/migrate/20191213104838_add_service_desk_username.rb b/db/migrate/20191213104838_add_service_desk_username.rb new file mode 100644 index 00000000000..945bdb67fa1 --- /dev/null +++ b/db/migrate/20191213104838_add_service_desk_username.rb @@ -0,0 +1,9 @@ +# frozen_string_literal: true + +class AddServiceDeskUsername < ActiveRecord::Migration[5.2] + DOWNTIME = false + + def change + add_column :service_desk_settings, :outgoing_name, :string, limit: 255 + end +end diff --git a/db/post_migrate/20191209215316_knative_0_9_prometheus_update.rb b/db/post_migrate/20191209215316_knative_0_9_prometheus_update.rb new file mode 100644 index 00000000000..52127f71cd0 --- /dev/null +++ b/db/post_migrate/20191209215316_knative_0_9_prometheus_update.rb @@ -0,0 +1,13 @@ +# frozen_string_literal: true + +class Knative09PrometheusUpdate < ActiveRecord::Migration[5.2] + DOWNTIME = false + + def up + ::Gitlab::DatabaseImporters::CommonMetrics::Importer.new.execute + end + + def down + # no-op + end +end diff --git a/db/schema.rb b/db/schema.rb index d3e9f66c388..67d305a3505 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 2019_12_16_183532) do +ActiveRecord::Schema.define(version: 2019_12_17_160632) do # These are extensions that must be enabled in order to support this database enable_extension "pg_trgm" @@ -3663,6 +3663,7 @@ ActiveRecord::Schema.define(version: 2019_12_16_183532) do create_table "service_desk_settings", primary_key: "project_id", id: :bigint, default: nil, force: :cascade do |t| t.string "issue_template_key", limit: 255 + t.string "outgoing_name", limit: 255 end create_table "services", id: :serial, force: :cascade do |t| diff --git a/doc/development/background_migrations.md b/doc/development/background_migrations.md index 5e16f83b63c..8a1db615022 100644 --- a/doc/development/background_migrations.md +++ b/doc/development/background_migrations.md @@ -10,11 +10,6 @@ migrations automatically reschedule themselves for a later point in time. ## When To Use Background Migrations -> **Note:** -> When adding background migrations _you must_ make sure they are announced in the -> monthly release post along with an estimate of how long it will take to complete -> the migrations. - In the vast majority of cases you will want to use a regular Rails migration instead. Background migrations should be used when migrating _data_ in tables that have so many rows this process would take hours when performed in a @@ -34,6 +29,11 @@ Some examples where background migrations can be useful: - Populating one column based on JSON stored in another column. - Migrating data that depends on the output of external services (e.g. an API). +> **Note:** +> If the background migration is part of an important upgrade, make sure it's announced +> in the release post. Discuss with your Project Manager if you're not sure the migration falls +> into this category. + ## Isolation Background migrations must be isolated and can not use application code (e.g. diff --git a/doc/development/fe_guide/graphql.md b/doc/development/fe_guide/graphql.md index 40df5f3265a..40b9fdef76e 100644 --- a/doc/development/fe_guide/graphql.md +++ b/doc/development/fe_guide/graphql.md @@ -39,43 +39,31 @@ To distinguish queries from mutations and fragments, the following naming conven - `addUser.mutation.graphql` for mutations; - `basicUser.fragment.graphql` for fragments. -GraphQL: - -- Queries are stored in `(ee/)app/assets/javascripts/` under the feature. For example, `respository/queries`. Frontend components can use these stored queries. -- Mutations are stored in - `(ee/)app/assets/javascripts/<subfolders>/<name of mutation>.mutation.graphql`. - ### Fragments -Fragments are a way to make your complex GraphQL queries more readable and re-usable. -They can be stored in a separate file and imported. +Fragments are a way to make your complex GraphQL queries more readable and re-usable. Here is an example of GraphQL fragment: -For example, a fragment that references another fragment: - -```ruby -fragment BaseEpic on Epic { +```javascript +fragment DesignListItem on Design { id - iid - title - webPath - relativePosition - userPermissions { - adminEpic - createEpic - } + image + event + filename + notesCount } +``` -fragment EpicNode on Epic { - ...BaseEpic - state - reference(full: true) - relationPath - createdAt - closedAt - hasChildren - hasIssues - group { - fullPath +Fragments can be stored in separate files, imported and used in queries, mutations or other fragments. + +```javascript +#import "./designList.fragment.graphql" +#import "./diffRefs.fragment.graphql" + +fragment DesignItem on Design { + ...DesignListItem + fullPath + diffRefs { + ...DesignDiffRefs } } ``` diff --git a/doc/user/permissions.md b/doc/user/permissions.md index ed58c23a22f..9cbf4fd6192 100644 --- a/doc/user/permissions.md +++ b/doc/user/permissions.md @@ -253,7 +253,7 @@ project and should only have access to that project. External users: -- Cannot create groups or projects. +- Cannot create groups, projects, or personal snippets. - Can only access projects to which they are explicitly granted access, thus hiding all other internal or private ones from them (like being logged out). diff --git a/lib/banzai/filter/relative_link_filter.rb b/lib/banzai/filter/relative_link_filter.rb index 583b0081319..2581a179c79 100644 --- a/lib/banzai/filter/relative_link_filter.rb +++ b/lib/banzai/filter/relative_link_filter.rb @@ -152,11 +152,18 @@ module Banzai def rebuild_relative_uri(uri) file_path = nested_file_path_if_exists(uri) + resource_type = uri_type(file_path) + + # Repository routes are under /-/ scope now. + # Since we craft a path without using route helpers we must + # ensure - is added here. + prefix = '-' if %w(tree blob raw commits).include?(resource_type.to_s) uri.path = [ relative_url_root, project.full_path, - uri_type(file_path), + prefix, + resource_type, Addressable::URI.escape(ref).gsub('#', '%23'), Addressable::URI.escape(file_path) ].compact.join('/').squeeze('/').chomp('/') diff --git a/lib/gitlab/dependency_linker/godeps_json_linker.rb b/lib/gitlab/dependency_linker/godeps_json_linker.rb index d24c137793e..9166e9091ac 100644 --- a/lib/gitlab/dependency_linker/godeps_json_linker.rb +++ b/lib/gitlab/dependency_linker/godeps_json_linker.rb @@ -12,10 +12,12 @@ module Gitlab def link_dependencies link_json('ImportPath') do |path| case path + when %r{\A(?<repo>github\.com/#{REPO_REGEX})/(?<path>.+)\z} + "https://#{$~[:repo]}/tree/master/#{$~[:path]}" when %r{\A(?<repo>gitlab\.com/#{NESTED_REPO_REGEX})\.git/(?<path>.+)\z}, - %r{\A(?<repo>git(lab|hub)\.com/#{REPO_REGEX})/(?<path>.+)\z} + %r{\A(?<repo>gitlab\.com/#{REPO_REGEX})/(?<path>.+)\z} - "https://#{$~[:repo]}/tree/master/#{$~[:path]}" + "https://#{$~[:repo]}/-/tree/master/#{$~[:path]}" when /\Agolang\.org/ "https://godoc.org/#{path}" else diff --git a/lib/gitlab/import_export/import_export.yml b/lib/gitlab/import_export/import_export.yml index bf92de73b48..ba1ccd77604 100644 --- a/lib/gitlab/import_export/import_export.yml +++ b/lib/gitlab/import_export/import_export.yml @@ -220,6 +220,8 @@ excluded_attributes: - :encrypted_token - :encrypted_token_iv - :enabled + service_desk_setting: + - :outgoing_name methods: notes: diff --git a/lib/gitlab/middleware/go.rb b/lib/gitlab/middleware/go.rb index f207d91235f..53508938c49 100644 --- a/lib/gitlab/middleware/go.rb +++ b/lib/gitlab/middleware/go.rb @@ -60,7 +60,7 @@ module Gitlab end meta_import_tag = tag :meta, name: 'go-import', content: "#{import_prefix} git #{repository_url}" - meta_source_tag = tag :meta, name: 'go-source', content: "#{import_prefix} #{project_url} #{project_url}/tree/#{branch}{/dir} #{project_url}/blob/#{branch}{/dir}/{file}#L{line}" + meta_source_tag = tag :meta, name: 'go-source', content: "#{import_prefix} #{project_url} #{project_url}/-/tree/#{branch}{/dir} #{project_url}/-/blob/#{branch}{/dir}/{file}#L{line}" head_tag = content_tag :head, meta_import_tag + meta_source_tag html_tag = content_tag :html, head_tag + body_tag [html_tag, 200] diff --git a/lib/quality/test_level.rb b/lib/quality/test_level.rb index 90a8096cc2b..84470a73b1b 100644 --- a/lib/quality/test_level.rb +++ b/lib/quality/test_level.rb @@ -5,6 +5,10 @@ module Quality UnknownTestLevelError = Class.new(StandardError) TEST_LEVEL_FOLDERS = { + migration: %w[ + migrations + lib/gitlab/background_migration + ], unit: %w[ bin config @@ -19,7 +23,6 @@ module Quality initializers javascripts lib - migrations models policies presenters @@ -36,10 +39,6 @@ module Quality workers elastic_integration ], - migration: %w[ - migrations - lib/gitlab/background_migration - ], integration: %w[ controllers mailers diff --git a/locale/gitlab.pot b/locale/gitlab.pot index 6301a72f48a..be2ba9d22fb 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -4994,12 +4994,18 @@ msgstr "" msgid "Could not create group" msgstr "" +msgid "Could not create issue" +msgstr "" + msgid "Could not create project" msgstr "" msgid "Could not delete chat nickname %{chat_name}." msgstr "" +msgid "Could not fetch projects" +msgstr "" + msgid "Could not remove the trigger." msgstr "" @@ -5644,6 +5650,12 @@ msgstr "" msgid "Delete list" msgstr "" +msgid "Delete snippet" +msgstr "" + +msgid "Delete snippet?" +msgstr "" + msgid "Delete source branch" msgstr "" @@ -10001,6 +10013,9 @@ msgstr "" msgid "IssuesAnalytics|Total:" msgstr "" +msgid "Issue|Title" +msgstr "" + msgid "It must have a header row and at least two columns: the first column is the issue title and the second column is the issue description. The separator is automatically detected." msgstr "" @@ -10709,6 +10724,9 @@ msgstr "" msgid "Loading issues" msgstr "" +msgid "Loading snippet" +msgstr "" + msgid "Loading the GitLab IDE..." msgstr "" @@ -11724,6 +11742,9 @@ msgstr "" msgid "New issue" msgstr "" +msgid "New issue title" +msgstr "" + msgid "New label" msgstr "" diff --git a/package.json b/package.json index aa11e35d3e6..098cdd534a0 100644 --- a/package.json +++ b/package.json @@ -34,6 +34,7 @@ "@babel/core": "^7.6.2", "@babel/plugin-proposal-class-properties": "^7.5.5", "@babel/plugin-proposal-json-strings": "^7.2.0", + "@babel/plugin-proposal-optional-chaining": "^7.7.5", "@babel/plugin-proposal-private-methods": "^7.6.0", "@babel/plugin-syntax-dynamic-import": "^7.2.0", "@babel/plugin-syntax-import-meta": "^7.2.0", diff --git a/scripts/review_apps/base-config.yaml b/scripts/review_apps/base-config.yaml index e8a21451e02..999f730efc5 100644 --- a/scripts/review_apps/base-config.yaml +++ b/scripts/review_apps/base-config.yaml @@ -44,7 +44,7 @@ gitlab: memory: 37.5M maxReplicas: 3 hpa: - targetAverageValue: 130m + targetAverageValue: 500m deployment: livenessProbe: timeoutSeconds: 5 @@ -56,6 +56,8 @@ gitlab: limits: cpu: 975m memory: 1450M + hpa: + targetAverageValue: 650m task-runner: resources: requests: diff --git a/spec/controllers/concerns/metrics_dashboard_spec.rb b/spec/controllers/concerns/metrics_dashboard_spec.rb index ff2b6fbb8ec..662fb386208 100644 --- a/spec/controllers/concerns/metrics_dashboard_spec.rb +++ b/spec/controllers/concerns/metrics_dashboard_spec.rb @@ -72,7 +72,7 @@ describe MetricsDashboard do it 'includes project_blob_path only for project dashboards' do expect(system_dashboard['project_blob_path']).to be_nil - expect(project_dashboard['project_blob_path']).to eq("/#{project.namespace.path}/#{project.name}/blob/master/.gitlab/dashboards/test.yml") + expect(project_dashboard['project_blob_path']).to eq("/#{project.namespace.path}/#{project.name}/-/blob/master/.gitlab/dashboards/test.yml") end describe 'project permissions' do diff --git a/spec/controllers/projects/blame_controller_spec.rb b/spec/controllers/projects/blame_controller_spec.rb index dd7c0f45dc2..ac8394e3cd4 100644 --- a/spec/controllers/projects/blame_controller_spec.rb +++ b/spec/controllers/projects/blame_controller_spec.rb @@ -36,7 +36,7 @@ describe Projects::BlameController do it 'redirects' do expect(subject) - .to redirect_to("/#{project.full_path}/tree/master") + .to redirect_to("/#{project.full_path}/-/tree/master") end end diff --git a/spec/controllers/projects/blob_controller_spec.rb b/spec/controllers/projects/blob_controller_spec.rb index 78599935910..aa1dcdd9f1d 100644 --- a/spec/controllers/projects/blob_controller_spec.rb +++ b/spec/controllers/projects/blob_controller_spec.rb @@ -33,7 +33,7 @@ describe Projects::BlobController do it 'redirects' do expect(subject) - .to redirect_to("/#{project.full_path}/tree/master") + .to redirect_to("/#{project.full_path}/-/tree/master") end end @@ -115,7 +115,7 @@ describe Projects::BlobController do it 'redirects' do expect(subject) - .to redirect_to("/#{project.full_path}/tree/markdown/doc") + .to redirect_to("/#{project.full_path}/-/tree/markdown/doc") end end end diff --git a/spec/controllers/projects/branches_controller_spec.rb b/spec/controllers/projects/branches_controller_spec.rb index 4f8ab6a5def..bf7ef9dab0c 100644 --- a/spec/controllers/projects/branches_controller_spec.rb +++ b/spec/controllers/projects/branches_controller_spec.rb @@ -37,7 +37,7 @@ describe Projects::BranchesController do let(:ref) { "master" } it 'redirects' do expect(subject) - .to redirect_to("/#{project.full_path}/tree/merge_branch") + .to redirect_to("/#{project.full_path}/-/tree/merge_branch") end end @@ -46,7 +46,7 @@ describe Projects::BranchesController do let(:ref) { "master" } it 'redirects' do expect(subject) - .to redirect_to("/#{project.full_path}/tree/alert('merge');") + .to redirect_to("/#{project.full_path}/-/tree/alert('merge');") end end @@ -88,7 +88,7 @@ describe Projects::BranchesController do } expect(subject) - .to redirect_to("/#{project.full_path}/tree/1-feature-branch") + .to redirect_to("/#{project.full_path}/-/tree/1-feature-branch") end it 'posts a system note' do diff --git a/spec/controllers/projects/raw_controller_spec.rb b/spec/controllers/projects/raw_controller_spec.rb index bdf1c1a84d3..391b7ad1648 100644 --- a/spec/controllers/projects/raw_controller_spec.rb +++ b/spec/controllers/projects/raw_controller_spec.rb @@ -69,7 +69,7 @@ describe Projects::RawController do env: :raw_blob_request_limit, remote_ip: '0.0.0.0', request_method: 'GET', - path: "/#{project.full_path}/raw/#{file_path}" + path: "/#{project.full_path}/-/raw/#{file_path}" } expect(Gitlab::AuthLogger).to receive(:error).with(attributes).once diff --git a/spec/controllers/projects/serverless/functions_controller_spec.rb b/spec/controllers/projects/serverless/functions_controller_spec.rb index 73fb0fad646..33d66f4ac5a 100644 --- a/spec/controllers/projects/serverless/functions_controller_spec.rb +++ b/spec/controllers/projects/serverless/functions_controller_spec.rb @@ -149,6 +149,14 @@ describe Projects::Serverless::FunctionsController do include_examples 'GET #show with valid data' end + + context 'on Knative 0.9.0' do + before do + prepare_knative_stubs(knative_09_service(knative_stub_options)) + end + + include_examples 'GET #show with valid data' + end end end @@ -210,6 +218,14 @@ describe Projects::Serverless::FunctionsController do include_examples 'GET #index with data' end + + context 'on Knative 0.9.0' do + before do + prepare_knative_stubs(knative_09_service(knative_stub_options)) + end + + include_examples 'GET #index with data' + end end def prepare_knative_stubs(knative_service) diff --git a/spec/controllers/projects/tree_controller_spec.rb b/spec/controllers/projects/tree_controller_spec.rb index c0c11db5dd6..f89881af5e2 100644 --- a/spec/controllers/projects/tree_controller_spec.rb +++ b/spec/controllers/projects/tree_controller_spec.rb @@ -45,7 +45,7 @@ describe Projects::TreeController do it 'redirects' do expect(subject) - .to redirect_to("/#{project.full_path}/tree/master") + .to redirect_to("/#{project.full_path}/-/tree/master") end end @@ -60,7 +60,7 @@ describe Projects::TreeController do it 'redirects' do expect(subject) - .to redirect_to("/#{project.full_path}/tree/empty-branch") + .to redirect_to("/#{project.full_path}/-/tree/empty-branch") end end @@ -125,7 +125,7 @@ describe Projects::TreeController do let(:id) { 'master/README.md' } it 'redirects' do - redirect_url = "/#{project.full_path}/blob/master/README.md" + redirect_url = "/#{project.full_path}/-/blob/master/README.md" expect(subject) .to redirect_to(redirect_url) end @@ -153,7 +153,7 @@ describe Projects::TreeController do it 'redirects to the new directory' do expect(subject) - .to redirect_to("/#{project.full_path}/tree/#{branch_name}/#{path}") + .to redirect_to("/#{project.full_path}/-/tree/#{branch_name}/#{path}") expect(flash[:notice]).to eq('The directory has been successfully created.') end end @@ -164,7 +164,7 @@ describe Projects::TreeController do it 'does not allow overwriting of existing files' do expect(subject) - .to redirect_to("/#{project.full_path}/tree/master") + .to redirect_to("/#{project.full_path}/-/tree/master") expect(flash[:alert]).to eq('A file with this name already exists') end end diff --git a/spec/controllers/projects_controller_spec.rb b/spec/controllers/projects_controller_spec.rb index 5259c612bbd..a1dff0881b6 100644 --- a/spec/controllers/projects_controller_spec.rb +++ b/spec/controllers/projects_controller_spec.rb @@ -943,7 +943,7 @@ describe ProjectsController do end it 'renders JSON body with image links expanded' do - expanded_path = "/#{project_with_repo.full_path}/raw/master/files/images/logo-white.png" + expanded_path = "/#{project_with_repo.full_path}/-/raw/master/files/images/logo-white.png" post :preview_markdown, params: preview_markdown_params diff --git a/spec/features/dashboard/snippets_spec.rb b/spec/features/dashboard/snippets_spec.rb index 4fb01995cb0..ff3eb58931d 100644 --- a/spec/features/dashboard/snippets_spec.rb +++ b/spec/features/dashboard/snippets_spec.rb @@ -6,6 +6,7 @@ describe 'Dashboard snippets' do context 'when the project has snippets' do let(:project) { create(:project, :public) } let!(:snippets) { create_list(:project_snippet, 2, :public, author: project.owner, project: project) } + before do allow(Snippet).to receive(:default_per_page).and_return(1) sign_in(project.owner) @@ -13,10 +14,16 @@ describe 'Dashboard snippets' do end it_behaves_like 'paginated snippets' + + it 'shows new snippet button in header' do + parent_element = page.find('.page-title-controls') + expect(parent_element).to have_link('New snippet') + end end context 'when there are no project snippets', :js do let(:project) { create(:project, :public) } + before do sign_in(project.owner) visit dashboard_snippets_path @@ -28,6 +35,11 @@ describe 'Dashboard snippets' do expect(element).to have_content("Snippets are small pieces of code or notes that you want to keep.") expect(element.find('.svg-content img')['src']).to have_content('illustrations/snippets_empty') end + + it 'shows new snippet button in main content area' do + parent_element = page.find('.row.empty-state') + expect(parent_element).to have_link('New snippet') + end end context 'filtering by visibility' do @@ -76,4 +88,26 @@ describe 'Dashboard snippets' do expect(page).to have_content(snippets[0].title) end end + + context 'as an external user' do + let(:user) { create(:user, :external) } + before do + sign_in(user) + visit dashboard_snippets_path + end + + context 'without snippets' do + it 'hides new snippet button' do + expect(page).not_to have_link('New snippet') + end + end + + context 'with snippets' do + let!(:snippets) { create(:personal_snippet, author: user) } + + it 'hides new snippet button' do + expect(page).not_to have_link('New snippet') + end + end + end end diff --git a/spec/features/discussion_comments/snippets_spec.rb b/spec/features/discussion_comments/snippets_spec.rb index 082f35050c0..0dccb7f5bb3 100644 --- a/spec/features/discussion_comments/snippets_spec.rb +++ b/spec/features/discussion_comments/snippets_spec.rb @@ -8,6 +8,7 @@ describe 'Thread Comments Snippet', :js do let(:snippet) { create(:project_snippet, :private, project: project, author: user) } before do + stub_feature_flags(snippets_vue: false) project.add_maintainer(user) sign_in(user) diff --git a/spec/features/issues/move_spec.rb b/spec/features/issues/move_spec.rb index 1122504248f..7126707affd 100644 --- a/spec/features/issues/move_spec.rb +++ b/spec/features/issues/move_spec.rb @@ -70,6 +70,7 @@ describe 'issue move to another project' do context 'user does not have permission to move the issue to a project', :js do let!(:private_project) { create(:project, :private) } let(:another_project) { create(:project) } + before do another_project.add_guest(user) end diff --git a/spec/features/issues/user_views_issues_spec.rb b/spec/features/issues/user_views_issues_spec.rb index b986991f38f..8f174472f49 100644 --- a/spec/features/issues/user_views_issues_spec.rb +++ b/spec/features/issues/user_views_issues_spec.rb @@ -6,6 +6,7 @@ describe "User views issues" do let!(:closed_issue) { create(:closed_issue, project: project) } let!(:open_issue1) { create(:issue, project: project) } let!(:open_issue2) { create(:issue, project: project) } + set(:user) { create(:user) } shared_examples "opens issue from list" do diff --git a/spec/features/merge_requests/user_sorts_merge_requests_spec.rb b/spec/features/merge_requests/user_sorts_merge_requests_spec.rb index ca3e24d7036..3c217786d43 100644 --- a/spec/features/merge_requests/user_sorts_merge_requests_spec.rb +++ b/spec/features/merge_requests/user_sorts_merge_requests_spec.rb @@ -9,6 +9,7 @@ describe 'User sorts merge requests' do let!(:merge_request2) do create(:merge_request_with_diffs, source_project: project, target_project: project, source_branch: 'merge-test') end + set(:user) { create(:user) } set(:group) { create(:group) } set(:group_member) { create(:group_member, :maintainer, user: user, group: group) } diff --git a/spec/features/merge_requests/user_views_open_merge_requests_spec.rb b/spec/features/merge_requests/user_views_open_merge_requests_spec.rb index cefac9690ce..932090bdbce 100644 --- a/spec/features/merge_requests/user_views_open_merge_requests_spec.rb +++ b/spec/features/merge_requests/user_views_open_merge_requests_spec.rb @@ -113,6 +113,7 @@ describe 'User views open merge requests' do context 'when project is internal' do let!(:merge_request) { create(:merge_request, source_project: project, target_project: project) } + set(:project) { create(:project, :internal, :repository) } context 'when signed in' do diff --git a/spec/features/oauth_login_spec.rb b/spec/features/oauth_login_spec.rb index 4a1e8598131..29e9b0c313a 100644 --- a/spec/features/oauth_login_spec.rb +++ b/spec/features/oauth_login_spec.rb @@ -33,6 +33,7 @@ describe 'OAuth Login', :js, :allow_forgery_protection do let(:remember_me) { false } let(:user) { create(:omniauth_user, extern_uid: uid, provider: provider.to_s) } let(:two_factor_user) { create(:omniauth_user, :two_factor, extern_uid: uid, provider: provider.to_s) } + provider == :salesforce ? let(:additional_info) { { extra: { email_verified: true } } } : let(:additional_info) { {} } before do diff --git a/spec/features/participants_autocomplete_spec.rb b/spec/features/participants_autocomplete_spec.rb index a7bba124716..fdedd319116 100644 --- a/spec/features/participants_autocomplete_spec.rb +++ b/spec/features/participants_autocomplete_spec.rb @@ -34,6 +34,7 @@ describe 'Member autocomplete', :js do context 'adding a new note on a Issue' do let(:noteable) { create(:issue, author: author, project: project) } + before do visit project_issue_path(project, noteable) end @@ -47,6 +48,7 @@ describe 'Member autocomplete', :js do create(:merge_request, source_project: project, target_project: project, author: author) end + before do visit project_merge_request_path(project, noteable) end diff --git a/spec/features/projects/clusters/gcp_spec.rb b/spec/features/projects/clusters/gcp_spec.rb index 7c8b2640e89..142aaaffb7d 100644 --- a/spec/features/projects/clusters/gcp_spec.rb +++ b/spec/features/projects/clusters/gcp_spec.rb @@ -194,6 +194,7 @@ describe 'Gcp Cluster', :js, :do_not_mock_admin_mode do context 'when third party offers are disabled' do let(:admin) { create(:admin) } + before do stub_env('IN_MEMORY_APPLICATION_SETTINGS', 'false') sign_in(admin) diff --git a/spec/features/projects/files/user_edits_files_spec.rb b/spec/features/projects/files/user_edits_files_spec.rb index 374a7fb7936..cc428dce2a8 100644 --- a/spec/features/projects/files/user_edits_files_spec.rb +++ b/spec/features/projects/files/user_edits_files_spec.rb @@ -193,6 +193,7 @@ describe 'Projects > Files > User edits files', :js do context 'when the user already had a fork of the project', :js do let!(:forked_project) { fork_project(project2, user, namespace: user.namespace, repository: true) } + before do visit(project2_tree_path_root_ref) wait_for_requests diff --git a/spec/features/projects/snippets/create_snippet_spec.rb b/spec/features/projects/snippets/create_snippet_spec.rb index 684793ce116..ad65e04473c 100644 --- a/spec/features/projects/snippets/create_snippet_spec.rb +++ b/spec/features/projects/snippets/create_snippet_spec.rb @@ -18,6 +18,7 @@ describe 'Projects > Snippets > Create Snippet', :js do context 'when a user is authenticated' do before do + stub_feature_flags(snippets_vue: false) project.add_maintainer(user) sign_in(user) @@ -76,6 +77,10 @@ describe 'Projects > Snippets > Create Snippet', :js do end context 'when a user is not authenticated' do + before do + stub_feature_flags(snippets_vue: false) + end + it 'shows a public snippet on the index page but not the New snippet button' do snippet = create(:project_snippet, :public, project: project) diff --git a/spec/features/projects/snippets/show_spec.rb b/spec/features/projects/snippets/show_spec.rb index e448309356d..9be226c017f 100644 --- a/spec/features/projects/snippets/show_spec.rb +++ b/spec/features/projects/snippets/show_spec.rb @@ -8,6 +8,7 @@ describe 'Projects > Snippets > Project snippet', :js do let(:snippet) { create(:project_snippet, project: project, file_name: file_name, content: content) } before do + stub_feature_flags(snippets_vue: false) project.add_maintainer(user) sign_in(user) end diff --git a/spec/features/projects/snippets/user_comments_on_snippet_spec.rb b/spec/features/projects/snippets/user_comments_on_snippet_spec.rb index 239d19d35d1..11707378996 100644 --- a/spec/features/projects/snippets/user_comments_on_snippet_spec.rb +++ b/spec/features/projects/snippets/user_comments_on_snippet_spec.rb @@ -8,6 +8,7 @@ describe 'Projects > Snippets > User comments on a snippet', :js do let(:user) { create(:user) } before do + stub_feature_flags(snippets_vue: false) project.add_maintainer(user) sign_in(user) diff --git a/spec/features/projects/snippets/user_deletes_snippet_spec.rb b/spec/features/projects/snippets/user_deletes_snippet_spec.rb index 1b56d7bf26d..7e337710e19 100644 --- a/spec/features/projects/snippets/user_deletes_snippet_spec.rb +++ b/spec/features/projects/snippets/user_deletes_snippet_spec.rb @@ -8,6 +8,7 @@ describe 'Projects > Snippets > User deletes a snippet' do let(:user) { create(:user) } before do + stub_feature_flags(snippets_vue: false) project.add_maintainer(user) sign_in(user) diff --git a/spec/features/projects/snippets/user_updates_snippet_spec.rb b/spec/features/projects/snippets/user_updates_snippet_spec.rb index c7ff4f89fd6..93a5b4a7262 100644 --- a/spec/features/projects/snippets/user_updates_snippet_spec.rb +++ b/spec/features/projects/snippets/user_updates_snippet_spec.rb @@ -8,6 +8,7 @@ describe 'Projects > Snippets > User updates a snippet' do let(:user) { create(:user) } before do + stub_feature_flags(snippets_vue: false) project.add_maintainer(user) sign_in(user) diff --git a/spec/features/reportable_note/snippets_spec.rb b/spec/features/reportable_note/snippets_spec.rb index c2c853cdb05..bd37675315f 100644 --- a/spec/features/reportable_note/snippets_spec.rb +++ b/spec/features/reportable_note/snippets_spec.rb @@ -7,6 +7,7 @@ describe 'Reportable note on snippets', :js do let(:project) { create(:project) } before do + stub_feature_flags(snippets_vue: false) project.add_maintainer(user) sign_in(user) end diff --git a/spec/features/security/group/internal_access_spec.rb b/spec/features/security/group/internal_access_spec.rb index a182b6b9d57..8dd15789cd1 100644 --- a/spec/features/security/group/internal_access_spec.rb +++ b/spec/features/security/group/internal_access_spec.rb @@ -53,6 +53,7 @@ describe 'Internal Group access' do describe 'GET /groups/:path/merge_requests' do let(:project) { create(:project, :internal, :repository, group: group) } + subject { merge_requests_group_path(group) } it { is_expected.to be_allowed_for(:admin) } diff --git a/spec/features/security/group/private_access_spec.rb b/spec/features/security/group/private_access_spec.rb index 5e3e9824aaa..0720302b03b 100644 --- a/spec/features/security/group/private_access_spec.rb +++ b/spec/features/security/group/private_access_spec.rb @@ -53,6 +53,7 @@ describe 'Private Group access' do describe 'GET /groups/:path/merge_requests' do let(:project) { create(:project, :private, :repository, group: group) } + subject { merge_requests_group_path(group) } it { is_expected.to be_allowed_for(:admin) } diff --git a/spec/features/security/group/public_access_spec.rb b/spec/features/security/group/public_access_spec.rb index efc84205980..0a18a0ff812 100644 --- a/spec/features/security/group/public_access_spec.rb +++ b/spec/features/security/group/public_access_spec.rb @@ -53,6 +53,7 @@ describe 'Public Group access' do describe 'GET /groups/:path/merge_requests' do let(:project) { create(:project, :public, :repository, group: group) } + subject { merge_requests_group_path(group) } it { is_expected.to be_allowed_for(:admin) } diff --git a/spec/features/security/project/internal_access_spec.rb b/spec/features/security/project/internal_access_spec.rb index 20a320e5b92..5c74b566ef0 100644 --- a/spec/features/security/project/internal_access_spec.rb +++ b/spec/features/security/project/internal_access_spec.rb @@ -129,6 +129,7 @@ describe "Internal Project Access" do describe "GET /:project_path/blob" do let(:commit) { project.repository.commit } + subject { project_blob_path(project, File.join(commit.id, '.gitignore')) } it { is_expected.to be_allowed_for(:admin) } @@ -186,6 +187,7 @@ describe "Internal Project Access" do describe "GET /:project_path/issues/:id/edit" do let(:issue) { create(:issue, project: project) } + subject { edit_project_issue_path(project, issue) } it { is_expected.to be_allowed_for(:admin) } @@ -327,6 +329,7 @@ describe "Internal Project Access" do describe "GET /:project_path/pipelines/:id" do let(:pipeline) { create(:ci_pipeline, project: project) } + subject { project_pipeline_path(project, pipeline) } it { is_expected.to be_allowed_for(:admin) } @@ -379,6 +382,7 @@ describe "Internal Project Access" do describe "GET /:project_path/builds/:id" do let(:pipeline) { create(:ci_pipeline, project: project) } let(:build) { create(:ci_build, pipeline: pipeline) } + subject { project_job_path(project, build.id) } context "when allowed for public and internal" do @@ -417,6 +421,7 @@ describe "Internal Project Access" do describe 'GET /:project_path/builds/:id/trace' do let(:pipeline) { create(:ci_pipeline, project: project) } let(:build) { create(:ci_build, pipeline: pipeline) } + subject { trace_project_job_path(project, build.id) } context 'when allowed for public and internal' do @@ -482,6 +487,7 @@ describe "Internal Project Access" do describe "GET /:project_path/-/environments/:id" do let(:environment) { create(:environment, project: project) } + subject { project_environment_path(project, environment) } it { is_expected.to be_allowed_for(:admin) } @@ -497,6 +503,7 @@ describe "Internal Project Access" do describe "GET /:project_path/-/environments/:id/deployments" do let(:environment) { create(:environment, project: project) } + subject { project_environment_deployments_path(project, environment) } it { is_expected.to be_allowed_for(:admin) } diff --git a/spec/features/security/project/private_access_spec.rb b/spec/features/security/project/private_access_spec.rb index 62f9a96305d..2404b7cc69d 100644 --- a/spec/features/security/project/private_access_spec.rb +++ b/spec/features/security/project/private_access_spec.rb @@ -129,6 +129,7 @@ describe "Private Project Access" do describe "GET /:project_path/blob" do let(:commit) { project.repository.commit } + subject { project_blob_path(project, File.join(commit.id, '.gitignore')) } it { is_expected.to be_allowed_for(:admin) } @@ -186,6 +187,7 @@ describe "Private Project Access" do describe "GET /:project_path/issues/:id/edit" do let(:issue) { create(:issue, project: project) } + subject { edit_project_issue_path(project, issue) } it { is_expected.to be_allowed_for(:admin) } @@ -311,6 +313,7 @@ describe "Private Project Access" do describe "GET /:project_path/pipelines/:id" do let(:pipeline) { create(:ci_pipeline, project: project) } + subject { project_pipeline_path(project, pipeline) } it { is_expected.to be_allowed_for(:admin) } @@ -365,6 +368,7 @@ describe "Private Project Access" do describe "GET /:project_path/builds/:id" do let(:pipeline) { create(:ci_pipeline, project: project) } let(:build) { create(:ci_build, pipeline: pipeline) } + subject { project_job_path(project, build.id) } it { is_expected.to be_allowed_for(:admin) } @@ -398,6 +402,7 @@ describe "Private Project Access" do describe 'GET /:project_path/builds/:id/trace' do let(:pipeline) { create(:ci_pipeline, project: project) } let(:build) { create(:ci_build, pipeline: pipeline) } + subject { trace_project_job_path(project, build.id) } it { is_expected.to be_allowed_for(:admin) } @@ -443,6 +448,7 @@ describe "Private Project Access" do describe "GET /:project_path/-/environments/:id" do let(:environment) { create(:environment, project: project) } + subject { project_environment_path(project, environment) } it { is_expected.to be_allowed_for(:admin) } @@ -458,6 +464,7 @@ describe "Private Project Access" do describe "GET /:project_path/-/environments/:id/deployments" do let(:environment) { create(:environment, project: project) } + subject { project_environment_deployments_path(project, environment) } it { is_expected.to be_allowed_for(:admin) } diff --git a/spec/features/security/project/public_access_spec.rb b/spec/features/security/project/public_access_spec.rb index 317c7bae084..8e07af61c8b 100644 --- a/spec/features/security/project/public_access_spec.rb +++ b/spec/features/security/project/public_access_spec.rb @@ -143,6 +143,7 @@ describe "Public Project Access" do describe "GET /:project_path/pipelines/:id" do let(:pipeline) { create(:ci_pipeline, project: project) } + subject { project_pipeline_path(project, pipeline) } it { is_expected.to be_allowed_for(:admin) } @@ -195,6 +196,7 @@ describe "Public Project Access" do describe "GET /:project_path/builds/:id" do let(:pipeline) { create(:ci_pipeline, project: project) } let(:build) { create(:ci_build, pipeline: pipeline) } + subject { project_job_path(project, build.id) } context "when allowed for public" do @@ -233,6 +235,7 @@ describe "Public Project Access" do describe 'GET /:project_path/builds/:id/trace' do let(:pipeline) { create(:ci_pipeline, project: project) } let(:build) { create(:ci_build, pipeline: pipeline) } + subject { trace_project_job_path(project, build.id) } context 'when allowed for public' do @@ -298,6 +301,7 @@ describe "Public Project Access" do describe "GET /:project_path/-/environments/:id" do let(:environment) { create(:environment, project: project) } + subject { project_environment_path(project, environment) } it { is_expected.to be_allowed_for(:admin) } @@ -313,6 +317,7 @@ describe "Public Project Access" do describe "GET /:project_path/-/environments/:id/deployments" do let(:environment) { create(:environment, project: project) } + subject { project_environment_deployments_path(project, environment) } it { is_expected.to be_allowed_for(:admin) } @@ -399,6 +404,7 @@ describe "Public Project Access" do describe "GET /:project_path/issues/:id/edit" do let(:issue) { create(:issue, project: project) } + subject { edit_project_issue_path(project, issue) } it { is_expected.to be_allowed_for(:admin) } diff --git a/spec/features/snippets/explore_spec.rb b/spec/features/snippets/explore_spec.rb index 57e91fea709..2075742eafb 100644 --- a/spec/features/snippets/explore_spec.rb +++ b/spec/features/snippets/explore_spec.rb @@ -6,30 +6,59 @@ describe 'Explore Snippets' do let!(:public_snippet) { create(:personal_snippet, :public) } let!(:internal_snippet) { create(:personal_snippet, :internal) } let!(:private_snippet) { create(:personal_snippet, :private) } + let(:user) { nil } - it 'User should see snippets that are not private' do - sign_in create(:user) + before do + sign_in(user) if user visit explore_snippets_path - - expect(page).to have_content(public_snippet.title) - expect(page).to have_content(internal_snippet.title) - expect(page).not_to have_content(private_snippet.title) end - it 'External user should see only public snippets' do - sign_in create(:user, :external) - visit explore_snippets_path + context 'User' do + let(:user) { create(:user) } + + it 'see snippets that are not private' do + expect(page).to have_content(public_snippet.title) + expect(page).to have_content(internal_snippet.title) + expect(page).not_to have_content(private_snippet.title) + end - expect(page).to have_content(public_snippet.title) - expect(page).not_to have_content(internal_snippet.title) - expect(page).not_to have_content(private_snippet.title) + it 'shows new snippet button in header' do + parent_element = page.find('.page-title-controls') + expect(parent_element).to have_link('New snippet') + end end - it 'Not authenticated user should see only public snippets' do - visit explore_snippets_path + context 'External user' do + let(:user) { create(:user, :external) } + + it 'see only public snippets' do + expect(page).to have_content(public_snippet.title) + expect(page).not_to have_content(internal_snippet.title) + expect(page).not_to have_content(private_snippet.title) + end + + context 'without snippets' do + before do + Snippet.delete_all + end + + it 'hides new snippet button' do + expect(page).not_to have_link('New snippet') + end + end + + context 'with snippets' do + it 'hides new snippet button' do + expect(page).not_to have_link('New snippet') + end + end + end - expect(page).to have_content(public_snippet.title) - expect(page).not_to have_content(internal_snippet.title) - expect(page).not_to have_content(private_snippet.title) + context 'Not authenticated user' do + it 'see only public snippets' do + expect(page).to have_content(public_snippet.title) + expect(page).not_to have_content(internal_snippet.title) + expect(page).not_to have_content(private_snippet.title) + end end end diff --git a/spec/features/task_lists_spec.rb b/spec/features/task_lists_spec.rb index acffc4ce580..11429f16f42 100644 --- a/spec/features/task_lists_spec.rb +++ b/spec/features/task_lists_spec.rb @@ -146,6 +146,7 @@ describe 'Task Lists' do describe 'for Notes' do let!(:issue) { create(:issue, author: user, project: project) } + describe 'multiple tasks' do let!(:note) do create(:note, note: markdown, noteable: issue, diff --git a/spec/features/users/login_spec.rb b/spec/features/users/login_spec.rb index b7c54bb6de8..5f4f92e547c 100644 --- a/spec/features/users/login_spec.rb +++ b/spec/features/users/login_spec.rb @@ -406,6 +406,7 @@ describe 'Login' do describe 'with required two-factor authentication enabled' do let(:user) { create(:user) } + # TODO: otp_grace_period_started_at context 'global setting' do diff --git a/spec/finders/clusters_finder_spec.rb b/spec/finders/clusters_finder_spec.rb index f6ea8347f67..5dde616f679 100644 --- a/spec/finders/clusters_finder_spec.rb +++ b/spec/finders/clusters_finder_spec.rb @@ -4,6 +4,7 @@ require 'spec_helper' describe ClustersFinder do let(:project) { create(:project) } + set(:user) { create(:user) } describe '#execute' do diff --git a/spec/finders/group_descendants_finder_spec.rb b/spec/finders/group_descendants_finder_spec.rb index 17875a9b9ab..ee8606e474e 100644 --- a/spec/finders/group_descendants_finder_spec.rb +++ b/spec/finders/group_descendants_finder_spec.rb @@ -6,6 +6,7 @@ describe GroupDescendantsFinder do let(:user) { create(:user) } let(:group) { create(:group) } let(:params) { {} } + subject(:finder) do described_class.new(current_user: user, parent_group: group, params: params) end diff --git a/spec/finders/group_projects_finder_spec.rb b/spec/finders/group_projects_finder_spec.rb index 0a7ca5211e1..89fc1e380dc 100644 --- a/spec/finders/group_projects_finder_spec.rb +++ b/spec/finders/group_projects_finder_spec.rb @@ -132,11 +132,13 @@ describe GroupProjectsFinder do context "only shared" do let(:options) { { only_shared: true } } + it { is_expected.to eq([shared_project_3, shared_project_2, shared_project_1]) } end context "only owned" do let(:options) { { only_owned: true } } + it { is_expected.to eq([private_project, public_project]) } end diff --git a/spec/finders/groups_finder_spec.rb b/spec/finders/groups_finder_spec.rb index 741a89a270b..939b818f165 100644 --- a/spec/finders/groups_finder_spec.rb +++ b/spec/finders/groups_finder_spec.rb @@ -111,6 +111,7 @@ describe GroupsFinder do context 'authorized to private project' do context 'project one level deep' do let!(:subproject) { create(:project, :private, namespace: private_subgroup) } + before do subproject.add_guest(user) end @@ -129,6 +130,7 @@ describe GroupsFinder do context 'project two levels deep' do let!(:private_subsubgroup) { create(:group, :private, parent: private_subgroup) } let!(:subsubproject) { create(:project, :private, namespace: private_subsubgroup) } + before do subsubproject.add_guest(user) end diff --git a/spec/finders/issues_finder_spec.rb b/spec/finders/issues_finder_spec.rb index 6c10a617279..c52ee89006b 100644 --- a/spec/finders/issues_finder_spec.rb +++ b/spec/finders/issues_finder_spec.rb @@ -786,6 +786,7 @@ describe IssuesFinder do describe '#with_confidentiality_access_check' do let(:guest) { create(:user) } + set(:authorized_user) { create(:user) } set(:project) { create(:project, namespace: authorized_user.namespace) } set(:public_issue) { create(:issue, project: project) } diff --git a/spec/finders/merge_request_target_project_finder_spec.rb b/spec/finders/merge_request_target_project_finder_spec.rb index 7fef16d1040..4d2e4c5318c 100644 --- a/spec/finders/merge_request_target_project_finder_spec.rb +++ b/spec/finders/merge_request_target_project_finder_spec.rb @@ -6,6 +6,7 @@ describe MergeRequestTargetProjectFinder do include ProjectForksHelper let(:user) { create(:user) } + subject(:finder) { described_class.new(current_user: user, source_project: forked_project) } shared_examples 'finding related projects' do diff --git a/spec/finders/pipelines_finder_spec.rb b/spec/finders/pipelines_finder_spec.rb index 116088f5141..c8a4ea799c3 100644 --- a/spec/finders/pipelines_finder_spec.rb +++ b/spec/finders/pipelines_finder_spec.rb @@ -6,6 +6,7 @@ describe PipelinesFinder do let(:project) { create(:project, :public, :repository) } let(:current_user) { nil } let(:params) { {} } + subject { described_class.new(project, current_user, params).execute } describe "#execute" do diff --git a/spec/finders/projects_finder_spec.rb b/spec/finders/projects_finder_spec.rb index a9344cd593a..bf97e3cf7db 100644 --- a/spec/finders/projects_finder_spec.rb +++ b/spec/finders/projects_finder_spec.rb @@ -181,6 +181,7 @@ describe ProjectsFinder, :do_not_mock_admin_mode do describe 'filter by non_public' do let(:params) { { non_public: true } } + before do private_project.add_developer(current_user) end @@ -190,6 +191,7 @@ describe ProjectsFinder, :do_not_mock_admin_mode do describe 'filter by starred' do let(:params) { { starred: true } } + before do current_user.toggle_star(public_project) end diff --git a/spec/finders/tags_finder_spec.rb b/spec/finders/tags_finder_spec.rb index 582d82bbf79..b9de2d29895 100644 --- a/spec/finders/tags_finder_spec.rb +++ b/spec/finders/tags_finder_spec.rb @@ -96,6 +96,7 @@ describe TagsFinder do context 'filter and sort' do let(:tags_to_compare) { %w[v1.0.0 v1.1.0] } + subject { described_class.new(repository, params).execute.select { |tag| tags_to_compare.include?(tag.name) } } context 'when sort by updated_desc' do diff --git a/spec/frontend/fixtures/static/projects.json b/spec/frontend/fixtures/static/projects.json index d92d3acdea0..f28d9899099 100644 --- a/spec/frontend/fixtures/static/projects.json +++ b/spec/frontend/fixtures/static/projects.json @@ -99,6 +99,15 @@ "access_level": 50, "notification_level": 3 } + }, + "_links": { + "self": "https://gitlab.com/api/v4/projects/278964", + "issues": "https://gitlab.com/api/v4/projects/278964/issues", + "merge_requests": "https://gitlab.com/api/v4/projects/278964/merge_requests", + "repo_branches": "https://gitlab.com/api/v4/projects/278964/repository/branches", + "labels": "https://gitlab.com/api/v4/projects/278964/labels", + "events": "https://gitlab.com/api/v4/projects/278964/events", + "members": "https://gitlab.com/api/v4/projects/278964/members" } }, { "id": 7, diff --git a/spec/frontend/helpers/dom_shims/index.js b/spec/frontend/helpers/dom_shims/index.js index 40256398e6d..1fc5130cefc 100644 --- a/spec/frontend/helpers/dom_shims/index.js +++ b/spec/frontend/helpers/dom_shims/index.js @@ -1 +1,2 @@ import './get_client_rects'; +import './inner_text'; diff --git a/spec/frontend/helpers/dom_shims/inner_text.js b/spec/frontend/helpers/dom_shims/inner_text.js new file mode 100644 index 00000000000..2b8201eed31 --- /dev/null +++ b/spec/frontend/helpers/dom_shims/inner_text.js @@ -0,0 +1,11 @@ +// workaround for JSDOM not supporting innerText +// see https://github.com/jsdom/jsdom/issues/1245 +Object.defineProperty(global.Element.prototype, 'innerText', { + get() { + return this.textContent; + }, + set(value) { + this.textContext = value; + }, + configurable: true, // make it so that it doesn't blow chunks on re-running tests with things like --watch +}); diff --git a/spec/frontend/ide/stores/getters_spec.js b/spec/frontend/ide/stores/getters_spec.js index d196f6f79d5..21c5e886738 100644 --- a/spec/frontend/ide/stores/getters_spec.js +++ b/spec/frontend/ide/stores/getters_spec.js @@ -1,12 +1,14 @@ import * as getters from '~/ide/stores/getters'; -import state from '~/ide/stores/state'; +import { createStore } from '~/ide/stores'; import { file } from '../helpers'; describe('IDE store getters', () => { let localState; + let localStore; beforeEach(() => { - localState = state(); + localStore = createStore(); + localState = localStore.state; }); describe('activeFile', () => { @@ -310,4 +312,90 @@ describe('IDE store getters', () => { expect(getters.canPushToBranch({}, localGetters)).toBeFalsy(); }); }); + + describe('isFileDeletedAndReadded', () => { + const f = { ...file('sample'), content: 'sample', raw: 'sample' }; + + it.each([ + { + entry: { ...f, tempFile: true }, + staged: { ...f, deleted: true }, + output: true, + }, + { + entry: { ...f, content: 'changed' }, + staged: { ...f, content: 'changed' }, + output: false, + }, + { + entry: { ...f, content: 'changed' }, + output: false, + }, + ])( + 'checks staged and unstaged files to see if a file was deleted and readded (case %#)', + ({ entry, staged, output }) => { + Object.assign(localState, { + entries: { + [entry.path]: entry, + }, + stagedFiles: [], + }); + + if (staged) localState.stagedFiles.push(staged); + + expect(localStore.getters.isFileDeletedAndReadded(entry.path)).toBe(output); + }, + ); + }); + + describe('getDiffInfo', () => { + const f = { ...file('sample'), content: 'sample', raw: 'sample' }; + it.each([ + { + entry: { ...f, tempFile: true }, + staged: { ...f, deleted: true }, + output: { deleted: false, changed: false, tempFile: false }, + }, + { + entry: { ...f, tempFile: true, content: 'changed', raw: '' }, + staged: { ...f, deleted: true }, + output: { deleted: false, changed: true, tempFile: false }, + }, + { + entry: { ...f, content: 'changed' }, + output: { changed: true }, + }, + { + entry: { ...f, content: 'sample' }, + staged: { ...f, content: 'changed' }, + output: { changed: false }, + }, + { + entry: { ...f, deleted: true }, + output: { deleted: true, changed: false }, + }, + { + entry: { ...f, prevPath: 'old_path' }, + output: { renamed: true, changed: false }, + }, + { + entry: { ...f, prevPath: 'old_path', content: 'changed' }, + output: { renamed: true, changed: true }, + }, + ])( + 'compares changes in a file entry and returns a resulting diff info (case %#)', + ({ entry, staged, output }) => { + Object.assign(localState, { + entries: { + [entry.path]: entry, + }, + stagedFiles: [], + }); + + if (staged) localState.stagedFiles.push(staged); + + expect(localStore.getters.getDiffInfo(entry.path)).toEqual(expect.objectContaining(output)); + }, + ); + }); }); diff --git a/spec/javascripts/monitoring/charts/column_spec.js b/spec/frontend/monitoring/components/charts/column_spec.js index 9676617e8e1..b4539801e0f 100644 --- a/spec/javascripts/monitoring/charts/column_spec.js +++ b/spec/frontend/monitoring/components/charts/column_spec.js @@ -4,6 +4,10 @@ import ColumnChart from '~/monitoring/components/charts/column.vue'; const localVue = createLocalVue(); +jest.mock('~/lib/utils/icon_utils', () => ({ + getSvgIconPathContent: jest.fn().mockResolvedValue('mockSvgPathContent'), +})); + describe('Column component', () => { let columnChart; diff --git a/spec/javascripts/monitoring/charts/empty_chart_spec.js b/spec/frontend/monitoring/components/charts/empty_chart_spec.js index 06822126b59..06822126b59 100644 --- a/spec/javascripts/monitoring/charts/empty_chart_spec.js +++ b/spec/frontend/monitoring/components/charts/empty_chart_spec.js diff --git a/spec/javascripts/monitoring/charts/heatmap_spec.js b/spec/frontend/monitoring/components/charts/heatmap_spec.js index 9a98fc6fb05..5e2c1932e9e 100644 --- a/spec/javascripts/monitoring/charts/heatmap_spec.js +++ b/spec/frontend/monitoring/components/charts/heatmap_spec.js @@ -1,7 +1,7 @@ import { shallowMount } from '@vue/test-utils'; import { GlHeatmap } from '@gitlab/ui/dist/charts'; import Heatmap from '~/monitoring/components/charts/heatmap.vue'; -import { graphDataPrometheusQueryRangeMultiTrack } from '../mock_data'; +import { graphDataPrometheusQueryRangeMultiTrack } from '../../mock_data'; describe('Heatmap component', () => { let heatmapChart; diff --git a/spec/javascripts/monitoring/charts/single_stat_spec.js b/spec/frontend/monitoring/components/charts/single_stat_spec.js index 6adca0b0eed..78bcc400787 100644 --- a/spec/javascripts/monitoring/charts/single_stat_spec.js +++ b/spec/frontend/monitoring/components/charts/single_stat_spec.js @@ -1,6 +1,6 @@ import { shallowMount, createLocalVue } from '@vue/test-utils'; import SingleStatChart from '~/monitoring/components/charts/single_stat.vue'; -import { graphDataPrometheusQuery } from '../mock_data'; +import { graphDataPrometheusQuery } from '../../mock_data'; const localVue = createLocalVue(); diff --git a/spec/frontend/monitoring/charts/time_series_spec.js b/spec/frontend/monitoring/components/charts/time_series_spec.js index 128c4bc49f1..098b3408e67 100644 --- a/spec/frontend/monitoring/charts/time_series_spec.js +++ b/spec/frontend/monitoring/components/charts/time_series_spec.js @@ -12,20 +12,14 @@ import { mockedQueryResultPayload, mockProjectDir, mockHost, -} from '../mock_data'; - +} from '../../mock_data'; import * as iconUtils from '~/lib/utils/icon_utils'; -const mockSvgPathContent = 'mockSvgPathContent'; const mockWidgets = 'mockWidgets'; +const mockSvgPathContent = 'mockSvgPathContent'; jest.mock('~/lib/utils/icon_utils', () => ({ - getSvgIconPathContent: jest.fn().mockImplementation( - () => - new Promise(resolve => { - resolve(mockSvgPathContent); - }), - ), + getSvgIconPathContent: jest.fn().mockImplementation(() => Promise.resolve(mockSvgPathContent)), })); describe('Time series component', () => { diff --git a/spec/frontend/repository/components/table/parent_row_spec.js b/spec/frontend/repository/components/table/parent_row_spec.js index 7020055271f..63f84b2597b 100644 --- a/spec/frontend/repository/components/table/parent_row_spec.js +++ b/spec/frontend/repository/components/table/parent_row_spec.js @@ -30,8 +30,8 @@ describe('Repository parent row component', () => { it.each` path | to - ${'app'} | ${'/tree/master/'} - ${'app/assets'} | ${'/tree/master/app'} + ${'app'} | ${'/-/tree/master/'} + ${'app/assets'} | ${'/-/tree/master/app'} `('renders link in $path to $to', ({ path, to }) => { factory(path); @@ -46,7 +46,7 @@ describe('Repository parent row component', () => { vm.find('td').trigger('click'); expect($router.push).toHaveBeenCalledWith({ - path: '/tree/master/app', + path: '/-/tree/master/app', }); }); @@ -58,7 +58,7 @@ describe('Repository parent row component', () => { vm.find('a').trigger('click'); expect($router.push).not.toHaveBeenCalledWith({ - path: '/tree/master/app', + path: '/-/tree/master/app', }); }); }); diff --git a/spec/frontend/repository/components/table/row_spec.js b/spec/frontend/repository/components/table/row_spec.js index 94fa8b1e363..3114b6a2eaa 100644 --- a/spec/frontend/repository/components/table/row_spec.js +++ b/spec/frontend/repository/components/table/row_spec.js @@ -83,7 +83,7 @@ describe('Repository table row component', () => { vm.trigger('click'); if (pushes) { - expect($router.push).toHaveBeenCalledWith({ path: '/tree/master/test' }); + expect($router.push).toHaveBeenCalledWith({ path: '/-/tree/master/test' }); } else { expect($router.push).not.toHaveBeenCalled(); } diff --git a/spec/frontend/repository/router_spec.js b/spec/frontend/repository/router_spec.js index f61a0ccd1e6..1efd74a30c2 100644 --- a/spec/frontend/repository/router_spec.js +++ b/spec/frontend/repository/router_spec.js @@ -4,11 +4,11 @@ import createRouter from '~/repository/router'; describe('Repository router spec', () => { it.each` - path | component | componentName - ${'/'} | ${IndexPage} | ${'IndexPage'} - ${'/tree/master'} | ${TreePage} | ${'TreePage'} - ${'/tree/master/app/assets'} | ${TreePage} | ${'TreePage'} - ${'/tree/123/app/assets'} | ${null} | ${'null'} + path | component | componentName + ${'/'} | ${IndexPage} | ${'IndexPage'} + ${'/-/tree/master'} | ${TreePage} | ${'TreePage'} + ${'/-/tree/master/app/assets'} | ${TreePage} | ${'TreePage'} + ${'/-/tree/123/app/assets'} | ${null} | ${'null'} `('sets component as $componentName for path "$path"', ({ path, component }) => { const router = createRouter('', 'master'); diff --git a/spec/frontend/snippets/components/app_spec.js b/spec/frontend/snippets/components/app_spec.js index 535e71b6da7..f2800f9e6af 100644 --- a/spec/frontend/snippets/components/app_spec.js +++ b/spec/frontend/snippets/components/app_spec.js @@ -1,19 +1,22 @@ import SnippetApp from '~/snippets/components/app.vue'; +import SnippetHeader from '~/snippets/components/snippet_header.vue'; +import { GlLoadingIcon } from '@gitlab/ui'; + import { createLocalVue, shallowMount } from '@vue/test-utils'; describe('Snippet view app', () => { let wrapper; - let snippetDataMock; const localVue = createLocalVue(); const defaultProps = { - snippetGid: 'gid://gitlab/PersonalSnippet/35', + snippetGid: 'gid://gitlab/PersonalSnippet/42', }; - function createComponent({ props = defaultProps, snippetData = {} } = {}) { - snippetDataMock = jest.fn(); + function createComponent({ props = defaultProps, loading = false } = {}) { const $apollo = { queries: { - snippetData: snippetDataMock, + snippet: { + loading, + }, }, }; @@ -25,17 +28,18 @@ describe('Snippet view app', () => { ...props, }, }); - - wrapper.setData({ - snippetData, - }); } afterEach(() => { wrapper.destroy(); }); - it('renders itself', () => { + it('renders loader while the query is in flight', () => { + createComponent({ loading: true }); + expect(wrapper.find(GlLoadingIcon).exists()).toBe(true); + }); + + it('renders SnippetHeader component after the query is finished', () => { createComponent(); - expect(wrapper.find('.js-snippet-view').exists()).toBe(true); + expect(wrapper.find(SnippetHeader).exists()).toBe(true); }); }); diff --git a/spec/frontend/snippets/components/snippet_header_spec.js b/spec/frontend/snippets/components/snippet_header_spec.js new file mode 100644 index 00000000000..8847a3a6938 --- /dev/null +++ b/spec/frontend/snippets/components/snippet_header_spec.js @@ -0,0 +1,171 @@ +import SnippetHeader from '~/snippets/components/snippet_header.vue'; +import DeleteSnippetMutation from '~/snippets/mutations/deleteSnippet.mutation.graphql'; +import { ApolloMutation } from 'vue-apollo'; +import { GlButton, GlModal } from '@gitlab/ui'; +import { createLocalVue, shallowMount } from '@vue/test-utils'; + +describe('Snippet header component', () => { + let wrapper; + const localVue = createLocalVue(); + const snippet = { + snippet: { + id: 'gid://gitlab/PersonalSnippet/50', + title: 'The property of Thor', + visibilityLevel: 'private', + webUrl: 'http://personal.dev.null/42', + userPermissions: { + adminSnippet: true, + updateSnippet: true, + reportSnippet: false, + }, + project: null, + author: { + name: 'Thor Odinson', + }, + }, + }; + const mutationVariables = { + mutation: DeleteSnippetMutation, + variables: { + id: snippet.snippet.id, + }, + }; + const errorMsg = 'Foo bar'; + const err = { message: errorMsg }; + + const resolveMutate = jest.fn(() => Promise.resolve()); + const rejectMutation = jest.fn(() => Promise.reject(err)); + + const mutationTypes = { + RESOLVE: resolveMutate, + REJECT: rejectMutation, + }; + + function createComponent({ + loading = false, + permissions = {}, + mutationRes = mutationTypes.RESOLVE, + } = {}) { + const defaultProps = Object.assign({}, snippet); + if (permissions) { + Object.assign(defaultProps.snippet.userPermissions, { + ...permissions, + }); + } + const $apollo = { + queries: { + canCreateSnippet: { + loading, + }, + }, + mutate: mutationRes, + }; + + wrapper = shallowMount(SnippetHeader, { + sync: false, + mocks: { $apollo }, + localVue, + propsData: { + ...defaultProps, + }, + stubs: { + ApolloMutation, + }, + }); + } + + afterEach(() => { + wrapper.destroy(); + }); + + it('renders itself', () => { + createComponent(); + expect(wrapper.find('.detail-page-header').exists()).toBe(true); + }); + + it('renders action buttons based on permissions', () => { + createComponent({ + permissions: { + adminSnippet: false, + updateSnippet: false, + }, + }); + expect(wrapper.findAll(GlButton).length).toEqual(0); + + createComponent({ + permissions: { + adminSnippet: true, + updateSnippet: false, + }, + }); + expect(wrapper.findAll(GlButton).length).toEqual(1); + + createComponent({ + permissions: { + adminSnippet: true, + updateSnippet: true, + }, + }); + expect(wrapper.findAll(GlButton).length).toEqual(2); + + createComponent({ + permissions: { + adminSnippet: true, + updateSnippet: true, + }, + }); + wrapper.setData({ + canCreateSnippet: true, + }); + return wrapper.vm.$nextTick().then(() => { + expect(wrapper.findAll(GlButton).length).toEqual(3); + }); + }); + + it('renders modal for deletion of a snippet', () => { + createComponent(); + expect(wrapper.find(GlModal).exists()).toBe(true); + }); + + describe('Delete mutation', () => { + const { location } = window; + + beforeEach(() => { + delete window.location; + window.location = { + pathname: '', + }; + }); + + afterEach(() => { + window.location = location; + }); + + it('dispatches a mutation to delete the snippet with correct variables', () => { + createComponent(); + wrapper.vm.deleteSnippet(); + expect(mutationTypes.RESOLVE).toHaveBeenCalledWith(mutationVariables); + }); + + it('sets error message if mutation fails', () => { + createComponent({ mutationRes: mutationTypes.REJECT }); + expect(Boolean(wrapper.vm.errorMessage)).toBe(false); + + wrapper.vm.deleteSnippet(); + return wrapper.vm.$nextTick().then(() => { + expect(wrapper.vm.errorMessage).toEqual(errorMsg); + }); + }); + + it('closes modal and redirects to snippets listing in case of successful mutation', () => { + createComponent(); + wrapper.vm.closeDeleteModal = jest.fn(); + + wrapper.vm.deleteSnippet(); + return wrapper.vm.$nextTick().then(() => { + expect(wrapper.vm.closeDeleteModal).toHaveBeenCalled(); + expect(window.location.pathname).toEqual('dashboard/snippets'); + }); + }); + }); +}); diff --git a/spec/frontend/test_setup.js b/spec/frontend/test_setup.js index 4636de6b8b6..ab42dbe7cd1 100644 --- a/spec/frontend/test_setup.js +++ b/spec/frontend/test_setup.js @@ -34,18 +34,6 @@ Vue.config.productionTip = false; Vue.use(Translate); -// workaround for JSDOM not supporting innerText -// see https://github.com/jsdom/jsdom/issues/1245 -Object.defineProperty(global.Element.prototype, 'innerText', { - get() { - return this.textContent; - }, - set(value) { - this.textContext = value; - }, - configurable: true, // make it so that it doesn't blow chunks on re-running tests with things like --watch -}); - // convenience wrapper for migration from Karma Object.assign(global, { getJSONFixture, diff --git a/spec/graphql/mutations/concerns/mutations/resolves_group_spec.rb b/spec/graphql/mutations/concerns/mutations/resolves_group_spec.rb index 897b8f4e9ef..fcc717f83a2 100644 --- a/spec/graphql/mutations/concerns/mutations/resolves_group_spec.rb +++ b/spec/graphql/mutations/concerns/mutations/resolves_group_spec.rb @@ -10,6 +10,7 @@ describe Mutations::ResolvesGroup do end let(:context) { double } + subject(:mutation) { mutation_class.new(object: nil, context: context) } it 'uses the GroupsResolver to resolve groups by path' do diff --git a/spec/graphql/mutations/concerns/mutations/resolves_project_spec.rb b/spec/graphql/mutations/concerns/mutations/resolves_project_spec.rb index 09d1f66a2c7..918e5fb016e 100644 --- a/spec/graphql/mutations/concerns/mutations/resolves_project_spec.rb +++ b/spec/graphql/mutations/concerns/mutations/resolves_project_spec.rb @@ -10,6 +10,7 @@ describe Mutations::ResolvesProject do end let(:context) { double } + subject(:mutation) { mutation_class.new(object: nil, context: context) } it 'uses the ProjectsResolver to resolve projects by path' do diff --git a/spec/graphql/mutations/issues/set_confidential_spec.rb b/spec/graphql/mutations/issues/set_confidential_spec.rb index 05b787eb5ca..a8f1fcdf7f1 100644 --- a/spec/graphql/mutations/issues/set_confidential_spec.rb +++ b/spec/graphql/mutations/issues/set_confidential_spec.rb @@ -5,11 +5,13 @@ require 'spec_helper' describe Mutations::Issues::SetConfidential do let(:issue) { create(:issue) } let(:user) { create(:user) } + subject(:mutation) { described_class.new(object: nil, context: { current_user: user }) } describe '#resolve' do let(:confidential) { true } let(:mutated_issue) { subject[:issue] } + subject { mutation.resolve(project_path: issue.project.full_path, iid: issue.iid, confidential: confidential) } it 'raises an error if the resource is not accessible to the user' do diff --git a/spec/graphql/mutations/issues/set_due_date_spec.rb b/spec/graphql/mutations/issues/set_due_date_spec.rb index 9a1f0925fe3..b45a7b460cd 100644 --- a/spec/graphql/mutations/issues/set_due_date_spec.rb +++ b/spec/graphql/mutations/issues/set_due_date_spec.rb @@ -5,11 +5,13 @@ require 'spec_helper' describe Mutations::Issues::SetDueDate do let(:issue) { create(:issue) } let(:user) { create(:user) } + subject(:mutation) { described_class.new(object: nil, context: { current_user: user }) } describe '#resolve' do let(:due_date) { 2.days.since } let(:mutated_issue) { subject[:issue] } + subject { mutation.resolve(project_path: issue.project.full_path, iid: issue.iid, due_date: due_date) } it 'raises an error if the resource is not accessible to the user' do diff --git a/spec/graphql/mutations/merge_requests/set_assignees_spec.rb b/spec/graphql/mutations/merge_requests/set_assignees_spec.rb index e8da0e25b7d..2033ab57a0d 100644 --- a/spec/graphql/mutations/merge_requests/set_assignees_spec.rb +++ b/spec/graphql/mutations/merge_requests/set_assignees_spec.rb @@ -5,6 +5,7 @@ require 'spec_helper' describe Mutations::MergeRequests::SetAssignees do let(:merge_request) { create(:merge_request) } let(:user) { create(:user) } + subject(:mutation) { described_class.new(object: nil, context: { current_user: user }) } describe '#resolve' do @@ -12,6 +13,7 @@ describe Mutations::MergeRequests::SetAssignees do let(:assignee2) { create(:user) } let(:assignee_usernames) { [assignee.username] } let(:mutated_merge_request) { subject[:merge_request] } + subject { mutation.resolve(project_path: merge_request.project.full_path, iid: merge_request.iid, assignee_usernames: assignee_usernames) } before do diff --git a/spec/graphql/mutations/merge_requests/set_labels_spec.rb b/spec/graphql/mutations/merge_requests/set_labels_spec.rb index 3729251bab7..f7c04a57f68 100644 --- a/spec/graphql/mutations/merge_requests/set_labels_spec.rb +++ b/spec/graphql/mutations/merge_requests/set_labels_spec.rb @@ -5,6 +5,7 @@ require 'spec_helper' describe Mutations::MergeRequests::SetLabels do let(:merge_request) { create(:merge_request) } let(:user) { create(:user) } + subject(:mutation) { described_class.new(object: nil, context: { current_user: user }) } describe '#resolve' do @@ -12,6 +13,7 @@ describe Mutations::MergeRequests::SetLabels do let(:label2) { create(:label, project: merge_request.project) } let(:label_ids) { [label.to_global_id] } let(:mutated_merge_request) { subject[:merge_request] } + subject { mutation.resolve(project_path: merge_request.project.full_path, iid: merge_request.iid, label_ids: label_ids) } it 'raises an error if the resource is not accessible to the user' do diff --git a/spec/graphql/mutations/merge_requests/set_locked_spec.rb b/spec/graphql/mutations/merge_requests/set_locked_spec.rb index 51249854378..d35430abff1 100644 --- a/spec/graphql/mutations/merge_requests/set_locked_spec.rb +++ b/spec/graphql/mutations/merge_requests/set_locked_spec.rb @@ -5,11 +5,13 @@ require 'spec_helper' describe Mutations::MergeRequests::SetLocked do let(:merge_request) { create(:merge_request) } let(:user) { create(:user) } + subject(:mutation) { described_class.new(object: nil, context: { current_user: user }) } describe '#resolve' do let(:locked) { true } let(:mutated_merge_request) { subject[:merge_request] } + subject { mutation.resolve(project_path: merge_request.project.full_path, iid: merge_request.iid, locked: locked) } it 'raises an error if the resource is not accessible to the user' do diff --git a/spec/graphql/mutations/merge_requests/set_milestone_spec.rb b/spec/graphql/mutations/merge_requests/set_milestone_spec.rb index c2792a4bc25..d79b0a995d7 100644 --- a/spec/graphql/mutations/merge_requests/set_milestone_spec.rb +++ b/spec/graphql/mutations/merge_requests/set_milestone_spec.rb @@ -5,11 +5,13 @@ require 'spec_helper' describe Mutations::MergeRequests::SetMilestone do let(:merge_request) { create(:merge_request) } let(:user) { create(:user) } + subject(:mutation) { described_class.new(object: nil, context: { current_user: user }) } describe '#resolve' do let(:milestone) { create(:milestone, project: merge_request.project) } let(:mutated_merge_request) { subject[:merge_request] } + subject { mutation.resolve(project_path: merge_request.project.full_path, iid: merge_request.iid, milestone: milestone) } it 'raises an error if the resource is not accessible to the user' do diff --git a/spec/graphql/mutations/merge_requests/set_subscription_spec.rb b/spec/graphql/mutations/merge_requests/set_subscription_spec.rb index 116a77abcc0..286de6c0c97 100644 --- a/spec/graphql/mutations/merge_requests/set_subscription_spec.rb +++ b/spec/graphql/mutations/merge_requests/set_subscription_spec.rb @@ -6,11 +6,13 @@ describe Mutations::MergeRequests::SetSubscription do let(:merge_request) { create(:merge_request) } let(:project) { merge_request.project } let(:user) { create(:user) } + subject(:mutation) { described_class.new(object: nil, context: { current_user: user }) } describe '#resolve' do let(:subscribe) { true } let(:mutated_merge_request) { subject[:merge_request] } + subject { mutation.resolve(project_path: merge_request.project.full_path, iid: merge_request.iid, subscribed_state: subscribe) } it 'raises an error if the resource is not accessible to the user' do diff --git a/spec/graphql/mutations/merge_requests/set_wip_spec.rb b/spec/graphql/mutations/merge_requests/set_wip_spec.rb index c4accab9e46..490994c4577 100644 --- a/spec/graphql/mutations/merge_requests/set_wip_spec.rb +++ b/spec/graphql/mutations/merge_requests/set_wip_spec.rb @@ -5,11 +5,13 @@ require 'spec_helper' describe Mutations::MergeRequests::SetWip do let(:merge_request) { create(:merge_request) } let(:user) { create(:user) } + subject(:mutation) { described_class.new(object: nil, context: { current_user: user }) } describe '#resolve' do let(:wip) { true } let(:mutated_merge_request) { subject[:merge_request] } + subject { mutation.resolve(project_path: merge_request.project.full_path, iid: merge_request.iid, wip: wip) } it 'raises an error if the resource is not accessible to the user' do diff --git a/spec/graphql/resolvers/concerns/resolves_pipelines_spec.rb b/spec/graphql/resolvers/concerns/resolves_pipelines_spec.rb index fa031af4013..b59561ebdd4 100644 --- a/spec/graphql/resolvers/concerns/resolves_pipelines_spec.rb +++ b/spec/graphql/resolvers/concerns/resolves_pipelines_spec.rb @@ -16,6 +16,7 @@ describe ResolvesPipelines do end let(:current_user) { create(:user) } + set(:project) { create(:project, :private) } set(:pipeline) { create(:ci_pipeline, project: project) } set(:failed_pipeline) { create(:ci_pipeline, :failed, project: project) } diff --git a/spec/graphql/resolvers/error_tracking/sentry_detailed_error_resolver_spec.rb b/spec/graphql/resolvers/error_tracking/sentry_detailed_error_resolver_spec.rb index 5e7f18636ec..4490b54d1f7 100644 --- a/spec/graphql/resolvers/error_tracking/sentry_detailed_error_resolver_spec.rb +++ b/spec/graphql/resolvers/error_tracking/sentry_detailed_error_resolver_spec.rb @@ -20,6 +20,7 @@ describe Resolvers::ErrorTracking::SentryDetailedErrorResolver do describe '#resolve' do let(:args) { { id: issue_global_id(1234) } } + it 'fetches the data via the sentry API' do resolve_error(args) diff --git a/spec/graphql/types/permission_types/base_permission_type_spec.rb b/spec/graphql/types/permission_types/base_permission_type_spec.rb index a45102e5b50..aa6b4320006 100644 --- a/spec/graphql/types/permission_types/base_permission_type_spec.rb +++ b/spec/graphql/types/permission_types/base_permission_type_spec.rb @@ -6,6 +6,7 @@ describe Types::PermissionTypes::BasePermissionType do let(:permitable) { double('permittable') } let(:current_user) { build(:user) } let(:context) { { current_user: current_user } } + subject(:test_type) do Class.new(described_class) do graphql_name 'TestClass' diff --git a/spec/helpers/avatars_helper_spec.rb b/spec/helpers/avatars_helper_spec.rb index 77182a59c1c..8b6817efcc4 100644 --- a/spec/helpers/avatars_helper_spec.rb +++ b/spec/helpers/avatars_helper_spec.rb @@ -193,6 +193,7 @@ describe AvatarsHelper do describe '#user_avatar_without_link' do let(:options) { { user: user } } + subject { helper.user_avatar_without_link(options) } it 'displays user avatar' do diff --git a/spec/helpers/blob_helper_spec.rb b/spec/helpers/blob_helper_spec.rb index 4996e27c2e6..2d0c4723648 100644 --- a/spec/helpers/blob_helper_spec.rb +++ b/spec/helpers/blob_helper_spec.rb @@ -56,7 +56,7 @@ describe BlobHelper do stub_feature_flags(web_ide_default: false) link = helper.edit_blob_button(project, 'master', 'README.md') - expect(Capybara.string(link).find_link('Edit')[:href]).to eq("/#{project.full_path}/edit/master/README.md") + expect(Capybara.string(link).find_link('Edit')[:href]).to eq("/#{project.full_path}/-/edit/master/README.md") end it 'returns a link with a Web IDE route' do @@ -69,7 +69,7 @@ describe BlobHelper do stub_feature_flags(web_ide_default: false) link = helper.edit_blob_button(project, 'master', 'README.md', link_opts: { mr_id: 10 }) - expect(Capybara.string(link).find_link('Edit')[:href]).to eq("/#{project.full_path}/edit/master/README.md?mr_id=10") + expect(Capybara.string(link).find_link('Edit')[:href]).to eq("/#{project.full_path}/-/edit/master/README.md?mr_id=10") end end diff --git a/spec/helpers/events_helper_spec.rb b/spec/helpers/events_helper_spec.rb index 63a37a1f113..fa553710274 100644 --- a/spec/helpers/events_helper_spec.rb +++ b/spec/helpers/events_helper_spec.rb @@ -5,6 +5,7 @@ require 'spec_helper' describe EventsHelper do describe '#event_commit_title' do let(:message) { 'foo & bar ' + 'A' * 70 + '\n' + 'B' * 80 } + subject { helper.event_commit_title(message) } it 'returns the first line, truncated to 70 chars' do diff --git a/spec/helpers/groups_helper_spec.rb b/spec/helpers/groups_helper_spec.rb index 8b33277ea18..ac2f028f937 100644 --- a/spec/helpers/groups_helper_spec.rb +++ b/spec/helpers/groups_helper_spec.rb @@ -127,6 +127,7 @@ describe GroupsHelper do sub_sub_owner: sub_sub_owner } end + subject { helper.share_with_group_lock_help_text(sub_subgroup) } where(:root_share_with_group_locked, :subgroup_share_with_group_locked, :sub_subgroup_share_with_group_locked, :current_user, :help_text, :linked_ancestor) do @@ -194,6 +195,7 @@ describe GroupsHelper do describe '#group_container_registry_nav' do let(:group) { create(:group, :public) } let(:user) { create(:user) } + before do stub_container_registry_config(enabled: true) allow(helper).to receive(:current_user) { user } @@ -229,6 +231,7 @@ describe GroupsHelper do describe '#group_sidebar_links' do let(:group) { create(:group, :public) } let(:user) { create(:user) } + before do group.add_owner(user) allow(helper).to receive(:current_user) { user } diff --git a/spec/helpers/issuables_helper_spec.rb b/spec/helpers/issuables_helper_spec.rb index 9249c625135..a39110d0aa7 100644 --- a/spec/helpers/issuables_helper_spec.rb +++ b/spec/helpers/issuables_helper_spec.rb @@ -278,6 +278,7 @@ describe IssuablesHelper do describe '#assignee_sidebar_data' do let(:user) { create(:user) } let(:merge_request) { nil } + subject { helper.assignee_sidebar_data(user, merge_request: merge_request) } it 'returns hash of assignee data' do diff --git a/spec/helpers/labels_helper_spec.rb b/spec/helpers/labels_helper_spec.rb index e2dff05cfaa..7ad554fd618 100644 --- a/spec/helpers/labels_helper_spec.rb +++ b/spec/helpers/labels_helper_spec.rb @@ -274,6 +274,7 @@ describe LabelsHelper do describe '#label_status_tooltip' do let(:status) { 'unsubscribed'.inquiry } + subject { label_status_tooltip(label.present(issuable_subject: nil), status) } context 'with a project label' do diff --git a/spec/helpers/markup_helper_spec.rb b/spec/helpers/markup_helper_spec.rb index 5ca5f5703cf..6227a5f5662 100644 --- a/spec/helpers/markup_helper_spec.rb +++ b/spec/helpers/markup_helper_spec.rb @@ -44,6 +44,7 @@ describe MarkupHelper do describe "override default project" do let(:actual) { issue.to_reference } + set(:second_project) { create(:project, :public) } set(:second_issue) { create(:issue, project: second_project) } @@ -55,6 +56,7 @@ describe MarkupHelper do describe 'uploads' do let(:text) { "![ImageTest](/uploads/test.png)" } + set(:group) { create(:group) } subject { helper.markdown(text) } @@ -101,7 +103,7 @@ describe MarkupHelper do let(:requested_path) { 'files/images/README.md' } it 'returns the correct HTML for the image' do - expanded_path = "/#{project.full_path}/raw/master/files/images/#{image_file}" + expanded_path = "/#{project.full_path}/-/raw/master/files/images/#{image_file}" expect(subject.css('a')[0].attr('href')).to eq(expanded_path) expect(subject.css('img')[0].attr('data-src')).to eq(expanded_path) diff --git a/spec/helpers/merge_requests_helper_spec.rb b/spec/helpers/merge_requests_helper_spec.rb index 6bd567eab57..8db8c37038e 100644 --- a/spec/helpers/merge_requests_helper_spec.rb +++ b/spec/helpers/merge_requests_helper_spec.rb @@ -54,6 +54,7 @@ describe MergeRequestsHelper do describe '#format_mr_branch_names' do describe 'within the same project' do let(:merge_request) { create(:merge_request) } + subject { format_mr_branch_names(merge_request) } it { is_expected.to eq([merge_request.source_branch, merge_request.target_branch]) } diff --git a/spec/helpers/projects_helper_spec.rb b/spec/helpers/projects_helper_spec.rb index 0db54599ede..46228d0d1c2 100644 --- a/spec/helpers/projects_helper_spec.rb +++ b/spec/helpers/projects_helper_spec.rb @@ -313,6 +313,7 @@ describe ProjectsHelper do describe '#link_to_project' do let(:group) { create(:group, name: 'group name with space') } let(:project) { create(:project, group: group, name: 'project name with space') } + subject { link_to_project(project) } it 'returns an HTML link to the project' do @@ -544,6 +545,7 @@ describe ProjectsHelper do describe '#git_user_name' do let(:user) { double(:user, name: 'John "A" Doe53') } + before do allow(helper).to receive(:current_user).and_return(user) end @@ -566,6 +568,7 @@ describe ProjectsHelper do context 'user logged in' do let(:user) { create(:user) } + before do allow(helper).to receive(:current_user).and_return(user) end diff --git a/spec/helpers/submodule_helper_spec.rb b/spec/helpers/submodule_helper_spec.rb index fcfce0eaf31..9046c1e9fb4 100644 --- a/spec/helpers/submodule_helper_spec.rb +++ b/spec/helpers/submodule_helper_spec.rb @@ -95,7 +95,7 @@ describe SubmoduleHelper do allow(repo).to receive(:project).and_return(project) stub_url('./') - expect(subject).to eq(["/master-project/#{project.path}", "/master-project/#{project.path}/tree/hash"]) + expect(subject).to eq(["/master-project/#{project.path}", "/master-project/#{project.path}/-/tree/hash"]) end end @@ -166,7 +166,7 @@ describe SubmoduleHelper do allow(repo).to receive(:submodule_url_for).and_return(relative_path) result = subject - expect(result).to eq([expected_path, "#{expected_path}/tree/#{submodule_item.id}"]) + expect(result).to eq([expected_path, "#{expected_path}/-/tree/#{submodule_item.id}"]) end it 'handles project under same group' do diff --git a/spec/javascripts/diffs/components/app_spec.js b/spec/javascripts/diffs/components/app_spec.js index b21cab58b4e..48e1ed18a2f 100644 --- a/spec/javascripts/diffs/components/app_spec.js +++ b/spec/javascripts/diffs/components/app_spec.js @@ -92,16 +92,16 @@ describe('diffs/components/app', () => { }); }); - it('calls fetchDiffFiles if diffsBatchLoad is enabled, and not latest version', () => { + it('calls batch methods if diffsBatchLoad is enabled, and not latest version', () => { wrapper.vm.glFeatures.diffsBatchLoad = true; wrapper.vm.isLatestVersion = () => false; wrapper.vm.fetchData(false); - expect(wrapper.vm.fetchDiffFiles).toHaveBeenCalled(); + expect(wrapper.vm.fetchDiffFiles).not.toHaveBeenCalled(); wrapper.vm.$nextTick(() => { expect(wrapper.vm.startRenderDiffsQueue).toHaveBeenCalled(); - expect(wrapper.vm.fetchDiffFilesMeta).not.toHaveBeenCalled(); - expect(wrapper.vm.fetchDiffFilesBatch).not.toHaveBeenCalled(); + expect(wrapper.vm.fetchDiffFilesMeta).toHaveBeenCalled(); + expect(wrapper.vm.fetchDiffFilesBatch).toHaveBeenCalled(); }); }); diff --git a/spec/javascripts/diffs/store/actions_spec.js b/spec/javascripts/diffs/store/actions_spec.js index 589bd0e649a..b23334d38dc 100644 --- a/spec/javascripts/diffs/store/actions_spec.js +++ b/spec/javascripts/diffs/store/actions_spec.js @@ -147,13 +147,15 @@ describe('DiffsStoreActions', () => { describe('fetchDiffFilesBatch', () => { it('should fetch batch diff files', done => { const endpointBatch = '/fetch/diffs_batch'; - const batch1 = `${endpointBatch}?per_page=${DIFFS_PER_PAGE}`; - const batch2 = `${endpointBatch}?per_page=${DIFFS_PER_PAGE}&page=2`; const mock = new MockAdapter(axios); const res1 = { diff_files: [], pagination: { next_page: 2 } }; const res2 = { diff_files: [], pagination: {} }; - mock.onGet(batch1).reply(200, res1); - mock.onGet(batch2).reply(200, res2); + mock + .onGet(endpointBatch, { params: { page: undefined, per_page: DIFFS_PER_PAGE, w: '1' } }) + .reply(200, res1); + mock + .onGet(endpointBatch, { params: { page: 2, per_page: DIFFS_PER_PAGE, w: '1' } }) + .reply(200, res2); testAction( fetchDiffFilesBatch, diff --git a/spec/javascripts/vue_shared/components/diff_viewer/diff_viewer_spec.js b/spec/javascripts/vue_shared/components/diff_viewer/diff_viewer_spec.js index c743f1f6ad7..6a83790093a 100644 --- a/spec/javascripts/vue_shared/components/diff_viewer/diff_viewer_spec.js +++ b/spec/javascripts/vue_shared/components/diff_viewer/diff_viewer_spec.js @@ -38,11 +38,11 @@ describe('DiffViewer', () => { setTimeout(() => { expect(vm.$el.querySelector('.deleted img').getAttribute('src')).toBe( - `//raw/DEF/${RED_BOX_IMAGE_URL}`, + `//-/raw/DEF/${RED_BOX_IMAGE_URL}`, ); expect(vm.$el.querySelector('.added img').getAttribute('src')).toBe( - `//raw/ABC/${GREEN_BOX_IMAGE_URL}`, + `//-/raw/ABC/${GREEN_BOX_IMAGE_URL}`, ); done(); diff --git a/spec/lib/banzai/filter/relative_link_filter_spec.rb b/spec/lib/banzai/filter/relative_link_filter_spec.rb index 1efca647b8b..500df24ece8 100644 --- a/spec/lib/banzai/filter/relative_link_filter_spec.rb +++ b/spec/lib/banzai/filter/relative_link_filter_spec.rb @@ -153,7 +153,7 @@ describe Banzai::Filter::RelativeLinkFilter do it 'rebuilds absolute URL for a file in the repo' do doc = filter(link('/doc/api/README.md')) expect(doc.at_css('a')['href']) - .to eq "/#{project_path}/blob/#{ref}/doc/api/README.md" + .to eq "/#{project_path}/-/blob/#{ref}/doc/api/README.md" end it 'does not modify relative URLs in system notes' do @@ -171,13 +171,13 @@ describe Banzai::Filter::RelativeLinkFilter do it 'rebuilds relative URL for a file in the repo' do doc = filter(link('doc/api/README.md')) expect(doc.at_css('a')['href']) - .to eq "/#{project_path}/blob/#{ref}/doc/api/README.md" + .to eq "/#{project_path}/-/blob/#{ref}/doc/api/README.md" end it 'rebuilds relative URL for a file in the repo with leading ./' do doc = filter(link('./doc/api/README.md')) expect(doc.at_css('a')['href']) - .to eq "/#{project_path}/blob/#{ref}/doc/api/README.md" + .to eq "/#{project_path}/-/blob/#{ref}/doc/api/README.md" end it 'rebuilds relative URL for a file in the repo up one directory' do @@ -185,7 +185,7 @@ describe Banzai::Filter::RelativeLinkFilter do doc = filter(relative_link, requested_path: 'doc/update/7.14-to-8.0.md') expect(doc.at_css('a')['href']) - .to eq "/#{project_path}/blob/#{ref}/doc/api/README.md" + .to eq "/#{project_path}/-/blob/#{ref}/doc/api/README.md" end it 'rebuilds relative URL for a file in the repo up multiple directories' do @@ -193,7 +193,7 @@ describe Banzai::Filter::RelativeLinkFilter do doc = filter(relative_link, requested_path: 'doc/foo/bar/baz/README.md') expect(doc.at_css('a')['href']) - .to eq "/#{project_path}/blob/#{ref}/doc/api/README.md" + .to eq "/#{project_path}/-/blob/#{ref}/doc/api/README.md" end it 'rebuilds relative URL for a file in the repository root' do @@ -201,47 +201,47 @@ describe Banzai::Filter::RelativeLinkFilter do doc = filter(relative_link, requested_path: 'doc/some-file.md') expect(doc.at_css('a')['href']) - .to eq "/#{project_path}/blob/#{ref}/README.md" + .to eq "/#{project_path}/-/blob/#{ref}/README.md" end it 'rebuilds relative URL for a file in the repo with an anchor' do doc = filter(link('README.md#section')) expect(doc.at_css('a')['href']) - .to eq "/#{project_path}/blob/#{ref}/README.md#section" + .to eq "/#{project_path}/-/blob/#{ref}/README.md#section" end it 'rebuilds relative URL for a directory in the repo' do doc = filter(link('doc/api/')) expect(doc.at_css('a')['href']) - .to eq "/#{project_path}/tree/#{ref}/doc/api" + .to eq "/#{project_path}/-/tree/#{ref}/doc/api" end it 'rebuilds relative URL for an image in the repo' do doc = filter(image('files/images/logo-black.png')) expect(doc.at_css('img')['src']) - .to eq "/#{project_path}/raw/#{ref}/files/images/logo-black.png" + .to eq "/#{project_path}/-/raw/#{ref}/files/images/logo-black.png" end it 'rebuilds relative URL for link to an image in the repo' do doc = filter(link('files/images/logo-black.png')) expect(doc.at_css('a')['href']) - .to eq "/#{project_path}/raw/#{ref}/files/images/logo-black.png" + .to eq "/#{project_path}/-/raw/#{ref}/files/images/logo-black.png" end it 'rebuilds relative URL for a video in the repo' do doc = filter(video('files/videos/intro.mp4'), commit: project.commit('video'), ref: 'video') expect(doc.at_css('video')['src']) - .to eq "/#{project_path}/raw/video/files/videos/intro.mp4" + .to eq "/#{project_path}/-/raw/video/files/videos/intro.mp4" end it 'rebuilds relative URL for audio in the repo' do doc = filter(audio('files/audio/sample.wav'), commit: project.commit('audio'), ref: 'audio') expect(doc.at_css('audio')['src']) - .to eq "/#{project_path}/raw/audio/files/audio/sample.wav" + .to eq "/#{project_path}/-/raw/audio/files/audio/sample.wav" end it 'does not modify relative URL with an anchor only' do @@ -268,7 +268,7 @@ describe Banzai::Filter::RelativeLinkFilter do allow_any_instance_of(described_class).to receive(:uri_type).and_return(:raw) doc = filter(image(escaped)) - expect(doc.at_css('img')['src']).to eq "/#{project_path}/raw/#{Addressable::URI.escape(ref)}/#{escaped}" + expect(doc.at_css('img')['src']).to eq "/#{project_path}/-/raw/#{Addressable::URI.escape(ref)}/#{escaped}" end context 'when requested path is a file in the repo' do @@ -276,7 +276,7 @@ describe Banzai::Filter::RelativeLinkFilter do it 'rebuilds URL relative to the containing directory' do doc = filter(link('users.md')) - expect(doc.at_css('a')['href']).to eq "/#{project_path}/blob/#{Addressable::URI.escape(ref)}/doc/api/users.md" + expect(doc.at_css('a')['href']).to eq "/#{project_path}/-/blob/#{Addressable::URI.escape(ref)}/doc/api/users.md" end end @@ -285,7 +285,7 @@ describe Banzai::Filter::RelativeLinkFilter do it 'rebuilds URL relative to the directory' do doc = filter(link('users.md')) - expect(doc.at_css('a')['href']).to eq "/#{project_path}/blob/#{Addressable::URI.escape(ref)}/doc/api/users.md" + expect(doc.at_css('a')['href']).to eq "/#{project_path}/-/blob/#{Addressable::URI.escape(ref)}/doc/api/users.md" end end @@ -296,7 +296,7 @@ describe Banzai::Filter::RelativeLinkFilter do it 'correctly escapes the ref' do doc = filter(link('.gitkeep')) - expect(doc.at_css('a')['href']).to eq "/#{project_path}/blob/#{Addressable::URI.escape(ref)}/foo/bar/.gitkeep" + expect(doc.at_css('a')['href']).to eq "/#{project_path}/-/blob/#{Addressable::URI.escape(ref)}/foo/bar/.gitkeep" end end @@ -315,7 +315,7 @@ describe Banzai::Filter::RelativeLinkFilter do doc = filter(link(path)) expect(doc.at_css('a')['href']) - .to eq "/#{project_path}/raw/#{ref_escaped}/files/images/logo-black.png" + .to eq "/#{project_path}/-/raw/#{ref_escaped}/files/images/logo-black.png" end end @@ -326,7 +326,7 @@ describe Banzai::Filter::RelativeLinkFilter do it 'does not escape the space twice' do doc = filter(link('README.md')) - expect(doc.at_css('a')['href']).to eq "/#{project_path}/blob/#{Addressable::URI.escape(ref)}/with%20space/README.md" + expect(doc.at_css('a')['href']).to eq "/#{project_path}/-/blob/#{Addressable::URI.escape(ref)}/with%20space/README.md" end end end diff --git a/spec/lib/gitlab/conflict/file_spec.rb b/spec/lib/gitlab/conflict/file_spec.rb index adf5a232a75..7ecc42ea497 100644 --- a/spec/lib/gitlab/conflict/file_spec.rb +++ b/spec/lib/gitlab/conflict/file_spec.rb @@ -258,7 +258,7 @@ FILE describe '#as_json' do it 'includes the blob path for the file' do expect(conflict_file.as_json[:blob_path]) - .to eq("/#{project.full_path}/blob/#{our_commit.oid}/files/ruby/regex.rb") + .to eq("/#{project.full_path}/-/blob/#{our_commit.oid}/files/ruby/regex.rb") end it 'includes the blob icon for the file' do diff --git a/spec/lib/gitlab/database_spec.rb b/spec/lib/gitlab/database_spec.rb index a033316a6d9..3db8900ed8e 100644 --- a/spec/lib/gitlab/database_spec.rb +++ b/spec/lib/gitlab/database_spec.rb @@ -324,6 +324,7 @@ describe Gitlab::Database do context 'with version < 9.5' do let(:version) { 9.4 } + it 'refuses setting the upsert' do expect(connection) .not_to receive(:execute) diff --git a/spec/lib/gitlab/dependency_linker/godeps_json_linker_spec.rb b/spec/lib/gitlab/dependency_linker/godeps_json_linker_spec.rb index 9f8542a76c9..7128689e362 100644 --- a/spec/lib/gitlab/dependency_linker/godeps_json_linker_spec.rb +++ b/spec/lib/gitlab/dependency_linker/godeps_json_linker_spec.rb @@ -75,8 +75,8 @@ describe Gitlab::DependencyLinker::GodepsJsonLinker do end it 'links GitLab projects' do - expect(subject).to include(link('gitlab.com/group/project/path', 'https://gitlab.com/group/project/tree/master/path')) - expect(subject).to include(link('gitlab.com/group/subgroup/project.git/path', 'https://gitlab.com/group/subgroup/project/tree/master/path')) + expect(subject).to include(link('gitlab.com/group/project/path', 'https://gitlab.com/group/project/-/tree/master/path')) + expect(subject).to include(link('gitlab.com/group/subgroup/project.git/path', 'https://gitlab.com/group/subgroup/project/-/tree/master/path')) end it 'links Golang packages' do diff --git a/spec/lib/gitlab/middleware/go_spec.rb b/spec/lib/gitlab/middleware/go_spec.rb index 2b90035d148..99c2a364dfc 100644 --- a/spec/lib/gitlab/middleware/go_spec.rb +++ b/spec/lib/gitlab/middleware/go_spec.rb @@ -241,7 +241,7 @@ describe Gitlab::Middleware::Go do project_url = "http://#{Gitlab.config.gitlab.host}/#{path}" expect(response[0]).to eq(200) expect(response[1]['Content-Type']).to eq('text/html') - expected_body = %{<html><head><meta name="go-import" content="#{Gitlab.config.gitlab.host}/#{path} git #{repository_url}" /><meta name="go-source" content="#{Gitlab.config.gitlab.host}/#{path} #{project_url} #{project_url}/tree/#{branch}{/dir} #{project_url}/blob/#{branch}{/dir}/{file}#L{line}" /></head><body>go get #{Gitlab.config.gitlab.url}/#{path}</body></html>} + expected_body = %{<html><head><meta name="go-import" content="#{Gitlab.config.gitlab.host}/#{path} git #{repository_url}" /><meta name="go-source" content="#{Gitlab.config.gitlab.host}/#{path} #{project_url} #{project_url}/-/tree/#{branch}{/dir} #{project_url}/-/blob/#{branch}{/dir}/{file}#L{line}" /></head><body>go get #{Gitlab.config.gitlab.url}/#{path}</body></html>} expect(response[2].body).to eq([expected_body]) end end diff --git a/spec/lib/gitlab/prometheus/queries/knative_invocation_query_spec.rb b/spec/lib/gitlab/prometheus/queries/knative_invocation_query_spec.rb index 0936d895453..fa2dccc7c92 100644 --- a/spec/lib/gitlab/prometheus/queries/knative_invocation_query_spec.rb +++ b/spec/lib/gitlab/prometheus/queries/knative_invocation_query_spec.rb @@ -16,12 +16,12 @@ describe Gitlab::Prometheus::Queries::KnativeInvocationQuery do create(:prometheus_metric, :common, identifier: :system_metrics_knative_function_invocation_count, - query: 'sum(ceil(rate(istio_requests_total{destination_service_namespace="%{kube_namespace}", destination_app=~"%{function_name}.*"}[1m])*60))') + query: 'sum(ceil(rate(istio_requests_total{destination_service_namespace="%{kube_namespace}", destination_service=~"%{function_name}.*"}[1m])*60))') end it 'has the query, but no data' do expect(client).to receive(:query_range).with( - 'sum(ceil(rate(istio_requests_total{destination_service_namespace="test-ns", destination_app=~"test-name.*"}[1m])*60))', + 'sum(ceil(rate(istio_requests_total{destination_service_namespace="test-ns", destination_service=~"test-name.*"}[1m])*60))', hash_including(:start, :stop) ) diff --git a/spec/lib/quality/test_level_spec.rb b/spec/lib/quality/test_level_spec.rb index c85994402dd..13817bdcc72 100644 --- a/spec/lib/quality/test_level_spec.rb +++ b/spec/lib/quality/test_level_spec.rb @@ -21,7 +21,7 @@ RSpec.describe Quality::TestLevel do context 'when level is unit' do it 'returns a pattern' do expect(subject.pattern(:unit)) - .to eq("spec/{bin,config,db,dependencies,factories,finders,frontend,graphql,haml_lint,helpers,initializers,javascripts,lib,migrations,models,policies,presenters,rack_servers,routing,rubocop,serializers,services,sidekiq,tasks,uploaders,validators,views,workers,elastic_integration}{,/**/}*_spec.rb") + .to eq("spec/{bin,config,db,dependencies,factories,finders,frontend,graphql,haml_lint,helpers,initializers,javascripts,lib,models,policies,presenters,rack_servers,routing,rubocop,serializers,services,sidekiq,tasks,uploaders,validators,views,workers,elastic_integration}{,/**/}*_spec.rb") end end @@ -82,7 +82,7 @@ RSpec.describe Quality::TestLevel do context 'when level is unit' do it 'returns a regexp' do expect(subject.regexp(:unit)) - .to eq(%r{spec/(bin|config|db|dependencies|factories|finders|frontend|graphql|haml_lint|helpers|initializers|javascripts|lib|migrations|models|policies|presenters|rack_servers|routing|rubocop|serializers|services|sidekiq|tasks|uploaders|validators|views|workers|elastic_integration)}) + .to eq(%r{spec/(bin|config|db|dependencies|factories|finders|frontend|graphql|haml_lint|helpers|initializers|javascripts|lib|models|policies|presenters|rack_servers|routing|rubocop|serializers|services|sidekiq|tasks|uploaders|validators|views|workers|elastic_integration)}) end end diff --git a/spec/mailers/notify_spec.rb b/spec/mailers/notify_spec.rb index ad256c10964..e4a7d62eb02 100644 --- a/spec/mailers/notify_spec.rb +++ b/spec/mailers/notify_spec.rb @@ -109,6 +109,7 @@ describe Notify do describe 'that are reassigned' do let(:previous_assignee) { create(:user, name: 'Previous Assignee') } + subject { described_class.reassigned_issue_email(recipient.id, issue.id, [previous_assignee.id], current_user.id) } it_behaves_like 'a multiple recipients email' @@ -207,6 +208,7 @@ describe Notify do describe 'status changed' do let(:status) { 'closed' } + subject { described_class.issue_status_changed_email(recipient.id, issue.id, status, current_user.id) } it_behaves_like 'an answer to an existing thread with reply-by-email enabled' do @@ -235,6 +237,7 @@ describe Notify do describe 'moved to another project' do let(:new_issue) { create(:issue) } + subject { described_class.issue_moved_email(recipient, issue, new_issue, current_user) } context 'when a user has permissions to access the new issue' do @@ -334,6 +337,7 @@ describe Notify do describe 'that are reassigned' do let(:previous_assignee) { create(:user, name: 'Previous Assignee') } + subject { described_class.reassigned_merge_request_email(recipient.id, merge_request.id, [previous_assignee.id], current_user.id) } it_behaves_like 'a multiple recipients email' @@ -426,6 +430,7 @@ describe Notify do describe 'status changed' do let(:status) { 'reopened' } + subject { described_class.merge_request_status_email(recipient.id, merge_request.id, status, current_user.id) } it_behaves_like 'an answer to an existing thread with reply-by-email enabled' do @@ -454,6 +459,7 @@ describe Notify do describe 'that are merged' do let(:merge_author) { create(:user) } + subject { described_class.merged_merge_request_email(recipient.id, merge_request.id, merge_author.id) } it_behaves_like 'a multiple recipients email' @@ -698,6 +704,7 @@ describe Notify do describe 'project was moved' do let(:recipient) { user } + subject { described_class.project_was_moved_email(project.id, user.id, "gitlab/gitlab") } it_behaves_like 'an email sent to a user' @@ -725,6 +732,7 @@ describe Notify do project.request_access(user) project.requesters.find_by(user_id: user.id) end + subject { described_class.member_access_requested_email('project', project_member.id, recipient.id) } it_behaves_like 'an email sent from GitLab' @@ -750,6 +758,7 @@ describe Notify do project.request_access(user) project.requesters.find_by(user_id: user.id) end + subject { described_class.member_access_denied_email('project', project.id, user.id) } it_behaves_like 'an email sent from GitLab' @@ -769,6 +778,7 @@ describe Notify do let(:owner) { create(:user, name: "Chang O'Keefe") } let(:project) { create(:project, :public, namespace: owner.namespace) } let(:project_member) { create(:project_member, project: project, user: user) } + subject { described_class.member_access_granted_email('project', project_member.id) } it_behaves_like 'an email sent from GitLab' @@ -1190,6 +1200,7 @@ describe Notify do group.request_access(user) group.requesters.find_by(user_id: user.id) end + subject { described_class.member_access_requested_email('group', group_member.id, recipient.id) } it_behaves_like 'an email sent from GitLab' @@ -1216,6 +1227,7 @@ describe Notify do group.requesters.find_by(user_id: user.id) end let(:recipient) { user } + subject { described_class.member_access_denied_email('group', group.id, user.id) } it_behaves_like 'an email sent from GitLab' diff --git a/spec/models/clusters/applications/knative_spec.rb b/spec/models/clusters/applications/knative_spec.rb index 5b45dc078de..c1057af5f80 100644 --- a/spec/models/clusters/applications/knative_spec.rb +++ b/spec/models/clusters/applications/knative_spec.rb @@ -123,7 +123,7 @@ describe Clusters::Applications::Knative do subject { knative.install_command } it 'is initialized with latest version' do - expect(subject.version).to eq('0.7.0') + expect(subject.version).to eq('0.9.0') end it_behaves_like 'a command' diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb index 99d7e4d156f..7170003857e 100644 --- a/spec/models/project_spec.rb +++ b/spec/models/project_spec.rb @@ -697,7 +697,7 @@ describe Project do let(:project) { create(:project, :repository) } it 'returns the README' do - expect(project.readme_url).to eq("#{project.web_url}/blob/master/README.md") + expect(project.readme_url).to eq("#{project.web_url}/-/blob/master/README.md") end end end diff --git a/spec/policies/project_policy_spec.rb b/spec/policies/project_policy_spec.rb index 7465a616a83..188eafadfc1 100644 --- a/spec/policies/project_policy_spec.rb +++ b/spec/policies/project_policy_spec.rb @@ -307,6 +307,7 @@ describe ProjectPolicy do context 'for a guest in a private project' do let(:project) { create(:project, :private) } + subject { described_class.new(guest, project) } it 'disallows the guest from reading the merge request and merge request iid' do @@ -320,6 +321,7 @@ describe ProjectPolicy do describe 'for unconfirmed user' do let(:unconfirmed_user) { create(:user, confirmed_at: nil) } + subject { described_class.new(unconfirmed_user, project) } it 'disallows to modify pipelines' do diff --git a/spec/presenters/blob_presenter_spec.rb b/spec/presenters/blob_presenter_spec.rb index 8680e8b9b45..ee7bfd1256d 100644 --- a/spec/presenters/blob_presenter_spec.rb +++ b/spec/presenters/blob_presenter_spec.rb @@ -21,7 +21,7 @@ describe BlobPresenter, :seed_helper do subject { described_class.new(blob) } - it { expect(subject.web_url).to eq("http://localhost/#{project.full_path}/blob/#{blob.commit_id}/#{blob.path}") } + it { expect(subject.web_url).to eq("http://localhost/#{project.full_path}/-/blob/#{blob.commit_id}/#{blob.path}") } end describe '#highlight' do diff --git a/spec/presenters/label_presenter_spec.rb b/spec/presenters/label_presenter_spec.rb index d566da7c872..e9f9657490d 100644 --- a/spec/presenters/label_presenter_spec.rb +++ b/spec/presenters/label_presenter_spec.rb @@ -41,6 +41,7 @@ describe LabelPresenter do describe '#filter_path' do context 'with group as context subject' do let(:label_in_group) { build_stubbed(:label, project: project).present(issuable_subject: group) } + subject { label_in_group.filter_path } it { is_expected.to eq(issues_group_path(group, label_name: [label_in_group.title])) } diff --git a/spec/presenters/merge_request_presenter_spec.rb b/spec/presenters/merge_request_presenter_spec.rb index 6ce6f84cf61..025f083ab27 100644 --- a/spec/presenters/merge_request_presenter_spec.rb +++ b/spec/presenters/merge_request_presenter_spec.rb @@ -334,7 +334,7 @@ describe MergeRequestPresenter do allow(resource).to receive(:target_branch_exists?) { true } is_expected - .to eq("/#{resource.target_project.full_path}/commits/#{resource.target_branch}") + .to eq("/#{resource.target_project.full_path}/-/commits/#{resource.target_branch}") end end @@ -358,7 +358,7 @@ describe MergeRequestPresenter do allow(resource).to receive(:source_branch_exists?) { true } is_expected - .to eq("/#{resource.source_project.full_path}/commits/#{resource.source_branch}") + .to eq("/#{resource.source_project.full_path}/-/commits/#{resource.source_branch}") end end @@ -382,7 +382,7 @@ describe MergeRequestPresenter do allow(resource).to receive(:target_branch_exists?) { true } is_expected - .to eq("/#{resource.target_project.full_path}/tree/#{resource.target_branch}") + .to eq("/#{resource.target_project.full_path}/-/tree/#{resource.target_branch}") end end @@ -496,7 +496,7 @@ describe MergeRequestPresenter do allow(resource).to receive(:source_branch_exists?) { true } is_expected - .to eq("<a href=\"/#{resource.source_project.full_path}/tree/#{resource.source_branch}\">#{resource.source_branch}</a>") + .to eq("<a href=\"/#{resource.source_project.full_path}/-/tree/#{resource.source_branch}\">#{resource.source_branch}</a>") end it 'escapes html, when source_branch does not exist' do diff --git a/spec/presenters/project_presenter_spec.rb b/spec/presenters/project_presenter_spec.rb index ce095d2225f..318024bacd6 100644 --- a/spec/presenters/project_presenter_spec.rb +++ b/spec/presenters/project_presenter_spec.rb @@ -436,6 +436,7 @@ describe ProjectPresenter do describe '#repo_statistics_buttons' do let(:presenter) { described_class.new(project, current_user: user) } + subject(:empty_repo_statistics_buttons) { presenter.empty_repo_statistics_buttons } before do diff --git a/spec/presenters/tree_entry_presenter_spec.rb b/spec/presenters/tree_entry_presenter_spec.rb index d74ee5dc28f..0c29fe3e5ff 100644 --- a/spec/presenters/tree_entry_presenter_spec.rb +++ b/spec/presenters/tree_entry_presenter_spec.rb @@ -11,6 +11,6 @@ describe TreeEntryPresenter do let(:presenter) { described_class.new(tree) } describe '.web_url' do - it { expect(presenter.web_url).to eq("http://localhost/#{project.full_path}/tree/#{tree.commit_id}/#{tree.path}") } + it { expect(presenter.web_url).to eq("http://localhost/#{project.full_path}/-/tree/#{tree.commit_id}/#{tree.path}") } end end diff --git a/spec/requests/api/award_emoji_spec.rb b/spec/requests/api/award_emoji_spec.rb index 80040cddd4d..19a34314bb8 100644 --- a/spec/requests/api/award_emoji_spec.rb +++ b/spec/requests/api/award_emoji_spec.rb @@ -9,6 +9,7 @@ describe API::AwardEmoji do set(:award_emoji) { create(:award_emoji, awardable: issue, user: user) } let!(:merge_request) { create(:merge_request, source_project: project, target_project: project) } let!(:downvote) { create(:award_emoji, :downvote, awardable: merge_request, user: user) } + set(:note) { create(:note, project: project, noteable: issue) } before do diff --git a/spec/requests/api/boards_spec.rb b/spec/requests/api/boards_spec.rb index 8a67e956165..510ef9d7d0a 100644 --- a/spec/requests/api/boards_spec.rb +++ b/spec/requests/api/boards_spec.rb @@ -69,6 +69,7 @@ describe API::Boards do set(:group) { create(:group) } set(:board_parent) { create(:group, parent: group ) } let(:url) { "/groups/#{board_parent.id}/boards/#{board.id}/lists" } + set(:board) { create(:board, group: board_parent) } it 'creates a new board list for ancestor group labels' do diff --git a/spec/requests/api/graphql/mutations/award_emojis/add_spec.rb b/spec/requests/api/graphql/mutations/award_emojis/add_spec.rb index 5b910d5bfe0..b24981873c8 100644 --- a/spec/requests/api/graphql/mutations/award_emojis/add_spec.rb +++ b/spec/requests/api/graphql/mutations/award_emojis/add_spec.rb @@ -75,6 +75,7 @@ describe 'Adding an AwardEmoji' do describe 'marking Todos as done' do let(:user) { current_user} + subject { post_graphql_mutation(mutation, current_user: user) } include_examples 'creating award emojis marks Todos as done' diff --git a/spec/requests/api/graphql/mutations/award_emojis/toggle_spec.rb b/spec/requests/api/graphql/mutations/award_emojis/toggle_spec.rb index ae628d3e56c..5e2c0e668a5 100644 --- a/spec/requests/api/graphql/mutations/award_emojis/toggle_spec.rb +++ b/spec/requests/api/graphql/mutations/award_emojis/toggle_spec.rb @@ -83,6 +83,7 @@ describe 'Toggling an AwardEmoji' do describe 'marking Todos as done' do let(:user) { current_user} + subject { post_graphql_mutation(mutation, current_user: user) } include_examples 'creating award emojis marks Todos as done' diff --git a/spec/requests/api/project_import_spec.rb b/spec/requests/api/project_import_spec.rb index 866adbd424e..186f0f52a46 100644 --- a/spec/requests/api/project_import_spec.rb +++ b/spec/requests/api/project_import_spec.rb @@ -7,6 +7,7 @@ describe API::ProjectImport do let(:user) { create(:user) } let(:file) { File.join('spec', 'features', 'projects', 'import_export', 'test_project_export.tar.gz') } let(:namespace) { create(:group) } + before do allow_any_instance_of(Gitlab::ImportExport).to receive(:storage_path).and_return(export_path) stub_uploads_object_storage(FileUploader) diff --git a/spec/requests/api/projects_spec.rb b/spec/requests/api/projects_spec.rb index cda2dd7d2f4..eb3d5e698d8 100644 --- a/spec/requests/api/projects_spec.rb +++ b/spec/requests/api/projects_spec.rb @@ -715,7 +715,7 @@ describe API::Projects do post api('/projects', user), params: project - expect(json_response['readme_url']).to eql("#{Gitlab.config.gitlab.url}/#{json_response['namespace']['full_path']}/somewhere/blob/master/README.md") + expect(json_response['readme_url']).to eql("#{Gitlab.config.gitlab.url}/#{json_response['namespace']['full_path']}/somewhere/-/blob/master/README.md") end it 'sets tag list to a project' do @@ -1882,6 +1882,7 @@ describe API::Projects do describe "POST /projects/:id/share" do let(:group) { create(:group) } + before do group.add_developer(user) end diff --git a/spec/requests/api/settings_spec.rb b/spec/requests/api/settings_spec.rb index 6599e4b8f23..af86ba86303 100644 --- a/spec/requests/api/settings_spec.rb +++ b/spec/requests/api/settings_spec.rb @@ -4,6 +4,7 @@ require 'spec_helper' describe API::Settings, 'Settings' do let(:user) { create(:user) } + set(:admin) { create(:admin) } describe "GET /application/settings" do diff --git a/spec/requests/api/snippets_spec.rb b/spec/requests/api/snippets_spec.rb index eb9d0d38bcb..f32be7a8765 100644 --- a/spec/requests/api/snippets_spec.rb +++ b/spec/requests/api/snippets_spec.rb @@ -375,6 +375,7 @@ describe API::Snippets do describe 'DELETE /snippets/:id' do let!(:public_snippet) { create(:personal_snippet, :public, author: user) } + it 'deletes snippet' do expect do delete api("/snippets/#{public_snippet.id}", user) diff --git a/spec/requests/api/users_spec.rb b/spec/requests/api/users_spec.rb index 29088a42fbe..0a22a09b8a6 100644 --- a/spec/requests/api/users_spec.rb +++ b/spec/requests/api/users_spec.rb @@ -2124,6 +2124,7 @@ describe API::Users do describe 'GET /user/status' do let(:path) { '/user/status' } + it_behaves_like 'rendering user status' end diff --git a/spec/requests/git_http_spec.rb b/spec/requests/git_http_spec.rb index 42b4bd71b88..7424b7ee8d0 100644 --- a/spec/requests/git_http_spec.rb +++ b/spec/requests/git_http_spec.rb @@ -834,7 +834,7 @@ describe 'Git HTTP requests' do Blob.decorate(Gitlab::Git::Blob.find(project.repository, 'master', 'bar/branch-test.txt'), project) end - get "/#{project.full_path}/blob/master/info/refs" + get "/#{project.full_path}/-/blob/master/info/refs" end it "returns the file" do @@ -844,7 +844,7 @@ describe 'Git HTTP requests' do context "when the file does not exist" do before do - get "/#{project.full_path}/blob/master/info/refs" + get "/#{project.full_path}/-/blob/master/info/refs" end it "redirects" do diff --git a/spec/routing/project_routing_spec.rb b/spec/routing/project_routing_spec.rb index 96956d85de4..7816b77d14c 100644 --- a/spec/routing/project_routing_spec.rb +++ b/spec/routing/project_routing_spec.rb @@ -454,11 +454,14 @@ describe 'project routing' do it_behaves_like 'RESTful project resources' do let(:actions) { [:show] } let(:controller) { 'commits' } + let(:controller_path) { '/-/commits' } end it 'to #show' do - expect(get('/gitlab/gitlabhq/commits/master.atom')).to route_to('projects/commits#show', namespace_id: 'gitlab', project_id: 'gitlabhq', id: 'master.atom') + expect(get('/gitlab/gitlabhq/-/commits/master.atom')).to route_to('projects/commits#show', namespace_id: 'gitlab', project_id: 'gitlabhq', id: 'master.atom') end + + it_behaves_like 'redirecting a legacy project path', "/gitlab/gitlabhq/commits/master.atom", "/gitlab/gitlabhq/-/commits/master.atom" end # project_project_members GET /:project_id/project_members(.:format) project_members#index @@ -550,62 +553,68 @@ describe 'project routing' do # project_blame GET /:project_id/blame/:id(.:format) blame#show {id: /[^\0]+/, project_id: /[^\/]+/} describe Projects::BlameController, 'routing' do it 'to #show' do - expect(get('/gitlab/gitlabhq/blame/master/app/models/project.rb')).to route_to('projects/blame#show', namespace_id: 'gitlab', project_id: 'gitlabhq', id: 'master/app/models/project.rb') - expect(get('/gitlab/gitlabhq/blame/master/files.scss')).to route_to('projects/blame#show', namespace_id: 'gitlab', project_id: 'gitlabhq', id: 'master/files.scss') + expect(get('/gitlab/gitlabhq/-/blame/master/app/models/project.rb')).to route_to('projects/blame#show', namespace_id: 'gitlab', project_id: 'gitlabhq', id: 'master/app/models/project.rb') + expect(get('/gitlab/gitlabhq/-/blame/master/files.scss')).to route_to('projects/blame#show', namespace_id: 'gitlab', project_id: 'gitlabhq', id: 'master/files.scss') newline_file = "new\n\nline.txt" url_encoded_newline_file = ERB::Util.url_encode(newline_file) - assert_routing({ path: "/gitlab/gitlabhq/blame/master/#{url_encoded_newline_file}", + assert_routing({ path: "/gitlab/gitlabhq/-/blame/master/#{url_encoded_newline_file}", method: :get }, { controller: 'projects/blame', action: 'show', namespace_id: 'gitlab', project_id: 'gitlabhq', id: "master/#{newline_file}" }) end + + it_behaves_like 'redirecting a legacy project path', "/gitlab/gitlabhq/blame/master/readme.md", "/gitlab/gitlabhq/-/blame/master/readme.md" end # project_blob GET /:project_id/blob/:id(.:format) blob#show {id: /[^\0]+/, project_id: /[^\/]+/} describe Projects::BlobController, 'routing' do it 'to #show' do - expect(get('/gitlab/gitlabhq/blob/master/app/models/project.rb')).to route_to('projects/blob#show', namespace_id: 'gitlab', project_id: 'gitlabhq', id: 'master/app/models/project.rb') - expect(get('/gitlab/gitlabhq/blob/master/app/models/compare.rb')).to route_to('projects/blob#show', namespace_id: 'gitlab', project_id: 'gitlabhq', id: 'master/app/models/compare.rb') - expect(get('/gitlab/gitlabhq/blob/master/app/models/diff.js')).to route_to('projects/blob#show', namespace_id: 'gitlab', project_id: 'gitlabhq', id: 'master/app/models/diff.js') - expect(get('/gitlab/gitlabhq/blob/master/files.scss')).to route_to('projects/blob#show', namespace_id: 'gitlab', project_id: 'gitlabhq', id: 'master/files.scss') - expect(get('/gitlab/gitlabhq/blob/master/blob/index.js')).to route_to('projects/blob#show', namespace_id: 'gitlab', project_id: 'gitlabhq', id: 'master/blob/index.js') - expect(get('/gitlab/gitlabhq/blob/blob/master/blob/index.js')).to route_to('projects/blob#show', namespace_id: 'gitlab', project_id: 'gitlabhq', id: 'blob/master/blob/index.js') + expect(get('/gitlab/gitlabhq/-/blob/master/app/models/project.rb')).to route_to('projects/blob#show', namespace_id: 'gitlab', project_id: 'gitlabhq', id: 'master/app/models/project.rb') + expect(get('/gitlab/gitlabhq/-/blob/master/app/models/compare.rb')).to route_to('projects/blob#show', namespace_id: 'gitlab', project_id: 'gitlabhq', id: 'master/app/models/compare.rb') + expect(get('/gitlab/gitlabhq/-/blob/master/app/models/diff.js')).to route_to('projects/blob#show', namespace_id: 'gitlab', project_id: 'gitlabhq', id: 'master/app/models/diff.js') + expect(get('/gitlab/gitlabhq/-/blob/master/files.scss')).to route_to('projects/blob#show', namespace_id: 'gitlab', project_id: 'gitlabhq', id: 'master/files.scss') + expect(get('/gitlab/gitlabhq/-/blob/master/blob/index.js')).to route_to('projects/blob#show', namespace_id: 'gitlab', project_id: 'gitlabhq', id: 'master/blob/index.js') + expect(get('/gitlab/gitlabhq/-/blob/blob/master/blob/index.js')).to route_to('projects/blob#show', namespace_id: 'gitlab', project_id: 'gitlabhq', id: 'blob/master/blob/index.js') newline_file = "new\n\nline.txt" url_encoded_newline_file = ERB::Util.url_encode(newline_file) - assert_routing({ path: "/gitlab/gitlabhq/blob/blob/master/blob/#{url_encoded_newline_file}", + assert_routing({ path: "/gitlab/gitlabhq/-/blob/blob/master/blob/#{url_encoded_newline_file}", method: :get }, { controller: 'projects/blob', action: 'show', namespace_id: 'gitlab', project_id: 'gitlabhq', id: "blob/master/blob/#{newline_file}" }) end + + it_behaves_like 'redirecting a legacy project path', "/gitlab/gitlabhq/blob/master/readme.md", "/gitlab/gitlabhq/-/blob/master/readme.md" end # project_tree GET /:project_id/tree/:id(.:format) tree#show {id: /[^\0]+/, project_id: /[^\/]+/} describe Projects::TreeController, 'routing' do it 'to #show' do - expect(get('/gitlab/gitlabhq/tree/master/app/models/project.rb')).to route_to('projects/tree#show', namespace_id: 'gitlab', project_id: 'gitlabhq', id: 'master/app/models/project.rb') - expect(get('/gitlab/gitlabhq/tree/master/files.scss')).to route_to('projects/tree#show', namespace_id: 'gitlab', project_id: 'gitlabhq', id: 'master/files.scss') - expect(get('/gitlab/gitlabhq/tree/master/tree/files')).to route_to('projects/tree#show', namespace_id: 'gitlab', project_id: 'gitlabhq', id: 'master/tree/files') - expect(get('/gitlab/gitlabhq/tree/tree/master/tree/files')).to route_to('projects/tree#show', namespace_id: 'gitlab', project_id: 'gitlabhq', id: 'tree/master/tree/files') + expect(get('/gitlab/gitlabhq/-/tree/master/app/models/project.rb')).to route_to('projects/tree#show', namespace_id: 'gitlab', project_id: 'gitlabhq', id: 'master/app/models/project.rb') + expect(get('/gitlab/gitlabhq/-/tree/master/files.scss')).to route_to('projects/tree#show', namespace_id: 'gitlab', project_id: 'gitlabhq', id: 'master/files.scss') + expect(get('/gitlab/gitlabhq/-/tree/master/tree/files')).to route_to('projects/tree#show', namespace_id: 'gitlab', project_id: 'gitlabhq', id: 'master/tree/files') + expect(get('/gitlab/gitlabhq/-/tree/tree/master/tree/files')).to route_to('projects/tree#show', namespace_id: 'gitlab', project_id: 'gitlabhq', id: 'tree/master/tree/files') newline_file = "new\n\nline.txt" url_encoded_newline_file = ERB::Util.url_encode(newline_file) - assert_routing({ path: "/gitlab/gitlabhq/tree/master/#{url_encoded_newline_file}", + assert_routing({ path: "/gitlab/gitlabhq/-/tree/master/#{url_encoded_newline_file}", method: :get }, { controller: 'projects/tree', action: 'show', namespace_id: 'gitlab', project_id: 'gitlabhq', id: "master/#{newline_file}" }) end + + it_behaves_like 'redirecting a legacy project path', "/gitlab/gitlabhq/tree/master/app", "/gitlab/gitlabhq/-/tree/master/app" end # project_find_file GET /:namespace_id/:project_id/find_file/*id(.:format) projects/find_file#show {:id=>/[^\0]+/, :namespace_id=>/[a-zA-Z.0-9_\-]+/, :project_id=>/[a-zA-Z.0-9_\-]+(?<!\.atom)/, :format=>/html/} # project_files GET /:namespace_id/:project_id/files/*id(.:format) projects/find_file#list {:id=>/(?:[^.]|\.(?!json$))+/, :namespace_id=>/[a-zA-Z.0-9_\-]+/, :project_id=>/[a-zA-Z.0-9_\-]+(?<!\.atom)/, :format=>/json/} describe Projects::FindFileController, 'routing' do it 'to #show' do - expect(get('/gitlab/gitlabhq/find_file/master')).to route_to('projects/find_file#show', namespace_id: 'gitlab', project_id: 'gitlabhq', id: 'master') + expect(get('/gitlab/gitlabhq/-/find_file/master')).to route_to('projects/find_file#show', namespace_id: 'gitlab', project_id: 'gitlabhq', id: 'master') newline_file = "new\n\nline.txt" url_encoded_newline_file = ERB::Util.url_encode(newline_file) - assert_routing({ path: "/gitlab/gitlabhq/find_file/#{url_encoded_newline_file}", + assert_routing({ path: "/gitlab/gitlabhq/-/find_file/#{url_encoded_newline_file}", method: :get }, { controller: 'projects/find_file', action: 'show', namespace_id: 'gitlab', project_id: 'gitlabhq', @@ -613,26 +622,29 @@ describe 'project routing' do end it 'to #list' do - expect(get('/gitlab/gitlabhq/files/master.json')).to route_to('projects/find_file#list', namespace_id: 'gitlab', project_id: 'gitlabhq', id: 'master.json') + expect(get('/gitlab/gitlabhq/-/files/master.json')).to route_to('projects/find_file#list', namespace_id: 'gitlab', project_id: 'gitlabhq', id: 'master.json') newline_file = "new\n\nline.txt" url_encoded_newline_file = ERB::Util.url_encode(newline_file) - assert_routing({ path: "/gitlab/gitlabhq/files/#{url_encoded_newline_file}", + assert_routing({ path: "/gitlab/gitlabhq/-/files/#{url_encoded_newline_file}", method: :get }, { controller: 'projects/find_file', action: 'list', namespace_id: 'gitlab', project_id: 'gitlabhq', id: "#{newline_file}" }) end + + it_behaves_like 'redirecting a legacy project path', "/gitlab/gitlabhq/find_file/master", "/gitlab/gitlabhq/-/find_file/master" + it_behaves_like 'redirecting a legacy project path', "/gitlab/gitlabhq/files/master.json", "/gitlab/gitlabhq/-/files/master.json" end describe Projects::BlobController, 'routing' do it 'to #edit' do - expect(get('/gitlab/gitlabhq/edit/master/app/models/project.rb')).to( + expect(get('/gitlab/gitlabhq/-/edit/master/app/models/project.rb')).to( route_to('projects/blob#edit', namespace_id: 'gitlab', project_id: 'gitlabhq', id: 'master/app/models/project.rb')) newline_file = "new\n\nline.txt" url_encoded_newline_file = ERB::Util.url_encode(newline_file) - assert_routing({ path: "/gitlab/gitlabhq/edit/master/docs/#{url_encoded_newline_file}", + assert_routing({ path: "/gitlab/gitlabhq/-/edit/master/docs/#{url_encoded_newline_file}", method: :get }, { controller: 'projects/blob', action: 'edit', namespace_id: 'gitlab', project_id: 'gitlabhq', @@ -640,13 +652,13 @@ describe 'project routing' do end it 'to #preview' do - expect(post('/gitlab/gitlabhq/preview/master/app/models/project.rb')).to( + expect(post('/gitlab/gitlabhq/-/preview/master/app/models/project.rb')).to( route_to('projects/blob#preview', namespace_id: 'gitlab', project_id: 'gitlabhq', id: 'master/app/models/project.rb')) newline_file = "new\n\nline.txt" url_encoded_newline_file = ERB::Util.url_encode(newline_file) - assert_routing({ path: "/gitlab/gitlabhq/edit/master/docs/#{url_encoded_newline_file}", + assert_routing({ path: "/gitlab/gitlabhq/-/edit/master/docs/#{url_encoded_newline_file}", method: :get }, { controller: 'projects/blob', action: 'edit', namespace_id: 'gitlab', project_id: 'gitlabhq', @@ -659,12 +671,14 @@ describe 'project routing' do it 'to #show' do newline_file = "new\n\nline.txt" url_encoded_newline_file = ERB::Util.url_encode(newline_file) - assert_routing({ path: "/gitlab/gitlabhq/raw/master/#{url_encoded_newline_file}", + assert_routing({ path: "/gitlab/gitlabhq/-/raw/master/#{url_encoded_newline_file}", method: :get }, { controller: 'projects/raw', action: 'show', namespace_id: 'gitlab', project_id: 'gitlabhq', id: "master/#{newline_file}" }) end + + it_behaves_like 'redirecting a legacy project path', "/gitlab/gitlabhq/raw/master/app/models/project.rb", "/gitlab/gitlabhq/-/raw/master/app/models/project.rb" end # project_compare_index GET /:project_id/compare(.:format) compare#index {id: /[^\/]+/, project_id: /[^\/]+/} diff --git a/spec/serializers/blob_entity_spec.rb b/spec/serializers/blob_entity_spec.rb index 7e3a0a87bd5..3cd967ed44c 100644 --- a/spec/serializers/blob_entity_spec.rb +++ b/spec/serializers/blob_entity_spec.rb @@ -23,7 +23,7 @@ describe BlobEntity do mode: "100644", readable_text: true, icon: "file-text-o", - url: "/#{project.full_path}/blob/master/bar/branch-test.txt" + url: "/#{project.full_path}/-/blob/master/bar/branch-test.txt" }) end end diff --git a/spec/serializers/cluster_application_entity_spec.rb b/spec/serializers/cluster_application_entity_spec.rb index cb9325986d7..c700c150461 100644 --- a/spec/serializers/cluster_application_entity_spec.rb +++ b/spec/serializers/cluster_application_entity_spec.rb @@ -5,6 +5,7 @@ require 'spec_helper' describe ClusterApplicationEntity do describe '#as_json' do let(:application) { build(:clusters_applications_helm, version: '0.1.1') } + subject { described_class.new(application).as_json } it 'has name' do diff --git a/spec/serializers/cluster_entity_spec.rb b/spec/serializers/cluster_entity_spec.rb index 22b9166f922..e3826a7221d 100644 --- a/spec/serializers/cluster_entity_spec.rb +++ b/spec/serializers/cluster_entity_spec.rb @@ -39,6 +39,7 @@ describe ClusterEntity do context 'when no application has been installed' do let(:cluster) { create(:cluster) } + subject { described_class.new(cluster).as_json[:applications]} it 'contains helm as not_installable' do diff --git a/spec/serializers/environment_entity_spec.rb b/spec/serializers/environment_entity_spec.rb index e4d1d7f9049..f392ecea959 100644 --- a/spec/serializers/environment_entity_spec.rb +++ b/spec/serializers/environment_entity_spec.rb @@ -9,6 +9,7 @@ describe EnvironmentEntity do end let(:environment) { create(:environment) } + subject { entity.as_json } it 'exposes latest deployment' do diff --git a/spec/serializers/group_child_entity_spec.rb b/spec/serializers/group_child_entity_spec.rb index 198a55d5433..cae263e7fd5 100644 --- a/spec/serializers/group_child_entity_spec.rb +++ b/spec/serializers/group_child_entity_spec.rb @@ -9,6 +9,7 @@ describe GroupChildEntity do let(:user) { create(:user) } let(:request) { double('request') } let(:entity) { described_class.new(object, request: request) } + subject(:json) { entity.as_json } before do diff --git a/spec/serializers/group_child_serializer_spec.rb b/spec/serializers/group_child_serializer_spec.rb index 128e06cd172..92f083ed23e 100644 --- a/spec/serializers/group_child_serializer_spec.rb +++ b/spec/serializers/group_child_serializer_spec.rb @@ -5,6 +5,7 @@ require 'spec_helper' describe GroupChildSerializer do let(:request) { double('request') } let(:user) { create(:user) } + subject(:serializer) { described_class.new(current_user: user) } describe '#represent' do diff --git a/spec/serializers/merge_request_poll_widget_entity_spec.rb b/spec/serializers/merge_request_poll_widget_entity_spec.rb index ea9052b4046..0593dd527cc 100644 --- a/spec/serializers/merge_request_poll_widget_entity_spec.rb +++ b/spec/serializers/merge_request_poll_widget_entity_spec.rb @@ -60,7 +60,7 @@ describe MergeRequestPollWidgetEntity do project.add_developer(user) expect(subject[:new_blob_path]) - .to eq("/#{resource.project.full_path}/new/#{resource.source_branch}") + .to eq("/#{resource.project.full_path}/-/new/#{resource.source_branch}") end end diff --git a/spec/serializers/note_entity_spec.rb b/spec/serializers/note_entity_spec.rb index cec07cda063..f37fffb5048 100644 --- a/spec/serializers/note_entity_spec.rb +++ b/spec/serializers/note_entity_spec.rb @@ -10,6 +10,7 @@ describe NoteEntity do let(:entity) { described_class.new(note, request: request) } let(:note) { create(:note) } let(:user) { create(:user) } + subject { entity.as_json } it_behaves_like 'note entity' diff --git a/spec/serializers/project_note_entity_spec.rb b/spec/serializers/project_note_entity_spec.rb index 7c76f230781..469bf2b86de 100644 --- a/spec/serializers/project_note_entity_spec.rb +++ b/spec/serializers/project_note_entity_spec.rb @@ -10,6 +10,7 @@ describe ProjectNoteEntity do let(:entity) { described_class.new(note, request: request) } let(:note) { create(:note) } let(:user) { create(:user) } + subject { entity.as_json } it_behaves_like 'note entity' diff --git a/spec/serializers/user_entity_spec.rb b/spec/serializers/user_entity_spec.rb index edb49757b38..71107daf6ac 100644 --- a/spec/serializers/user_entity_spec.rb +++ b/spec/serializers/user_entity_spec.rb @@ -7,6 +7,7 @@ describe UserEntity do let(:entity) { described_class.new(user) } let(:user) { create(:user) } + subject { entity.as_json } it 'exposes user name and login' do diff --git a/spec/support/helpers/kubernetes_helpers.rb b/spec/support/helpers/kubernetes_helpers.rb index a3b527e0ffe..ad4ae93a027 100644 --- a/spec/support/helpers/kubernetes_helpers.rb +++ b/spec/support/helpers/kubernetes_helpers.rb @@ -351,7 +351,7 @@ module KubernetesHelpers def kube_knative_services_body(**options) { "kind" => "List", - "items" => [knative_07_service(options)] + "items" => [knative_09_service(options)] } end @@ -540,6 +540,58 @@ module KubernetesHelpers end # noinspection RubyStringKeysInHashInspection + def knative_09_service(name: 'kubetest', namespace: 'default', domain: 'example.com', description: 'a knative service', environment: 'production') + { "apiVersion" => "serving.knative.dev/v1alpha1", + "kind" => "Service", + "metadata" => + { "annotations" => + { "serving.knative.dev/creator" => "system:serviceaccount:#{namespace}:#{namespace}-service-account", + "serving.knative.dev/lastModifier" => "system:serviceaccount:#{namespace}:#{namespace}-service-account" }, + "creationTimestamp" => "2019-10-22T21:19:13Z", + "generation" => 1, + "labels" => { "service" => name }, + "name" => name, + "namespace" => namespace, + "resourceVersion" => "289726", + "selfLink" => "/apis/serving.knative.dev/v1alpha1/namespaces/#{namespace}/services/#{name}", + "uid" => "988349fa-f511-11e9-9ea1-42010a80005e" }, + "spec" => { + "template" => { + "metadata" => { + "annotations" => { "Description" => description }, + "creationTimestamp" => "2019-10-22T21:19:12Z", + "labels" => { "service" => name } + }, + "spec" => { + "containers" => [{ + "env" => + [{ "name" => "timestamp", "value" => "2019-10-22 21:19:12" }], + "image" => "image_name", + "name" => "user-container", + "resources" => {} + }], + "timeoutSeconds" => 300 + } + }, + "traffic" => [{ "latestRevision" => true, "percent" => 100 }] + }, + "status" => + { "address" => { "url" => "http://#{name}.#{namespace}.svc.cluster.local" }, + "conditions" => + [{ "lastTransitionTime" => "2019-10-22T21:20:15Z", "status" => "True", "type" => "ConfigurationsReady" }, + { "lastTransitionTime" => "2019-10-22T21:20:15Z", "status" => "True", "type" => "Ready" }, + { "lastTransitionTime" => "2019-10-22T21:20:15Z", "status" => "True", "type" => "RoutesReady" }], + "latestCreatedRevisionName" => "#{name}-92tsj", + "latestReadyRevisionName" => "#{name}-92tsj", + "observedGeneration" => 1, + "traffic" => [{ "latestRevision" => true, "percent" => 100, "revisionName" => "#{name}-92tsj" }], + "url" => "http://#{name}.#{namespace}.#{domain}" }, + "environment_scope" => environment, + "cluster_id" => 5, + "podcount" => 0 } + end + + # noinspection RubyStringKeysInHashInspection def knative_05_service(name: 'kubetest', namespace: 'default', domain: 'example.com', description: 'a knative service', environment: 'production') { "apiVersion" => "serving.knative.dev/v1alpha1", "kind" => "Service", diff --git a/spec/support/shared_examples/policies/project_policy_shared_examples.rb b/spec/support/shared_examples/policies/project_policy_shared_examples.rb index 37f8bc14e20..1831fc10628 100644 --- a/spec/support/shared_examples/policies/project_policy_shared_examples.rb +++ b/spec/support/shared_examples/policies/project_policy_shared_examples.rb @@ -152,6 +152,7 @@ end RSpec.shared_examples 'project policies as developer' do context 'abilities for non-public projects' do let(:project) { create(:project, namespace: owner.namespace) } + subject { described_class.new(developer, project) } it do diff --git a/spec/uploaders/file_mover_spec.rb b/spec/uploaders/file_mover_spec.rb index c4a315b3fd6..9f053f03b0e 100644 --- a/spec/uploaders/file_mover_spec.rb +++ b/spec/uploaders/file_mover_spec.rb @@ -22,6 +22,7 @@ describe FileMover do end let(:file) { fixture_file_upload('spec/fixtures/banana_sample.gif') } + subject { described_class.new(temp_file_path, from_model: user, to_model: snippet).execute } describe '#execute' do diff --git a/spec/validators/addressable_url_validator_spec.rb b/spec/validators/addressable_url_validator_spec.rb index 6927a1f67a1..e8a44f7a12a 100644 --- a/spec/validators/addressable_url_validator_spec.rb +++ b/spec/validators/addressable_url_validator_spec.rb @@ -4,6 +4,7 @@ require 'spec_helper' describe AddressableUrlValidator do let!(:badge) { build(:badge, link_url: 'http://www.example.com') } + subject { validator.validate(badge) } include_examples 'url validator examples', described_class::DEFAULT_OPTIONS[:schemes] diff --git a/spec/validators/devise_email_validator_spec.rb b/spec/validators/devise_email_validator_spec.rb index 7860b659bd3..1dbf3f66cfd 100644 --- a/spec/validators/devise_email_validator_spec.rb +++ b/spec/validators/devise_email_validator_spec.rb @@ -4,6 +4,7 @@ require 'spec_helper' describe DeviseEmailValidator do let!(:user) { build(:user, public_email: 'test@example.com') } + subject { validator.validate(user) } describe 'validations' do diff --git a/spec/views/help/index.html.haml_spec.rb b/spec/views/help/index.html.haml_spec.rb index 474a294ce0d..98040da9d2c 100644 --- a/spec/views/help/index.html.haml_spec.rb +++ b/spec/views/help/index.html.haml_spec.rb @@ -40,7 +40,7 @@ describe 'help/index' do render expect(rendered).to match '8.0.2' - expect(rendered).to have_link('abcdefg', href: %r{https://gitlab.com/gitlab-org/(gitlab|gitlab-foss)/commits/abcdefg}) + expect(rendered).to have_link('abcdefg', href: %r{https://gitlab.com/gitlab-org/(gitlab|gitlab-foss)/-/commits/abcdefg}) end end end diff --git a/spec/workers/expire_job_cache_worker_spec.rb b/spec/workers/expire_job_cache_worker_spec.rb index 6ac285ca944..eeab304d926 100644 --- a/spec/workers/expire_job_cache_worker_spec.rb +++ b/spec/workers/expire_job_cache_worker_spec.rb @@ -5,6 +5,7 @@ require 'spec_helper' describe ExpireJobCacheWorker do set(:pipeline) { create(:ci_empty_pipeline) } let(:project) { pipeline.project } + subject { described_class.new } describe '#perform' do diff --git a/spec/workers/expire_pipeline_cache_worker_spec.rb b/spec/workers/expire_pipeline_cache_worker_spec.rb index 5652f5e8685..e162a227a66 100644 --- a/spec/workers/expire_pipeline_cache_worker_spec.rb +++ b/spec/workers/expire_pipeline_cache_worker_spec.rb @@ -6,6 +6,7 @@ describe ExpirePipelineCacheWorker do let(:user) { create(:user) } let(:project) { create(:project) } let(:pipeline) { create(:ci_pipeline, project: project) } + subject { described_class.new } describe '#perform' do diff --git a/spec/workers/mail_scheduler/notification_service_worker_spec.rb b/spec/workers/mail_scheduler/notification_service_worker_spec.rb index 0729c5f9ffb..14a9f0ed8b7 100644 --- a/spec/workers/mail_scheduler/notification_service_worker_spec.rb +++ b/spec/workers/mail_scheduler/notification_service_worker_spec.rb @@ -5,6 +5,7 @@ require 'spec_helper' describe MailScheduler::NotificationServiceWorker do let(:worker) { described_class.new } let(:method) { 'new_key' } + set(:key) { create(:personal_key) } def serialize(*args) diff --git a/spec/workers/repository_check/batch_worker_spec.rb b/spec/workers/repository_check/batch_worker_spec.rb index 051c6a5d141..12e7d1879d0 100644 --- a/spec/workers/repository_check/batch_worker_spec.rb +++ b/spec/workers/repository_check/batch_worker_spec.rb @@ -4,6 +4,7 @@ require 'spec_helper' describe RepositoryCheck::BatchWorker do let(:shard_name) { 'default' } + subject { described_class.new } before do diff --git a/yarn.lock b/yarn.lock index fbc6733fea4..aa45c5dc6b2 100644 --- a/yarn.lock +++ b/yarn.lock @@ -278,6 +278,14 @@ "@babel/helper-plugin-utils" "^7.0.0" "@babel/plugin-syntax-optional-catch-binding" "^7.2.0" +"@babel/plugin-proposal-optional-chaining@^7.7.5": + version "7.7.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.7.5.tgz#f0835f044cef85b31071a924010a2a390add11d4" + integrity sha512-sOwFqT8JSchtJeDD+CjmWCaiFoLxY4Ps7NjvwHC/U7l4e9i5pTRNt8nDMIFSOUL+ncFbYSwruHM8WknYItWdXw== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + "@babel/plugin-syntax-optional-chaining" "^7.7.4" + "@babel/plugin-proposal-private-methods@^7.6.0": version "7.6.0" resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.6.0.tgz#19ddc493c7b5d47afdd4291e740c609a83c9fae4" @@ -337,6 +345,13 @@ dependencies: "@babel/helper-plugin-utils" "^7.0.0" +"@babel/plugin-syntax-optional-chaining@^7.7.4": + version "7.7.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.7.4.tgz#c91fdde6de85d2eb8906daea7b21944c3610c901" + integrity sha512-2MqYD5WjZSbJdUagnJvIdSfkb/ucOC9/1fRJxm7GAxY6YQLWlUvkfxoNbUPcPLHJyetKUDQ4+yyuUyAoc0HriA== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + "@babel/plugin-transform-arrow-functions@^7.2.0": version "7.2.0" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.2.0.tgz#9aeafbe4d6ffc6563bf8f8372091628f00779550" |