diff options
320 files changed, 4686 insertions, 1863 deletions
diff --git a/.codeclimate.yml b/.codeclimate.yml index e5636a13783..42afed54371 100644 --- a/.codeclimate.yml +++ b/.codeclimate.yml @@ -10,10 +10,10 @@ engines: languages: - ruby - javascript + exclude_paths: + - "lib/api/v3/*" eslint: enabled: true - fixme: - enabled: true rubocop: enabled: true ratings: @@ -35,4 +35,13 @@ exclude_paths: - node_modules/ - spec/ - vendor/ -- lib/api/v3/ +- .yarn-cache/ +- tmp/ +- builds/ +- coverage/ +- public/ +- shared/ +- webpack-report/ +- log/ +- backups/ +- coverage-javascript/ diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index b442e48a3d0..c6868931657 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -456,6 +456,21 @@ karma: paths: - coverage-javascript/ +codeclimate: + before_script: [] + image: docker:latest + stage: test + variables: + SETUP_DB: "false" + DOCKER_DRIVER: overlay + services: + - docker:dind + script: + - docker pull codeclimate/codeclimate + - docker run --env CODECLIMATE_CODE="$PWD" --volume "$PWD":/code --volume /var/run/docker.sock:/var/run/docker.sock --volume /tmp/cc:/tmp/cc codeclimate/codeclimate analyze -f json > codeclimate.json + artifacts: + paths: [codeclimate.json] + coverage: stage: post-test services: [] diff --git a/.rubocop.yml b/.rubocop.yml index 66a40f2cf57..4537e710dd4 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -1064,6 +1064,13 @@ RSpec/NotToNot: RSpec/RepeatedDescription: Enabled: false +# Ensure RSpec hook blocks are always multi-line. +RSpec/SingleLineHook: + Enabled: true + Exclude: + - 'spec/factories/*' + - 'spec/requests/api/v3/*' + # Checks for stubbed test subjects. RSpec/SubjectStub: Enabled: false diff --git a/app/assets/javascripts/commit/pipelines/pipelines_table.js b/app/assets/javascripts/commit/pipelines/pipelines_table.js index 082fbafb740..70ba83ce5b9 100644 --- a/app/assets/javascripts/commit/pipelines/pipelines_table.js +++ b/app/assets/javascripts/commit/pipelines/pipelines_table.js @@ -1,6 +1,6 @@ import Vue from 'vue'; import Visibility from 'visibilityjs'; -import pipelinesTableComponent from '../../vue_shared/components/pipelines_table'; +import pipelinesTableComponent from '../../vue_shared/components/pipelines_table.vue'; import PipelinesService from '../../pipelines/services/pipelines_service'; import PipelineStore from '../../pipelines/stores/pipelines_store'; import eventHub from '../../pipelines/event_hub'; diff --git a/app/assets/javascripts/environments/components/environment_item.vue b/app/assets/javascripts/environments/components/environment_item.vue index de2269118cd..614637b637e 100644 --- a/app/assets/javascripts/environments/components/environment_item.vue +++ b/app/assets/javascripts/environments/components/environment_item.vue @@ -9,7 +9,7 @@ import StopComponent from './environment_stop.vue'; import RollbackComponent from './environment_rollback.vue'; import TerminalButtonComponent from './environment_terminal_button.vue'; import MonitoringButtonComponent from './environment_monitoring.vue'; -import CommitComponent from '../../vue_shared/components/commit'; +import CommitComponent from '../../vue_shared/components/commit.vue'; import eventHub from '../event_hub'; /** diff --git a/app/assets/javascripts/environments/stores/environments_store.js b/app/assets/javascripts/environments/stores/environments_store.js index 8a2f6a473de..a5773dd7e4f 100644 --- a/app/assets/javascripts/environments/stores/environments_store.js +++ b/app/assets/javascripts/environments/stores/environments_store.js @@ -158,5 +158,4 @@ export default class EnvironmentsStore { return environments.filter(env => env.isFolder && env.isOpen); } - } diff --git a/app/assets/javascripts/milestone.js b/app/assets/javascripts/milestone.js index 841b24a60a3..07ede5ee913 100644 --- a/app/assets/javascripts/milestone.js +++ b/app/assets/javascripts/milestone.js @@ -65,14 +65,18 @@ }; Milestone.successCallback = function(data, element) { - var img_tag; - if (data.assignee) { - img_tag = $('<img/>'); - img_tag.attr('src', data.assignee.avatar_url); - img_tag.addClass('avatar s16'); - $(element).find('.assignee-icon img').replaceWith(img_tag); - } else { - $(element).find('.assignee-icon').empty(); + const $avatarContainer = $(element).find('.assignee-icon'); + $avatarContainer.empty(); + + if (data.assignees && data.assignees.length > 0) { + const $avatars = data.assignees.map((assignee) => { + const img_tag = $('<img/>'); + img_tag.attr('src', assignee.avatar_url); + img_tag.addClass('avatar s16'); + return img_tag; + }); + + $avatarContainer.append($avatars); } }; @@ -161,9 +165,9 @@ data = (function() { switch (newState) { case 'ongoing': - return opts.fieldName + '[assignee_id]=' + gon.current_user_id; + return `${opts.fieldName}[assignee_ids][]=${gon.current_user_id}`; case 'unassigned': - return opts.fieldName + '[assignee_id]='; + return `${opts.fieldName}[assignee_ids][]=0`; case 'closed': return opts.fieldName + '[state_event]=close'; } diff --git a/app/assets/javascripts/notes.js b/app/assets/javascripts/notes.js index b0143b12cfe..d56cf959486 100644 --- a/app/assets/javascripts/notes.js +++ b/app/assets/javascripts/notes.js @@ -56,6 +56,7 @@ const normalizeNewlines = function(str) { this.toggleCommitList = this.toggleCommitList.bind(this); this.postComment = this.postComment.bind(this); this.clearFlashWrapper = this.clearFlash.bind(this); + this.onHashChange = this.onHashChange.bind(this); this.notes_url = notes_url; this.note_ids = note_ids; @@ -127,7 +128,9 @@ const normalizeNewlines = function(str) { $(document).on('ajax:success', '.js-main-target-form', this.resetMainTargetForm); $(document).on('ajax:complete', '.js-main-target-form', this.reenableTargetFormSubmitButton); // when a key is clicked on the notes - return $(document).on('keydown', '.js-note-text', this.keydownNoteText); + $(document).on('keydown', '.js-note-text', this.keydownNoteText); + // When the URL fragment/hash has changed, `#note_xxx` + return $(window).on('hashchange', this.onHashChange); }; Notes.prototype.cleanBinding = function() { @@ -148,6 +151,7 @@ const normalizeNewlines = function(str) { $(document).off('ajax:success', '.js-main-target-form'); $(document).off('ajax:success', '.js-discussion-note-form'); $(document).off('ajax:complete', '.js-main-target-form'); + $(window).off('hashchange', this.onHashChange); }; Notes.initCommentTypeToggle = function (form) { @@ -298,8 +302,27 @@ const normalizeNewlines = function(str) { Notes.prototype.setupNewNote = function($note) { // Update datetime format on the recent note gl.utils.localTimeAgo($note.find('.js-timeago'), false); + this.collapseLongCommitList(); this.taskList.init(); + + // This stops the note highlight, #note_xxx`, from being removed after real time update + // The `:target` selector does not re-evaluate after we replace element in the DOM + Notes.updateNoteTargetSelector($note); + this.$noteToCleanHighlight = $note; + }; + + Notes.prototype.onHashChange = function() { + if (this.$noteToCleanHighlight) { + Notes.updateNoteTargetSelector(this.$noteToCleanHighlight); + } + + this.$noteToCleanHighlight = null; + }; + + Notes.updateNoteTargetSelector = function($note) { + const hash = gl.utils.getLocationHash(); + $note.toggleClass('target', hash && $note.filter(`#${hash}`).length > 0); }; /* @@ -597,13 +620,12 @@ const normalizeNewlines = function(str) { $noteEntityEl = $(noteEntity.html); $noteEntityEl.addClass('fade-in-full'); this.revertNoteEditForm($targetNote); - gl.utils.localTimeAgo($('.js-timeago', $noteEntityEl)); $noteEntityEl.renderGFM(); - $noteEntityEl.find('.js-task-list-container').taskList('enable'); // Find the note's `li` element by ID and replace it with the updated HTML $note_li = $('.note-row-' + noteEntity.id); $note_li.replaceWith($noteEntityEl); + this.setupNewNote($noteEntityEl); if (typeof gl.diffNotesCompileComponents !== 'undefined') { gl.diffNotesCompileComponents(); @@ -1060,7 +1082,7 @@ const normalizeNewlines = function(str) { var targetId = $originalContentEl.data('target-id'); var targetType = $originalContentEl.data('target-type'); - new gl.GLForm($editForm.find('form')); + new gl.GLForm($editForm.find('form'), this.enableGFM); $editForm.find('form') .attr('action', postUrl) diff --git a/app/assets/javascripts/pipelines/components/pipelines.vue b/app/assets/javascripts/pipelines/components/pipelines.vue new file mode 100644 index 00000000000..fed42d23112 --- /dev/null +++ b/app/assets/javascripts/pipelines/components/pipelines.vue @@ -0,0 +1,289 @@ +<script> + import Visibility from 'visibilityjs'; + import PipelinesService from '../services/pipelines_service'; + import eventHub from '../event_hub'; + import pipelinesTableComponent from '../../vue_shared/components/pipelines_table.vue'; + import tablePagination from '../../vue_shared/components/table_pagination.vue'; + import emptyState from './empty_state.vue'; + import errorState from './error_state.vue'; + import navigationTabs from './navigation_tabs.vue'; + import navigationControls from './nav_controls.vue'; + import loadingIcon from '../../vue_shared/components/loading_icon.vue'; + import Poll from '../../lib/utils/poll'; + + export default { + props: { + store: { + type: Object, + required: true, + }, + }, + components: { + tablePagination, + pipelinesTableComponent, + emptyState, + errorState, + navigationTabs, + navigationControls, + loadingIcon, + }, + data() { + const pipelinesData = document.querySelector('#pipelines-list-vue').dataset; + + return { + endpoint: pipelinesData.endpoint, + cssClass: pipelinesData.cssClass, + helpPagePath: pipelinesData.helpPagePath, + newPipelinePath: pipelinesData.newPipelinePath, + canCreatePipeline: pipelinesData.canCreatePipeline, + allPath: pipelinesData.allPath, + pendingPath: pipelinesData.pendingPath, + runningPath: pipelinesData.runningPath, + finishedPath: pipelinesData.finishedPath, + branchesPath: pipelinesData.branchesPath, + tagsPath: pipelinesData.tagsPath, + hasCi: pipelinesData.hasCi, + ciLintPath: pipelinesData.ciLintPath, + state: this.store.state, + apiScope: 'all', + pagenum: 1, + isLoading: false, + hasError: false, + isMakingRequest: false, + updateGraphDropdown: false, + hasMadeRequest: false, + }; + }, + computed: { + canCreatePipelineParsed() { + return gl.utils.convertPermissionToBoolean(this.canCreatePipeline); + }, + scope() { + const scope = gl.utils.getParameterByName('scope'); + return scope === null ? 'all' : scope; + }, + shouldRenderErrorState() { + return this.hasError && !this.isLoading; + }, + + /** + * The empty state should only be rendered when the request is made to fetch all pipelines + * and none is returned. + * + * @return {Boolean} + */ + shouldRenderEmptyState() { + return !this.isLoading && + !this.hasError && + this.hasMadeRequest && + !this.state.pipelines.length && + (this.scope === 'all' || this.scope === null); + }, + /** + * When a specific scope does not have pipelines we render a message. + * + * @return {Boolean} + */ + shouldRenderNoPipelinesMessage() { + return !this.isLoading && + !this.hasError && + !this.state.pipelines.length && + this.scope !== 'all' && + this.scope !== null; + }, + + shouldRenderTable() { + return !this.hasError && + !this.isLoading && this.state.pipelines.length; + }, + /** + * Pagination should only be rendered when there is more than one page. + * + * @return {Boolean} + */ + shouldRenderPagination() { + return !this.isLoading && + this.state.pipelines.length && + this.state.pageInfo.total > this.state.pageInfo.perPage; + }, + + hasCiEnabled() { + return this.hasCi !== undefined; + }, + paths() { + return { + allPath: this.allPath, + pendingPath: this.pendingPath, + finishedPath: this.finishedPath, + runningPath: this.runningPath, + branchesPath: this.branchesPath, + tagsPath: this.tagsPath, + }; + }, + pageParameter() { + return gl.utils.getParameterByName('page') || this.pagenum; + }, + scopeParameter() { + return gl.utils.getParameterByName('scope') || this.apiScope; + }, + }, + created() { + this.service = new PipelinesService(this.endpoint); + + const poll = new Poll({ + resource: this.service, + method: 'getPipelines', + data: { page: this.pageParameter, scope: this.scopeParameter }, + successCallback: this.successCallback, + errorCallback: this.errorCallback, + notificationCallback: this.setIsMakingRequest, + }); + + if (!Visibility.hidden()) { + this.isLoading = true; + poll.makeRequest(); + } else { + // If tab is not visible we need to make the first request so we don't show the empty + // state without knowing if there are any pipelines + this.fetchPipelines(); + } + + Visibility.change(() => { + if (!Visibility.hidden()) { + poll.restart(); + } else { + poll.stop(); + } + }); + + eventHub.$on('refreshPipelines', this.fetchPipelines); + }, + beforeDestroy() { + eventHub.$off('refreshPipelines'); + }, + methods: { + /** + * Will change the page number and update the URL. + * + * @param {Number} pageNumber desired page to go to. + */ + change(pageNumber) { + const param = gl.utils.setParamInURL('page', pageNumber); + + gl.utils.visitUrl(param); + return param; + }, + + fetchPipelines() { + if (!this.isMakingRequest) { + this.isLoading = true; + + this.service.getPipelines({ scope: this.scopeParameter, page: this.pageParameter }) + .then(response => this.successCallback(response)) + .catch(() => this.errorCallback()); + } + }, + successCallback(resp) { + const response = { + headers: resp.headers, + body: resp.json(), + }; + + this.store.storeCount(response.body.count); + this.store.storePipelines(response.body.pipelines); + this.store.storePagination(response.headers); + + this.isLoading = false; + this.updateGraphDropdown = true; + this.hasMadeRequest = true; + }, + + errorCallback() { + this.hasError = true; + this.isLoading = false; + this.updateGraphDropdown = false; + }, + + setIsMakingRequest(isMakingRequest) { + this.isMakingRequest = isMakingRequest; + + if (isMakingRequest) { + this.updateGraphDropdown = false; + } + }, + }, + }; +</script> +<template> + <div :class="cssClass"> + + <div + class="top-area scrolling-tabs-container inner-page-scroll-tabs" + v-if="!isLoading && !shouldRenderEmptyState"> + <div class="fade-left"> + <i + class="fa fa-angle-left" + aria-hidden="true"> + </i> + </div> + <div class="fade-right"> + <i + class="fa fa-angle-right" + aria-hidden="true"> + </i> + </div> + <navigation-tabs + :scope="scope" + :count="state.count" + :paths="paths" + /> + + <navigation-controls + :new-pipeline-path="newPipelinePath" + :has-ci-enabled="hasCiEnabled" + :help-page-path="helpPagePath" + :ciLintPath="ciLintPath" + :can-create-pipeline="canCreatePipelineParsed " + /> + </div> + + <div class="content-list pipelines"> + + <loading-icon + label="Loading Pipelines" + size="3" + v-if="isLoading" + /> + + <empty-state + v-if="shouldRenderEmptyState" + :help-page-path="helpPagePath" + /> + + <error-state v-if="shouldRenderErrorState" /> + + <div + class="blank-state blank-state-no-icon" + v-if="shouldRenderNoPipelinesMessage"> + <h2 class="blank-state-title js-blank-state-title">No pipelines to show.</h2> + </div> + + <div + class="table-holder" + v-if="shouldRenderTable"> + + <pipelines-table-component + :pipelines="state.pipelines" + :service="service" + :update-graph-dropdown="updateGraphDropdown" + /> + </div> + + <table-pagination + v-if="shouldRenderPagination" + :change="change" + :pageInfo="state.pageInfo" + /> + </div> + </div> +</template> diff --git a/app/assets/javascripts/pipelines/components/pipelines_actions.js b/app/assets/javascripts/pipelines/components/pipelines_actions.js deleted file mode 100644 index b9e066c5db1..00000000000 --- a/app/assets/javascripts/pipelines/components/pipelines_actions.js +++ /dev/null @@ -1,91 +0,0 @@ -/* eslint-disable no-new */ -/* global Flash */ -import '~/flash'; -import playIconSvg from 'icons/_icon_play.svg'; -import eventHub from '../event_hub'; -import loadingIconComponent from '../../vue_shared/components/loading_icon.vue'; - -export default { - props: { - actions: { - type: Array, - required: true, - }, - - service: { - type: Object, - required: true, - }, - }, - - components: { - loadingIconComponent, - }, - - data() { - return { - playIconSvg, - isLoading: false, - }; - }, - - methods: { - onClickAction(endpoint) { - this.isLoading = true; - - $(this.$refs.tooltip).tooltip('destroy'); - - this.service.postAction(endpoint) - .then(() => { - this.isLoading = false; - eventHub.$emit('refreshPipelines'); - }) - .catch(() => { - this.isLoading = false; - new Flash('An error occured while making the request.'); - }); - }, - - isActionDisabled(action) { - if (action.playable === undefined) { - return false; - } - - return !action.playable; - }, - }, - - template: ` - <div class="btn-group" v-if="actions"> - <button - type="button" - class="dropdown-toggle btn btn-default has-tooltip js-pipeline-dropdown-manual-actions" - title="Manual job" - data-toggle="dropdown" - data-placement="top" - aria-label="Manual job" - ref="tooltip" - :disabled="isLoading"> - ${playIconSvg} - <i - class="fa fa-caret-down" - aria-hidden="true" /> - <loading-icon v-if="isLoading" /> - </button> - - <ul class="dropdown-menu dropdown-menu-align-right"> - <li v-for="action in actions"> - <button - type="button" - class="js-pipeline-action-link no-btn btn" - @click="onClickAction(action.path)" - :class="{ 'disabled': isActionDisabled(action) }" - :disabled="isActionDisabled(action)"> - ${playIconSvg} - <span>{{action.name}}</span> - </button> - </li> - </ul> - </div> - `, -}; diff --git a/app/assets/javascripts/pipelines/components/pipelines_actions.vue b/app/assets/javascripts/pipelines/components/pipelines_actions.vue new file mode 100644 index 00000000000..da5df2a06cf --- /dev/null +++ b/app/assets/javascripts/pipelines/components/pipelines_actions.vue @@ -0,0 +1,88 @@ +<script> + /* global Flash */ + import '~/flash'; + import playIconSvg from 'icons/_icon_play.svg'; + import eventHub from '../event_hub'; + import loadingIcon from '../../vue_shared/components/loading_icon.vue'; + + export default { + props: { + actions: { + type: Array, + required: true, + }, + service: { + type: Object, + required: true, + }, + }, + components: { + loadingIcon, + }, + data() { + return { + playIconSvg, + isLoading: false, + }; + }, + methods: { + onClickAction(endpoint) { + this.isLoading = true; + + $(this.$refs.tooltip).tooltip('destroy'); + + this.service.postAction(endpoint) + .then(() => { + this.isLoading = false; + eventHub.$emit('refreshPipelines'); + }) + .catch(() => { + this.isLoading = false; + // eslint-disable-next-line no-new + new Flash('An error occured while making the request.'); + }); + }, + isActionDisabled(action) { + if (action.playable === undefined) { + return false; + } + + return !action.playable; + }, + }, + }; +</script> +<template> + <div class="btn-group"> + <button + type="button" + class="dropdown-toggle btn btn-default has-tooltip js-pipeline-dropdown-manual-actions" + title="Manual job" + data-toggle="dropdown" + data-placement="top" + aria-label="Manual job" + ref="tooltip" + :disabled="isLoading"> + <span v-html="playIconSvg"></span> + <i + class="fa fa-caret-down" + aria-hidden="true"> + </i> + <loading-icon v-if="isLoading" /> + </button> + + <ul class="dropdown-menu dropdown-menu-align-right"> + <li v-for="action in actions"> + <button + type="button" + class="js-pipeline-action-link no-btn btn" + @click="onClickAction(action.path)" + :class="{ disabled: isActionDisabled(action) }" + :disabled="isActionDisabled(action)"> + <span v-html="playIconSvg"></span> + <span>{{action.name}}</span> + </button> + </li> + </ul> + </div> +</template> diff --git a/app/assets/javascripts/pipelines/components/pipelines_artifacts.js b/app/assets/javascripts/pipelines/components/pipelines_artifacts.js deleted file mode 100644 index f18e2dfadaf..00000000000 --- a/app/assets/javascripts/pipelines/components/pipelines_artifacts.js +++ /dev/null @@ -1,33 +0,0 @@ -export default { - props: { - artifacts: { - type: Array, - required: true, - }, - }, - - template: ` - <div class="btn-group" role="group"> - <button - class="dropdown-toggle btn btn-default build-artifacts has-tooltip js-pipeline-dropdown-download" - title="Artifacts" - data-placement="top" - data-toggle="dropdown" - aria-label="Artifacts"> - <i class="fa fa-download" aria-hidden="true"></i> - <i class="fa fa-caret-down" aria-hidden="true"></i> - </button> - <ul class="dropdown-menu dropdown-menu-align-right"> - <li v-for="artifact in artifacts"> - <a - rel="nofollow" - download - :href="artifact.path"> - <i class="fa fa-download" aria-hidden="true"></i> - <span>Download {{artifact.name}} artifacts</span> - </a> - </li> - </ul> - </div> - `, -}; diff --git a/app/assets/javascripts/pipelines/components/pipelines_artifacts.vue b/app/assets/javascripts/pipelines/components/pipelines_artifacts.vue new file mode 100644 index 00000000000..b4520481cdc --- /dev/null +++ b/app/assets/javascripts/pipelines/components/pipelines_artifacts.vue @@ -0,0 +1,51 @@ +<script> + import tooltipMixin from '../../vue_shared/mixins/tooltip'; + + export default { + props: { + artifacts: { + type: Array, + required: true, + }, + }, + mixins: [ + tooltipMixin, + ], + }; +</script> +<template> + <div + class="btn-group" + role="group"> + <button + class="dropdown-toggle btn btn-default build-artifacts js-pipeline-dropdown-download" + title="Artifacts" + data-placement="top" + data-toggle="dropdown" + aria-label="Artifacts" + ref="tooltip"> + <i + class="fa fa-download" + aria-hidden="true"> + </i> + <i + class="fa fa-caret-down" + aria-hidden="true"> + </i> + </button> + <ul class="dropdown-menu dropdown-menu-align-right"> + <li v-for="artifact in artifacts"> + <a + rel="nofollow" + download + :href="artifact.path"> + <i + class="fa fa-download" + aria-hidden="true"> + </i> + <span>Download {{artifact.name}} artifacts</span> + </a> + </li> + </ul> + </div> +</template> diff --git a/app/assets/javascripts/pipelines/components/time_ago.js b/app/assets/javascripts/pipelines/components/time_ago.js deleted file mode 100644 index 188f74cc705..00000000000 --- a/app/assets/javascripts/pipelines/components/time_ago.js +++ /dev/null @@ -1,98 +0,0 @@ -import iconTimerSvg from 'icons/_icon_timer.svg'; -import '../../lib/utils/datetime_utility'; - -export default { - props: { - finishedTime: { - type: String, - required: true, - }, - - duration: { - type: Number, - required: true, - }, - }, - - data() { - return { - iconTimerSvg, - }; - }, - - updated() { - $(this.$refs.tooltip).tooltip('fixTitle'); - }, - - computed: { - hasDuration() { - return this.duration > 0; - }, - - hasFinishedTime() { - return this.finishedTime !== ''; - }, - - localTimeFinished() { - return gl.utils.formatDate(this.finishedTime); - }, - - durationFormated() { - const date = new Date(this.duration * 1000); - - let hh = date.getUTCHours(); - let mm = date.getUTCMinutes(); - let ss = date.getSeconds(); - - // left pad - if (hh < 10) { - hh = `0${hh}`; - } - if (mm < 10) { - mm = `0${mm}`; - } - if (ss < 10) { - ss = `0${ss}`; - } - - return `${hh}:${mm}:${ss}`; - }, - - finishedTimeFormated() { - const timeAgo = gl.utils.getTimeago(); - - return timeAgo.format(this.finishedTime); - }, - }, - - template: ` - <td class="pipelines-time-ago"> - <p - class="duration" - v-if="hasDuration"> - <span - v-html="iconTimerSvg"> - </span> - {{durationFormated}} - </p> - - <p - class="finished-at" - v-if="hasFinishedTime"> - - <i - class="fa fa-calendar" - aria-hidden="true" /> - - <time - ref="tooltip" - data-toggle="tooltip" - data-placement="top" - data-container="body" - :title="localTimeFinished"> - {{finishedTimeFormated}} - </time> - </p> - </td> - `, -}; diff --git a/app/assets/javascripts/pipelines/components/time_ago.vue b/app/assets/javascripts/pipelines/components/time_ago.vue new file mode 100644 index 00000000000..c47658cd6e6 --- /dev/null +++ b/app/assets/javascripts/pipelines/components/time_ago.vue @@ -0,0 +1,85 @@ +<script> + import iconTimerSvg from 'icons/_icon_timer.svg'; + import '../../lib/utils/datetime_utility'; + import tooltipMixin from '../../vue_shared/mixins/tooltip'; + import timeagoMixin from '../../vue_shared/mixins/timeago'; + + export default { + props: { + finishedTime: { + type: String, + required: true, + }, + duration: { + type: Number, + required: true, + }, + }, + mixins: [ + tooltipMixin, + timeagoMixin, + ], + data() { + return { + iconTimerSvg, + }; + }, + computed: { + hasDuration() { + return this.duration > 0; + }, + hasFinishedTime() { + return this.finishedTime !== ''; + }, + durationFormated() { + const date = new Date(this.duration * 1000); + + let hh = date.getUTCHours(); + let mm = date.getUTCMinutes(); + let ss = date.getSeconds(); + + // left pad + if (hh < 10) { + hh = `0${hh}`; + } + if (mm < 10) { + mm = `0${mm}`; + } + if (ss < 10) { + ss = `0${ss}`; + } + + return `${hh}:${mm}:${ss}`; + }, + }, + }; +</script> +<template> + <td class="pipelines-time-ago"> + <p + class="duration" + v-if="hasDuration"> + <span v-html="iconTimerSvg"> + </span> + {{durationFormated}} + </p> + + <p + class="finished-at" + v-if="hasFinishedTime"> + + <i + class="fa fa-calendar" + aria-hidden="true"> + </i> + + <time + ref="tooltip" + data-placement="top" + data-container="body" + :title="tooltipTitle(finishedTime)"> + {{timeFormated(finishedTime)}} + </time> + </p> + </td> +</script> diff --git a/app/assets/javascripts/pipelines/index.js b/app/assets/javascripts/pipelines/index.js deleted file mode 100644 index 48f9181a8d9..00000000000 --- a/app/assets/javascripts/pipelines/index.js +++ /dev/null @@ -1,22 +0,0 @@ -import Vue from 'vue'; -import PipelinesStore from './stores/pipelines_store'; -import PipelinesComponent from './pipelines'; -import '../vue_shared/vue_resource_interceptor'; - -$(() => new Vue({ - el: document.querySelector('#pipelines-list-vue'), - - data() { - const store = new PipelinesStore(); - - return { - store, - }; - }, - components: { - 'vue-pipelines': PipelinesComponent, - }, - template: ` - <vue-pipelines :store="store" /> - `, -})); diff --git a/app/assets/javascripts/pipelines/pipelines.js b/app/assets/javascripts/pipelines/pipelines.js deleted file mode 100644 index b530461837c..00000000000 --- a/app/assets/javascripts/pipelines/pipelines.js +++ /dev/null @@ -1,293 +0,0 @@ -import Visibility from 'visibilityjs'; -import PipelinesService from './services/pipelines_service'; -import eventHub from './event_hub'; -import pipelinesTableComponent from '../vue_shared/components/pipelines_table'; -import tablePagination from '../vue_shared/components/table_pagination.vue'; -import emptyState from './components/empty_state.vue'; -import errorState from './components/error_state.vue'; -import navigationTabs from './components/navigation_tabs.vue'; -import navigationControls from './components/nav_controls.vue'; -import loadingIcon from '../vue_shared/components/loading_icon.vue'; -import Poll from '../lib/utils/poll'; - -export default { - props: { - store: { - type: Object, - required: true, - }, - }, - - components: { - tablePagination, - pipelinesTableComponent, - emptyState, - errorState, - navigationTabs, - navigationControls, - loadingIcon, - }, - - data() { - const pipelinesData = document.querySelector('#pipelines-list-vue').dataset; - - return { - endpoint: pipelinesData.endpoint, - cssClass: pipelinesData.cssClass, - helpPagePath: pipelinesData.helpPagePath, - newPipelinePath: pipelinesData.newPipelinePath, - canCreatePipeline: pipelinesData.canCreatePipeline, - allPath: pipelinesData.allPath, - pendingPath: pipelinesData.pendingPath, - runningPath: pipelinesData.runningPath, - finishedPath: pipelinesData.finishedPath, - branchesPath: pipelinesData.branchesPath, - tagsPath: pipelinesData.tagsPath, - hasCi: pipelinesData.hasCi, - ciLintPath: pipelinesData.ciLintPath, - state: this.store.state, - apiScope: 'all', - pagenum: 1, - isLoading: false, - hasError: false, - isMakingRequest: false, - updateGraphDropdown: false, - hasMadeRequest: false, - }; - }, - - computed: { - canCreatePipelineParsed() { - return gl.utils.convertPermissionToBoolean(this.canCreatePipeline); - }, - - scope() { - const scope = gl.utils.getParameterByName('scope'); - return scope === null ? 'all' : scope; - }, - - shouldRenderErrorState() { - return this.hasError && !this.isLoading; - }, - - /** - * The empty state should only be rendered when the request is made to fetch all pipelines - * and none is returned. - * - * @return {Boolean} - */ - shouldRenderEmptyState() { - return !this.isLoading && - !this.hasError && - this.hasMadeRequest && - !this.state.pipelines.length && - (this.scope === 'all' || this.scope === null); - }, - - /** - * When a specific scope does not have pipelines we render a message. - * - * @return {Boolean} - */ - shouldRenderNoPipelinesMessage() { - return !this.isLoading && - !this.hasError && - !this.state.pipelines.length && - this.scope !== 'all' && - this.scope !== null; - }, - - shouldRenderTable() { - return !this.hasError && - !this.isLoading && this.state.pipelines.length; - }, - - /** - * Pagination should only be rendered when there is more than one page. - * - * @return {Boolean} - */ - shouldRenderPagination() { - return !this.isLoading && - this.state.pipelines.length && - this.state.pageInfo.total > this.state.pageInfo.perPage; - }, - - hasCiEnabled() { - return this.hasCi !== undefined; - }, - - paths() { - return { - allPath: this.allPath, - pendingPath: this.pendingPath, - finishedPath: this.finishedPath, - runningPath: this.runningPath, - branchesPath: this.branchesPath, - tagsPath: this.tagsPath, - }; - }, - - pageParameter() { - return gl.utils.getParameterByName('page') || this.pagenum; - }, - - scopeParameter() { - return gl.utils.getParameterByName('scope') || this.apiScope; - }, - }, - - created() { - this.service = new PipelinesService(this.endpoint); - - const poll = new Poll({ - resource: this.service, - method: 'getPipelines', - data: { page: this.pageParameter, scope: this.scopeParameter }, - successCallback: this.successCallback, - errorCallback: this.errorCallback, - notificationCallback: this.setIsMakingRequest, - }); - - if (!Visibility.hidden()) { - this.isLoading = true; - poll.makeRequest(); - } else { - // If tab is not visible we need to make the first request so we don't show the empty - // state without knowing if there are any pipelines - this.fetchPipelines(); - } - - Visibility.change(() => { - if (!Visibility.hidden()) { - poll.restart(); - } else { - poll.stop(); - } - }); - - eventHub.$on('refreshPipelines', this.fetchPipelines); - }, - - beforeDestroy() { - eventHub.$off('refreshPipelines'); - }, - - methods: { - /** - * Will change the page number and update the URL. - * - * @param {Number} pageNumber desired page to go to. - */ - change(pageNumber) { - const param = gl.utils.setParamInURL('page', pageNumber); - - gl.utils.visitUrl(param); - return param; - }, - - fetchPipelines() { - if (!this.isMakingRequest) { - this.isLoading = true; - - this.service.getPipelines({ scope: this.scopeParameter, page: this.pageParameter }) - .then(response => this.successCallback(response)) - .catch(() => this.errorCallback()); - } - }, - - successCallback(resp) { - const response = { - headers: resp.headers, - body: resp.json(), - }; - - this.store.storeCount(response.body.count); - this.store.storePipelines(response.body.pipelines); - this.store.storePagination(response.headers); - - this.isLoading = false; - this.updateGraphDropdown = true; - this.hasMadeRequest = true; - }, - - errorCallback() { - this.hasError = true; - this.isLoading = false; - this.updateGraphDropdown = false; - }, - - setIsMakingRequest(isMakingRequest) { - this.isMakingRequest = isMakingRequest; - - if (isMakingRequest) { - this.updateGraphDropdown = false; - } - }, - }, - - template: ` - <div :class="cssClass"> - - <div - class="top-area scrolling-tabs-container inner-page-scroll-tabs" - v-if="!isLoading && !shouldRenderEmptyState"> - <div class="fade-left"> - <i class="fa fa-angle-left" aria-hidden="true"></i> - </div> - <div class="fade-right"> - <i class="fa fa-angle-right" aria-hidden="true"></i> - </div> - <navigation-tabs - :scope="scope" - :count="state.count" - :paths="paths" /> - - <navigation-controls - :new-pipeline-path="newPipelinePath" - :has-ci-enabled="hasCiEnabled" - :help-page-path="helpPagePath" - :ciLintPath="ciLintPath" - :can-create-pipeline="canCreatePipelineParsed " /> - </div> - - <div class="content-list pipelines"> - - <loading-icon - label="Loading Pipelines" - size="3" - v-if="isLoading" - /> - - <empty-state - v-if="shouldRenderEmptyState" - :help-page-path="helpPagePath" /> - - <error-state v-if="shouldRenderErrorState" /> - - <div - class="blank-state blank-state-no-icon" - v-if="shouldRenderNoPipelinesMessage"> - <h2 class="blank-state-title js-blank-state-title">No pipelines to show.</h2> - </div> - - <div - class="table-holder" - v-if="shouldRenderTable"> - - <pipelines-table-component - :pipelines="state.pipelines" - :service="service" - :update-graph-dropdown="updateGraphDropdown" - /> - </div> - - <table-pagination - v-if="shouldRenderPagination" - :change="change" - :pageInfo="state.pageInfo" - /> - </div> - </div> - `, -}; diff --git a/app/assets/javascripts/pipelines/pipelines_bundle.js b/app/assets/javascripts/pipelines/pipelines_bundle.js new file mode 100644 index 00000000000..923d9bfb248 --- /dev/null +++ b/app/assets/javascripts/pipelines/pipelines_bundle.js @@ -0,0 +1,24 @@ +import Vue from 'vue'; +import PipelinesStore from './stores/pipelines_store'; +import pipelinesComponent from './components/pipelines.vue'; + +document.addEventListener('DOMContentLoaded', () => new Vue({ + el: '#pipelines-list-vue', + data() { + const store = new PipelinesStore(); + + return { + store, + }; + }, + components: { + pipelinesComponent, + }, + render(createElement) { + return createElement('pipelines-component', { + props: { + store: this.store, + }, + }); + }, +})); diff --git a/app/assets/javascripts/vue_shared/components/commit.js b/app/assets/javascripts/vue_shared/components/commit.js deleted file mode 100644 index ff5ae28e062..00000000000 --- a/app/assets/javascripts/vue_shared/components/commit.js +++ /dev/null @@ -1,159 +0,0 @@ -import commitIconSvg from 'icons/_icon_commit.svg'; -import userAvatarLink from './user_avatar/user_avatar_link.vue'; - -export default { - props: { - /** - * Indicates the existance of a tag. - * Used to render the correct icon, if true will render `fa-tag` icon, - * if false will render `fa-code-fork` icon. - */ - tag: { - type: Boolean, - required: false, - default: false, - }, - - /** - * If provided is used to render the branch name and url. - * Should contain the following properties: - * name - * ref_url - */ - commitRef: { - type: Object, - required: false, - default: () => ({}), - }, - - /** - * Used to link to the commit sha. - */ - commitUrl: { - type: String, - required: false, - default: '', - }, - - /** - * Used to show the commit short sha that links to the commit url. - */ - shortSha: { - type: String, - required: false, - default: '', - }, - - /** - * If provided shows the commit tile. - */ - title: { - type: String, - required: false, - default: '', - }, - - /** - * If provided renders information about the author of the commit. - * When provided should include: - * `avatar_url` to render the avatar icon - * `web_url` to link to user profile - * `username` to render alt and title tags - */ - author: { - type: Object, - required: false, - default: () => ({}), - }, - }, - - computed: { - /** - * Used to verify if all the properties needed to render the commit - * ref section were provided. - * - * TODO: Improve this! Use lodash _.has when we have it. - * - * @returns {Boolean} - */ - hasCommitRef() { - return this.commitRef && this.commitRef.name && this.commitRef.ref_url; - }, - - /** - * Used to verify if all the properties needed to render the commit - * author section were provided. - * - * TODO: Improve this! Use lodash _.has when we have it. - * - * @returns {Boolean} - */ - hasAuthor() { - return this.author && - this.author.avatar_url && - this.author.path && - this.author.username; - }, - - /** - * If information about the author is provided will return a string - * to be rendered as the alt attribute of the img tag. - * - * @returns {String} - */ - userImageAltDescription() { - return this.author && - this.author.username ? `${this.author.username}'s avatar` : null; - }, - }, - - data() { - return { commitIconSvg }; - }, - - components: { - userAvatarLink, - }, - template: ` - <div class="branch-commit"> - - <div v-if="hasCommitRef" class="icon-container"> - <i v-if="tag" class="fa fa-tag"></i> - <i v-if="!tag" class="fa fa-code-fork"></i> - </div> - - <a v-if="hasCommitRef" - class="ref-name" - :href="commitRef.ref_url"> - {{commitRef.name}} - </a> - - <div v-html="commitIconSvg" class="commit-icon js-commit-icon"></div> - - <a class="commit-sha" - :href="commitUrl"> - {{shortSha}} - </a> - - <div class="commit-title flex-truncate-parent"> - <span v-if="title" class="flex-truncate-child"> - <user-avatar-link - v-if="hasAuthor" - class="avatar-image-container" - :link-href="author.path" - :img-src="author.avatar_url" - :img-alt="userImageAltDescription" - :tooltip-text="author.username" - /> - <a class="commit-row-message" - :href="commitUrl"> - {{title}} - </a> - </span> - <span v-else> - Cant find HEAD commit for this branch - </span> - </div> - </div> - `, -}; diff --git a/app/assets/javascripts/vue_shared/components/commit.vue b/app/assets/javascripts/vue_shared/components/commit.vue new file mode 100644 index 00000000000..fcf48b11057 --- /dev/null +++ b/app/assets/javascripts/vue_shared/components/commit.vue @@ -0,0 +1,166 @@ +<script> + import commitIconSvg from 'icons/_icon_commit.svg'; + import userAvatarLink from './user_avatar/user_avatar_link.vue'; + + export default { + props: { + /** + * Indicates the existance of a tag. + * Used to render the correct icon, if true will render `fa-tag` icon, + * if false will render `fa-code-fork` icon. + */ + tag: { + type: Boolean, + required: false, + default: false, + }, + /** + * If provided is used to render the branch name and url. + * Should contain the following properties: + * name + * ref_url + */ + commitRef: { + type: Object, + required: false, + default: () => ({}), + }, + /** + * Used to link to the commit sha. + */ + commitUrl: { + type: String, + required: false, + default: '', + }, + + /** + * Used to show the commit short sha that links to the commit url. + */ + shortSha: { + type: String, + required: false, + default: '', + }, + /** + * If provided shows the commit tile. + */ + title: { + type: String, + required: false, + default: '', + }, + /** + * If provided renders information about the author of the commit. + * When provided should include: + * `avatar_url` to render the avatar icon + * `web_url` to link to user profile + * `username` to render alt and title tags + */ + author: { + type: Object, + required: false, + default: () => ({}), + }, + }, + computed: { + /** + * Used to verify if all the properties needed to render the commit + * ref section were provided. + * + * TODO: Improve this! Use lodash _.has when we have it. + * + * @returns {Boolean} + */ + hasCommitRef() { + return this.commitRef && this.commitRef.name && this.commitRef.ref_url; + }, + /** + * Used to verify if all the properties needed to render the commit + * author section were provided. + * + * TODO: Improve this! Use lodash _.has when we have it. + * + * @returns {Boolean} + */ + hasAuthor() { + return this.author && + this.author.avatar_url && + this.author.path && + this.author.username; + }, + /** + * If information about the author is provided will return a string + * to be rendered as the alt attribute of the img tag. + * + * @returns {String} + */ + userImageAltDescription() { + return this.author && + this.author.username ? `${this.author.username}'s avatar` : null; + }, + }, + data() { + return { commitIconSvg }; + }, + components: { + userAvatarLink, + }, + }; +</script> +<template> + <div class="branch-commit"> + <div v-if="hasCommitRef" class="icon-container"> + <i + v-if="tag" + class="fa fa-tag" + aria-hidden="true"> + </i> + <i + v-if="!tag" + class="fa fa-code-fork" + aria-hidden="true"> + </i> + </div> + + <a + v-if="hasCommitRef" + class="ref-name" + :href="commitRef.ref_url"> + {{commitRef.name}} + </a> + + <div + v-html="commitIconSvg" + class="commit-icon js-commit-icon"> + </div> + + <a + class="commit-sha" + :href="commitUrl"> + {{shortSha}} + </a> + + <div class="commit-title flex-truncate-parent"> + <span + v-if="title" + class="flex-truncate-child"> + <user-avatar-link + v-if="hasAuthor" + class="avatar-image-container" + :link-href="author.path" + :img-src="author.avatar_url" + :img-alt="userImageAltDescription" + :tooltip-text="author.username" + /> + <a class="commit-row-message" + :href="commitUrl"> + {{title}} + </a> + </span> + <span v-else> + Cant find HEAD commit for this branch + </span> + </div> + </div> +</template> diff --git a/app/assets/javascripts/vue_shared/components/pipelines_table.js b/app/assets/javascripts/vue_shared/components/pipelines_table.js deleted file mode 100644 index 48a39f18112..00000000000 --- a/app/assets/javascripts/vue_shared/components/pipelines_table.js +++ /dev/null @@ -1,55 +0,0 @@ -import PipelinesTableRowComponent from './pipelines_table_row'; - -/** - * Pipelines Table Component. - * - * Given an array of objects, renders a table. - */ -export default { - props: { - pipelines: { - type: Array, - required: true, - }, - - service: { - type: Object, - required: true, - }, - - updateGraphDropdown: { - type: Boolean, - required: false, - default: false, - }, - }, - - components: { - 'pipelines-table-row-component': PipelinesTableRowComponent, - }, - - template: ` - <table class="table ci-table"> - <thead> - <tr> - <th class="js-pipeline-status pipeline-status">Status</th> - <th class="js-pipeline-info pipeline-info">Pipeline</th> - <th class="js-pipeline-commit pipeline-commit">Commit</th> - <th class="js-pipeline-stages pipeline-stages">Stages</th> - <th class="js-pipeline-date pipeline-date"></th> - <th class="js-pipeline-actions pipeline-actions"></th> - </tr> - </thead> - <tbody> - <template v-for="model in pipelines" - v-bind:model="model"> - <tr is="pipelines-table-row-component" - :pipeline="model" - :service="service" - :update-graph-dropdown="updateGraphDropdown" - /> - </template> - </tbody> - </table> - `, -}; diff --git a/app/assets/javascripts/vue_shared/components/pipelines_table.vue b/app/assets/javascripts/vue_shared/components/pipelines_table.vue new file mode 100644 index 00000000000..ebe8fba8a44 --- /dev/null +++ b/app/assets/javascripts/vue_shared/components/pipelines_table.vue @@ -0,0 +1,55 @@ +<script> + import pipelinesTableRowComponent from './pipelines_table_row.vue'; + + /** + * Pipelines Table Component. + * + * Given an array of objects, renders a table. + */ + export default { + props: { + pipelines: { + type: Array, + required: true, + }, + service: { + type: Object, + required: true, + }, + updateGraphDropdown: { + type: Boolean, + required: false, + default: false, + }, + }, + components: { + pipelinesTableRowComponent, + }, + }; +</script> +<template> + <table class="table ci-table"> + <thead> + <tr> + <th class="js-pipeline-status pipeline-status">Status</th> + <th class="js-pipeline-info pipeline-info">Pipeline</th> + <th class="js-pipeline-commit pipeline-commit">Commit</th> + <th class="js-pipeline-stages pipeline-stages">Stages</th> + <th class="js-pipeline-date pipeline-date"></th> + <th class="js-pipeline-actions pipeline-actions"></th> + </tr> + </thead> + <tbody> + <template + v-for="model in pipelines" + :model="model"> + <tr + is="pipelines-table-row-component" + :pipeline="model" + :service="service" + :update-graph-dropdown="updateGraphDropdown" + /> + </template> + </tbody> + </table> +</template> diff --git a/app/assets/javascripts/vue_shared/components/pipelines_table_row.js b/app/assets/javascripts/vue_shared/components/pipelines_table_row.vue index f60f8eeb43d..33b3375deff 100644 --- a/app/assets/javascripts/vue_shared/components/pipelines_table_row.js +++ b/app/assets/javascripts/vue_shared/components/pipelines_table_row.vue @@ -1,12 +1,13 @@ +<script> /* eslint-disable no-param-reassign */ -import AsyncButtonComponent from '../../pipelines/components/async_button.vue'; -import PipelinesActionsComponent from '../../pipelines/components/pipelines_actions'; -import PipelinesArtifactsComponent from '../../pipelines/components/pipelines_artifacts'; +import asyncButtonComponent from '../../pipelines/components/async_button.vue'; +import pipelinesActionsComponent from '../../pipelines/components/pipelines_actions.vue'; +import pipelinesArtifactsComponent from '../../pipelines/components/pipelines_artifacts.vue'; import ciBadge from './ci_badge_link.vue'; -import PipelinesStageComponent from '../../pipelines/components/stage.vue'; -import PipelinesUrlComponent from '../../pipelines/components/pipeline_url.vue'; -import PipelinesTimeagoComponent from '../../pipelines/components/time_ago'; -import CommitComponent from './commit'; +import pipelineStage from '../../pipelines/components/stage.vue'; +import pipelineUrl from '../../pipelines/components/pipeline_url.vue'; +import pipelinesTimeago from '../../pipelines/components/time_ago.vue'; +import commitComponent from './commit.vue'; /** * Pipeline table row. @@ -19,30 +20,26 @@ export default { type: Object, required: true, }, - service: { type: Object, required: true, }, - updateGraphDropdown: { type: Boolean, required: false, default: false, }, }, - components: { - 'async-button-component': AsyncButtonComponent, - 'pipelines-actions-component': PipelinesActionsComponent, - 'pipelines-artifacts-component': PipelinesArtifactsComponent, - 'commit-component': CommitComponent, - 'dropdown-stage': PipelinesStageComponent, - 'pipeline-url': PipelinesUrlComponent, + asyncButtonComponent, + pipelinesActionsComponent, + pipelinesArtifactsComponent, + commitComponent, + pipelineStage, + pipelineUrl, ciBadge, - 'time-ago': PipelinesTimeagoComponent, + pipelinesTimeago, }, - computed: { /** * If provided, returns the commit tag. @@ -204,69 +201,76 @@ export default { return {}; }, }, +}; +</script> +<template> + <tr class="commit"> + <td class="commit-link"> + <ci-badge :status="pipelineStatus" /> + </td> - template: ` - <tr class="commit"> - <td class="commit-link"> - <ci-badge :status="pipelineStatus"/> - </td> - - <pipeline-url :pipeline="pipeline"></pipeline-url> + <pipeline-url :pipeline="pipeline" /> - <td> - <commit-component - :tag="commitTag" - :commit-ref="commitRef" - :commit-url="commitUrl" - :short-sha="commitShortSha" - :title="commitTitle" - :author="commitAuthor"/> - </td> + <td> + <commit-component + :tag="commitTag" + :commit-ref="commitRef" + :commit-url="commitUrl" + :short-sha="commitShortSha" + :title="commitTitle" + :author="commitAuthor" + /> + </td> - <td class="stage-cell"> - <div class="stage-container dropdown js-mini-pipeline-graph" - v-if="pipeline.details.stages.length > 0" - v-for="stage in pipeline.details.stages"> + <td class="stage-cell"> + <div class="stage-container dropdown js-mini-pipeline-graph" + v-if="pipeline.details.stages.length > 0" + v-for="stage in pipeline.details.stages"> - <dropdown-stage - :stage="stage" - :update-dropdown="updateGraphDropdown"/> - </div> - </td> + <pipeline-stage + :stage="stage" + :update-dropdown="updateGraphDropdown" + /> + </div> + </td> - <time-ago - :duration="pipelineDuration" - :finished-time="pipelineFinishedAt" /> + <pipelines-timeago + :duration="pipelineDuration" + :finished-time="pipelineFinishedAt" + /> - <td class="pipeline-actions"> - <div class="pull-right btn-group"> - <pipelines-actions-component - v-if="pipeline.details.manual_actions.length" - :actions="pipeline.details.manual_actions" - :service="service" /> + <td class="pipeline-actions"> + <div class="pull-right btn-group"> + <pipelines-actions-component + v-if="pipeline.details.manual_actions.length" + :actions="pipeline.details.manual_actions" + :service="service" + /> - <pipelines-artifacts-component - v-if="pipeline.details.artifacts.length" - :artifacts="pipeline.details.artifacts" /> + <pipelines-artifacts-component + v-if="pipeline.details.artifacts.length" + :artifacts="pipeline.details.artifacts" + /> - <async-button-component - v-if="pipeline.flags.retryable" - :service="service" - :endpoint="pipeline.retry_path" - css-class="js-pipelines-retry-button btn-default btn-retry" - title="Retry" - icon="repeat" /> + <async-button-component + v-if="pipeline.flags.retryable" + :service="service" + :endpoint="pipeline.retry_path" + css-class="js-pipelines-retry-button btn-default btn-retry" + title="Retry" + icon="repeat" + /> - <async-button-component - v-if="pipeline.flags.cancelable" - :service="service" - :endpoint="pipeline.cancel_path" - css-class="js-pipelines-cancel-button btn-remove" - title="Cancel" - icon="remove" - confirm-action-message="Are you sure you want to cancel this pipeline?" /> - </div> - </td> - </tr> - `, -}; + <async-button-component + v-if="pipeline.flags.cancelable" + :service="service" + :endpoint="pipeline.cancel_path" + css-class="js-pipelines-cancel-button btn-remove" + title="Cancel" + icon="remove" + confirm-action-message="Are you sure you want to cancel this pipeline?" + /> + </div> + </td> + </tr> +</template> diff --git a/app/assets/stylesheets/framework/selects.scss b/app/assets/stylesheets/framework/selects.scss index 5ae833cd5f6..1b20c35ad98 100644 --- a/app/assets/stylesheets/framework/selects.scss +++ b/app/assets/stylesheets/framework/selects.scss @@ -109,10 +109,12 @@ line-height: 15px; background-color: $gray-light; background-image: none; + padding: 3px 18px 3px 5px; .select2-search-choice-close { - top: 4px; - left: 3px; + top: 5px; + left: initial; + right: 3px; } &.select2-search-choice-focus { diff --git a/app/assets/stylesheets/framework/tw_bootstrap_variables.scss b/app/assets/stylesheets/framework/tw_bootstrap_variables.scss index c9f345d24be..b666223b120 100644 --- a/app/assets/stylesheets/framework/tw_bootstrap_variables.scss +++ b/app/assets/stylesheets/framework/tw_bootstrap_variables.scss @@ -74,9 +74,9 @@ $pagination-hover-color: $gl-text-color; $pagination-hover-bg: $row-hover; $pagination-hover-border: $border-color; -$pagination-active-color: $blue-600; -$pagination-active-bg: $white-light; -$pagination-active-border: $border-color; +$pagination-active-color: $white-light; +$pagination-active-bg: $gl-link-color; +$pagination-active-border: $gl-link-color; $pagination-disabled-color: #cdcdcd; $pagination-disabled-bg: $gray-light; diff --git a/app/assets/stylesheets/pages/events.scss b/app/assets/stylesheets/pages/events.scss index 5b723f7c722..4c3fa1fb8d4 100644 --- a/app/assets/stylesheets/pages/events.scss +++ b/app/assets/stylesheets/pages/events.scss @@ -89,7 +89,6 @@ background: $gray-light; border-radius: 0; color: $events-pre-color; - margin: 0 20px; overflow: hidden; } diff --git a/app/controllers/admin/application_settings_controller.rb b/app/controllers/admin/application_settings_controller.rb index 75fb19e815f..4d4b8a8425f 100644 --- a/app/controllers/admin/application_settings_controller.rb +++ b/app/controllers/admin/application_settings_controller.rb @@ -100,6 +100,8 @@ class Admin::ApplicationSettingsController < Admin::ApplicationController :enabled_git_access_protocol, :gravatar_enabled, :help_page_text, + :help_page_hide_commercial_content, + :help_page_support_url, :home_page_url, :housekeeping_bitmaps_enabled, :housekeeping_enabled, diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index 71154da7ec5..2bfc7586adc 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -204,6 +204,10 @@ module ApplicationHelper 'https://' + promo_host end + def support_url + current_application_settings.help_page_support_url.presence || promo_url + '/getting-help/' + end + def page_filter_path(options = {}) without = options.delete(:without) add_label = options.delete(:label) diff --git a/app/helpers/diff_helper.rb b/app/helpers/diff_helper.rb index 2ae3a616933..06822747d11 100644 --- a/app/helpers/diff_helper.rb +++ b/app/helpers/diff_helper.rb @@ -124,6 +124,30 @@ module DiffHelper !diff_file.deleted_file? && @merge_request && @merge_request.source_project end + def diff_render_error_reason(viewer) + case viewer.render_error + when :too_large + "it is too large" + when :server_side_but_stored_externally + case viewer.diff_file.external_storage + when :lfs + 'it is stored in LFS' + else + 'it is stored externally' + end + end + end + + def diff_render_error_options(viewer) + diff_file = viewer.diff_file + options = [] + + blob_url = namespace_project_blob_path(@project.namespace, @project, tree_join(diff_file.content_sha, diff_file.file_path)) + options << link_to('view the blob', blob_url) + + options + end + private def diff_btn(title, name, selected) diff --git a/app/models/application_setting.rb b/app/models/application_setting.rb index 2192f76499d..668caef0d2c 100644 --- a/app/models/application_setting.rb +++ b/app/models/application_setting.rb @@ -37,7 +37,12 @@ class ApplicationSetting < ActiveRecord::Base validates :home_page_url, allow_blank: true, url: true, - if: :home_page_url_column_exist + if: :home_page_url_column_exists? + + validates :help_page_support_url, + allow_blank: true, + url: true, + if: :help_page_support_url_column_exists? validates :after_sign_out_path, allow_blank: true, @@ -215,6 +220,7 @@ class ApplicationSetting < ActiveRecord::Base domain_whitelist: Settings.gitlab['domain_whitelist'], gravatar_enabled: Settings.gravatar['enabled'], help_page_text: nil, + help_page_hide_commercial_content: false, unique_ips_limit_per_user: 10, unique_ips_limit_time_window: 3600, unique_ips_limit_enabled: false, @@ -263,10 +269,14 @@ class ApplicationSetting < ActiveRecord::Base end end - def home_page_url_column_exist + def home_page_url_column_exists? ActiveRecord::Base.connection.column_exists?(:application_settings, :home_page_url) end + def help_page_support_url_column_exists? + ActiveRecord::Base.connection.column_exists?(:application_settings, :help_page_support_url) + end + def sidekiq_throttling_column_exists? ActiveRecord::Base.connection.column_exists?(:application_settings, :sidekiq_throttling_enabled) end diff --git a/app/models/blob_viewer/server_side.rb b/app/models/blob_viewer/server_side.rb index e6bcacf7f70..fbc1b520c01 100644 --- a/app/models/blob_viewer/server_side.rb +++ b/app/models/blob_viewer/server_side.rb @@ -13,14 +13,12 @@ module BlobViewer end def render_error - if blob.stored_externally? - # Files that are not stored in the repository, like LFS files and - # build artifacts, can only be rendered using a client-side viewer, - # since we do not want to read large amounts of data into memory on the - # server side. Client-side viewers use JS and can fetch the file from - # `blob_raw_url` using AJAX. - return :server_side_but_stored_externally - end + # Files that are not stored in the repository, like LFS files and + # build artifacts, can only be rendered using a client-side viewer, + # since we do not want to read large amounts of data into memory on the + # server side. Client-side viewers use JS and can fetch the file from + # `blob_raw_url` using AJAX. + return :server_side_but_stored_externally if blob.stored_externally? super end diff --git a/app/models/diff_viewer/added.rb b/app/models/diff_viewer/added.rb new file mode 100644 index 00000000000..1909e6ef9d8 --- /dev/null +++ b/app/models/diff_viewer/added.rb @@ -0,0 +1,8 @@ +module DiffViewer + class Added < Base + include Simple + include Static + + self.partial_name = 'added' + end +end diff --git a/app/models/diff_viewer/base.rb b/app/models/diff_viewer/base.rb new file mode 100644 index 00000000000..0cbe714288d --- /dev/null +++ b/app/models/diff_viewer/base.rb @@ -0,0 +1,87 @@ +module DiffViewer + class Base + PARTIAL_PATH_PREFIX = 'projects/diffs/viewers'.freeze + + class_attribute :partial_name, :type, :extensions, :file_types, :binary, :switcher_icon, :switcher_title + + # These limits relate to the sum of the old and new blob sizes. + # Limits related to the actual size of the diff are enforced in Gitlab::Diff::File. + class_attribute :collapse_limit, :size_limit + + delegate :partial_path, :loading_partial_path, :rich?, :simple?, :text?, :binary?, to: :class + + attr_reader :diff_file + + delegate :project, to: :diff_file + + def initialize(diff_file) + @diff_file = diff_file + @initially_binary = diff_file.binary? + end + + def self.partial_path + File.join(PARTIAL_PATH_PREFIX, partial_name) + end + + def self.rich? + type == :rich + end + + def self.simple? + type == :simple + end + + def self.binary? + binary + end + + def self.text? + !binary? + end + + def self.can_render?(diff_file, verify_binary: true) + can_render_blob?(diff_file.old_blob, verify_binary: verify_binary) && + can_render_blob?(diff_file.new_blob, verify_binary: verify_binary) + end + + def self.can_render_blob?(blob, verify_binary: true) + return true if blob.nil? + return false if verify_binary && binary? != blob.binary? + return true if extensions&.include?(blob.extension) + return true if file_types&.include?(blob.file_type) + + false + end + + def collapsed? + return @collapsed if defined?(@collapsed) + return @collapsed = true if diff_file.collapsed? + + @collapsed = !diff_file.expanded? && collapse_limit && diff_file.raw_size > collapse_limit + end + + def too_large? + return @too_large if defined?(@too_large) + return @too_large = true if diff_file.too_large? + + @too_large = size_limit && diff_file.raw_size > size_limit + end + + def binary_detected_after_load? + !@initially_binary && diff_file.binary? + end + + # This method is used on the server side to check whether we can attempt to + # render the diff_file at all. Human-readable error messages are found in the + # `BlobHelper#diff_render_error_reason` helper. + def render_error + if too_large? + :too_large + end + end + + def prepare! + # To be overridden by subclasses + end + end +end diff --git a/app/models/diff_viewer/client_side.rb b/app/models/diff_viewer/client_side.rb new file mode 100644 index 00000000000..cf41d07f8eb --- /dev/null +++ b/app/models/diff_viewer/client_side.rb @@ -0,0 +1,10 @@ +module DiffViewer + module ClientSide + extend ActiveSupport::Concern + + included do + self.collapse_limit = 1.megabyte + self.size_limit = 10.megabytes + end + end +end diff --git a/app/models/diff_viewer/deleted.rb b/app/models/diff_viewer/deleted.rb new file mode 100644 index 00000000000..9c129bac694 --- /dev/null +++ b/app/models/diff_viewer/deleted.rb @@ -0,0 +1,8 @@ +module DiffViewer + class Deleted < Base + include Simple + include Static + + self.partial_name = 'deleted' + end +end diff --git a/app/models/diff_viewer/image.rb b/app/models/diff_viewer/image.rb new file mode 100644 index 00000000000..759d9a36ebb --- /dev/null +++ b/app/models/diff_viewer/image.rb @@ -0,0 +1,12 @@ +module DiffViewer + class Image < Base + include Rich + include ClientSide + + self.partial_name = 'image' + self.extensions = UploaderHelper::IMAGE_EXT + self.binary = true + self.switcher_icon = 'picture-o' + self.switcher_title = 'image diff' + end +end diff --git a/app/models/diff_viewer/mode_changed.rb b/app/models/diff_viewer/mode_changed.rb new file mode 100644 index 00000000000..d487d996f8d --- /dev/null +++ b/app/models/diff_viewer/mode_changed.rb @@ -0,0 +1,8 @@ +module DiffViewer + class ModeChanged < Base + include Simple + include Static + + self.partial_name = 'mode_changed' + end +end diff --git a/app/models/diff_viewer/no_preview.rb b/app/models/diff_viewer/no_preview.rb new file mode 100644 index 00000000000..5455fee4490 --- /dev/null +++ b/app/models/diff_viewer/no_preview.rb @@ -0,0 +1,9 @@ +module DiffViewer + class NoPreview < Base + include Simple + include Static + + self.partial_name = 'no_preview' + self.binary = true + end +end diff --git a/app/models/diff_viewer/not_diffable.rb b/app/models/diff_viewer/not_diffable.rb new file mode 100644 index 00000000000..4f9638626ea --- /dev/null +++ b/app/models/diff_viewer/not_diffable.rb @@ -0,0 +1,9 @@ +module DiffViewer + class NotDiffable < Base + include Simple + include Static + + self.partial_name = 'not_diffable' + self.binary = true + end +end diff --git a/app/models/diff_viewer/renamed.rb b/app/models/diff_viewer/renamed.rb new file mode 100644 index 00000000000..f1fbfd8c6d5 --- /dev/null +++ b/app/models/diff_viewer/renamed.rb @@ -0,0 +1,8 @@ +module DiffViewer + class Renamed < Base + include Simple + include Static + + self.partial_name = 'renamed' + end +end diff --git a/app/models/diff_viewer/rich.rb b/app/models/diff_viewer/rich.rb new file mode 100644 index 00000000000..3b0ca6e4cff --- /dev/null +++ b/app/models/diff_viewer/rich.rb @@ -0,0 +1,11 @@ +module DiffViewer + module Rich + extend ActiveSupport::Concern + + included do + self.type = :rich + self.switcher_icon = 'file-text-o' + self.switcher_title = 'rendered diff' + end + end +end diff --git a/app/models/diff_viewer/server_side.rb b/app/models/diff_viewer/server_side.rb new file mode 100644 index 00000000000..aed1a0791b1 --- /dev/null +++ b/app/models/diff_viewer/server_side.rb @@ -0,0 +1,26 @@ +module DiffViewer + module ServerSide + extend ActiveSupport::Concern + + included do + self.collapse_limit = 1.megabyte + self.size_limit = 5.megabytes + end + + def prepare! + diff_file.old_blob&.load_all_data! + diff_file.new_blob&.load_all_data! + end + + def render_error + # Files that are not stored in the repository, like LFS files and + # build artifacts, can only be rendered using a client-side viewer, + # since we do not want to read large amounts of data into memory on the + # server side. Client-side viewers use JS and can fetch the file from + # `diff_file_blob_raw_path` and `diff_file_old_blob_raw_path` using AJAX. + return :server_side_but_stored_externally if diff_file.stored_externally? + + super + end + end +end diff --git a/app/models/diff_viewer/simple.rb b/app/models/diff_viewer/simple.rb new file mode 100644 index 00000000000..65750996ee4 --- /dev/null +++ b/app/models/diff_viewer/simple.rb @@ -0,0 +1,11 @@ +module DiffViewer + module Simple + extend ActiveSupport::Concern + + included do + self.type = :simple + self.switcher_icon = 'code' + self.switcher_title = 'source diff' + end + end +end diff --git a/app/models/diff_viewer/static.rb b/app/models/diff_viewer/static.rb new file mode 100644 index 00000000000..d761328b3f6 --- /dev/null +++ b/app/models/diff_viewer/static.rb @@ -0,0 +1,10 @@ +module DiffViewer + module Static + extend ActiveSupport::Concern + + # We can always render a static viewer, even if the diff is too large. + def render_error + nil + end + end +end diff --git a/app/models/diff_viewer/text.rb b/app/models/diff_viewer/text.rb new file mode 100644 index 00000000000..98f4b2aea2a --- /dev/null +++ b/app/models/diff_viewer/text.rb @@ -0,0 +1,15 @@ +module DiffViewer + class Text < Base + include Simple + include ServerSide + + self.partial_name = 'text' + self.binary = false + + # Since the text diff viewer doesn't render the old and new blobs in full, + # we only need the limits related to the actual size of the diff which are + # already enforced in Gitlab::Diff::File. + self.collapse_limit = nil + self.size_limit = nil + end +end diff --git a/app/models/environment.rb b/app/models/environment.rb index 6211a5c1e63..d5b974b2d31 100644 --- a/app/models/environment.rb +++ b/app/models/environment.rb @@ -209,7 +209,8 @@ class Environment < ActiveRecord::Base def etag_cache_key Gitlab::Routing.url_helpers.namespace_project_environments_path( project.namespace, - project) + project, + format: :json) end private diff --git a/app/models/project_services/kubernetes_service.rb b/app/models/project_services/kubernetes_service.rb index 8977a7cdafe..48e7802c557 100644 --- a/app/models/project_services/kubernetes_service.rb +++ b/app/models/project_services/kubernetes_service.rb @@ -116,30 +116,19 @@ class KubernetesService < DeploymentService # short time later def terminals(environment) with_reactive_cache do |data| - pods = data.fetch(:pods, nil) - filter_pods(pods, app: environment.slug). - flat_map { |pod| terminals_for_pod(api_url, actual_namespace, pod) }. - each { |terminal| add_terminal_auth(terminal, terminal_auth) } + pods = filter_by_label(data[:pods], app: environment.slug) + terminals = pods.flat_map { |pod| terminals_for_pod(api_url, actual_namespace, pod) } + terminals.each { |terminal| add_terminal_auth(terminal, terminal_auth) } end end - # Caches all pods in the namespace so other calls don't need to block on - # network access. + # Caches resources in the namespace so other calls don't need to block on + # network access def calculate_reactive_cache return unless active? && project && !project.pending_delete? - kubeclient = build_kubeclient! - - # Store as hashes, rather than as third-party types - pods = begin - kubeclient.get_pods(namespace: actual_namespace).as_json - rescue KubeException => err - raise err unless err.error_code == 404 - [] - end - # We may want to cache extra things in the future - { pods: pods } + { pods: read_pods } end TEMPLATE_PLACEHOLDER = 'Kubernetes namespace'.freeze @@ -166,6 +155,16 @@ class KubernetesService < DeploymentService ) end + # Returns a hash of all pods in the namespace + def read_pods + kubeclient = build_kubeclient! + + kubeclient.get_pods(namespace: actual_namespace).as_json + rescue KubeException => err + raise err unless err.error_code == 404 + [] + end + def kubeclient_ssl_options opts = { verify_ssl: OpenSSL::SSL::VERIFY_PEER } @@ -181,11 +180,11 @@ class KubernetesService < DeploymentService { bearer_token: token } end - def join_api_url(*parts) + def join_api_url(api_path) url = URI.parse(api_url) prefix = url.path.sub(%r{/+\z}, '') - url.path = [prefix, *parts].join("/") + url.path = [prefix, api_path].join("/") url.to_s end diff --git a/app/serializers/build_details_entity.rb b/app/serializers/build_details_entity.rb index cb6d3dfec89..eeb5399aa8b 100644 --- a/app/serializers/build_details_entity.rb +++ b/app/serializers/build_details_entity.rb @@ -25,7 +25,7 @@ class BuildDetailsEntity < JobEntity end expose :raw_path do |build| - raw_namespace_project_build_path(project.namespace, project, build) + raw_namespace_project_job_path(project.namespace, project, build) end private diff --git a/app/services/slash_commands/interpret_service.rb b/app/services/slash_commands/interpret_service.rb index b6b411d2185..83144b1e011 100644 --- a/app/services/slash_commands/interpret_service.rb +++ b/app/services/slash_commands/interpret_service.rb @@ -410,7 +410,7 @@ module SlashCommands params '@user' command :cc - desc 'Define target branch for MR' + desc 'Set target branch' explanation do |branch_name| "Sets target branch to #{branch_name}." end diff --git a/app/views/admin/application_settings/_form.html.haml b/app/views/admin/application_settings/_form.html.haml index d552704df88..0383c7ce546 100644 --- a/app/views/admin/application_settings/_form.html.haml +++ b/app/views/admin/application_settings/_form.html.haml @@ -180,11 +180,25 @@ .col-sm-10 = f.text_area :sign_in_text, class: 'form-control', rows: 4 .help-block Markdown enabled + + %fieldset + %legend Help Page .form-group = f.label :help_page_text, class: 'control-label col-sm-2' .col-sm-10 = f.text_area :help_page_text, class: 'form-control', rows: 4 .help-block Markdown enabled + .form-group + .col-sm-offset-2.col-sm-10 + .checkbox + = f.label :help_page_hide_commercial_content do + = f.check_box :help_page_hide_commercial_content + Hide marketing-related entries from help + .form-group + = f.label :help_page_support_url, 'Support page URL', class: 'control-label col-sm-2' + .col-sm-10 + = f.text_field :help_page_support_url, class: 'form-control', placeholder: 'http://company.example.com/getting-help', :'aria-describedby' => 'support_help_block' + %span.help-block#support_help_block Alternate support URL for help page %fieldset %legend Pages diff --git a/app/views/help/index.html.haml b/app/views/help/index.html.haml index 31d0e589c26..c25eae63eec 100644 --- a/app/views/help/index.html.haml +++ b/app/views/help/index.html.haml @@ -1,4 +1,9 @@ %div +- if current_application_settings.help_page_text.present? + = markdown_field(current_application_settings, :help_page_text) + %hr + +- unless current_application_settings.help_page_hide_commercial_content? %h1 GitLab Community Edition @@ -18,13 +23,9 @@ Used by more than 100,000 organizations, GitLab is the most popular solution to manage git repositories on-premises. %br Read more about GitLab at #{link_to promo_host, promo_url, target: '_blank', rel: 'noopener noreferrer'}. - - if current_application_settings.help_page_text.present? - %hr - = markdown_field(current_application_settings, :help_page_text) - -%hr + %hr -.row +.row.prepend-top-default .col-md-8 .documentation-index = markdown(@help_index) @@ -33,8 +34,9 @@ .panel-heading Quick help %ul.well-list - %li= link_to 'See our website for getting help', promo_url + '/getting-help/' + %li= link_to 'See our website for getting help', support_url %li= link_to 'Use the search bar on the top of this page', '#', onclick: 'Shortcuts.focusSearch(event)' %li= link_to 'Use shortcuts', '#', onclick: 'Shortcuts.toggleHelp()' - %li= link_to 'Get a support subscription', 'https://about.gitlab.com/pricing/' - %li= link_to 'Compare GitLab editions', 'https://about.gitlab.com/features/#compare' + - unless current_application_settings.help_page_hide_commercial_content? + %li= link_to 'Get a support subscription', 'https://about.gitlab.com/pricing/' + %li= link_to 'Compare GitLab editions', 'https://about.gitlab.com/features/#compare' diff --git a/app/views/help/show.html.haml b/app/views/help/show.html.haml index f6ebd76af9d..c07c148a12a 100644 --- a/app/views/help/show.html.haml +++ b/app/views/help/show.html.haml @@ -1,3 +1,3 @@ - page_title @path.split("/").reverse.map(&:humanize) -.documentation.wiki +.documentation.wiki.prepend-top-default = markdown @markdown diff --git a/app/views/projects/diffs/_collapsed.html.haml b/app/views/projects/diffs/_collapsed.html.haml new file mode 100644 index 00000000000..8772bd4705f --- /dev/null +++ b/app/views/projects/diffs/_collapsed.html.haml @@ -0,0 +1,5 @@ +- diff_file = viewer.diff_file +- url = url_for(params.merge(action: :diff_for_path, old_path: diff_file.old_path, new_path: diff_file.new_path, file_identifier: diff_file.file_identifier)) +.nothing-here-block.diff-collapsed{ data: { diff_for_path: url } } + This diff is collapsed. + %a.click-to-expand Click to expand it. diff --git a/app/views/projects/diffs/_content.html.haml b/app/views/projects/diffs/_content.html.haml index ec1c434a4b8..68f74f702ea 100644 --- a/app/views/projects/diffs/_content.html.haml +++ b/app/views/projects/diffs/_content.html.haml @@ -1,27 +1,2 @@ -- blob = diff_file.blob - .diff-content - - if diff_file.too_large? - .nothing-here-block This diff could not be displayed because it is too large. - - elsif blob.truncated? - .nothing-here-block The file could not be displayed because it is too large. - - elsif blob.readable_text? - - if !diff_file.diffable? - .nothing-here-block This diff was suppressed by a .gitattributes entry. - - elsif diff_file.collapsed? - - url = url_for(params.merge(action: :diff_for_path, old_path: diff_file.old_path, new_path: diff_file.new_path, file_identifier: diff_file.file_identifier)) - .nothing-here-block.diff-collapsed{ data: { diff_for_path: url } } - This diff is collapsed. - %a.click-to-expand - Click to expand it. - - elsif diff_file.diff_lines.length > 0 - = render "projects/diffs/viewers/text", diff_file: diff_file - - else - - if diff_file.mode_changed? - .nothing-here-block File mode changed - - elsif diff_file.renamed_file? - .nothing-here-block File moved - - elsif blob.image? - = render "projects/diffs/viewers/image", diff_file: diff_file - - else - .nothing-here-block No preview for this file type + = render 'projects/diffs/viewer', viewer: diff_file.rich_viewer || diff_file.simple_viewer diff --git a/app/views/projects/diffs/_render_error.html.haml b/app/views/projects/diffs/_render_error.html.haml new file mode 100644 index 00000000000..47a9ac3ee6b --- /dev/null +++ b/app/views/projects/diffs/_render_error.html.haml @@ -0,0 +1,6 @@ +.nothing-here-block + This #{viewer.switcher_title} could not be displayed because #{diff_render_error_reason(viewer)}. + + You can + = diff_render_error_options(viewer).to_sentence(two_words_connector: ' or ', last_word_connector: ', or ').html_safe + instead. diff --git a/app/views/projects/diffs/_viewer.html.haml b/app/views/projects/diffs/_viewer.html.haml new file mode 100644 index 00000000000..5c4d1760871 --- /dev/null +++ b/app/views/projects/diffs/_viewer.html.haml @@ -0,0 +1,16 @@ +- hidden = local_assigns.fetch(:hidden, false) + +.diff-viewer{ data: { type: viewer.type }, class: ('hidden' if hidden) } + - if viewer.render_error + = render 'projects/diffs/render_error', viewer: viewer + - elsif viewer.collapsed? + = render 'projects/diffs/collapsed', viewer: viewer + - else + - viewer.prepare! + + -# In the rare case where the first kilobyte of the file looks like text, + -# but the file turns out to actually be binary after loading all data, + -# we fall back on the binary No Preview viewer. + - viewer = DiffViewer::NoPreview.new(viewer.diff_file) if viewer.binary_detected_after_load? + + = render viewer.partial_path, viewer: viewer diff --git a/app/views/projects/diffs/viewers/_added.html.haml b/app/views/projects/diffs/viewers/_added.html.haml new file mode 100644 index 00000000000..8004fe16688 --- /dev/null +++ b/app/views/projects/diffs/viewers/_added.html.haml @@ -0,0 +1,2 @@ +.nothing-here-block + File added diff --git a/app/views/projects/diffs/viewers/_deleted.html.haml b/app/views/projects/diffs/viewers/_deleted.html.haml new file mode 100644 index 00000000000..0ac7b4ca8f6 --- /dev/null +++ b/app/views/projects/diffs/viewers/_deleted.html.haml @@ -0,0 +1,2 @@ +.nothing-here-block + File deleted diff --git a/app/views/projects/diffs/viewers/_image.html.haml b/app/views/projects/diffs/viewers/_image.html.haml index ea75373581e..19d08181223 100644 --- a/app/views/projects/diffs/viewers/_image.html.haml +++ b/app/views/projects/diffs/viewers/_image.html.haml @@ -1,3 +1,4 @@ +- diff_file = viewer.diff_file - blob = diff_file.blob - old_blob = diff_file.old_blob - blob_raw_path = diff_file_blob_raw_path(diff_file) diff --git a/app/views/projects/diffs/viewers/_mode_changed.html.haml b/app/views/projects/diffs/viewers/_mode_changed.html.haml new file mode 100644 index 00000000000..69bc96bbdad --- /dev/null +++ b/app/views/projects/diffs/viewers/_mode_changed.html.haml @@ -0,0 +1,3 @@ +- diff_file = viewer.diff_file +.nothing-here-block + File mode changed from #{diff_file.a_mode} to #{diff_file.b_mode} diff --git a/app/views/projects/diffs/viewers/_no_preview.html.haml b/app/views/projects/diffs/viewers/_no_preview.html.haml new file mode 100644 index 00000000000..befe070af2b --- /dev/null +++ b/app/views/projects/diffs/viewers/_no_preview.html.haml @@ -0,0 +1,2 @@ +.nothing-here-block + No preview for this file type diff --git a/app/views/projects/diffs/viewers/_not_diffable.html.haml b/app/views/projects/diffs/viewers/_not_diffable.html.haml new file mode 100644 index 00000000000..b2c677ec59c --- /dev/null +++ b/app/views/projects/diffs/viewers/_not_diffable.html.haml @@ -0,0 +1,2 @@ +.nothing-here-block + This diff was suppressed by a .gitattributes entry. diff --git a/app/views/projects/diffs/viewers/_renamed.html.haml b/app/views/projects/diffs/viewers/_renamed.html.haml new file mode 100644 index 00000000000..ef05ee38d8d --- /dev/null +++ b/app/views/projects/diffs/viewers/_renamed.html.haml @@ -0,0 +1,2 @@ +.nothing-here-block + File moved diff --git a/app/views/projects/diffs/viewers/_text.html.haml b/app/views/projects/diffs/viewers/_text.html.haml index 120d3540223..509e68598c9 100644 --- a/app/views/projects/diffs/viewers/_text.html.haml +++ b/app/views/projects/diffs/viewers/_text.html.haml @@ -1,5 +1,5 @@ +- diff_file = viewer.diff_file - blob = diff_file.blob -- blob.load_all_data! - total_lines = blob.lines.size - total_lines -= 1 if total_lines > 0 && blob.lines.last.blank? - if diff_view == :parallel diff --git a/changelogs/unreleased/32470-pag-links.yml b/changelogs/unreleased/32470-pag-links.yml new file mode 100644 index 00000000000..d0fd284f3ee --- /dev/null +++ b/changelogs/unreleased/32470-pag-links.yml @@ -0,0 +1,4 @@ +--- +title: more visual contrast in pagination widget +merge_request: +author: diff --git a/changelogs/unreleased/dm-diff-viewers.yml b/changelogs/unreleased/dm-diff-viewers.yml new file mode 100644 index 00000000000..e5b1352c8f1 --- /dev/null +++ b/changelogs/unreleased/dm-diff-viewers.yml @@ -0,0 +1,4 @@ +--- +title: Implement diff viewers +merge_request: +author: diff --git a/changelogs/unreleased/dm-fix-parser-cache.yml b/changelogs/unreleased/dm-fix-parser-cache.yml new file mode 100644 index 00000000000..31c163b7272 --- /dev/null +++ b/changelogs/unreleased/dm-fix-parser-cache.yml @@ -0,0 +1,4 @@ +--- +title: Don't return nil for missing objects from parser cache +merge_request: +author: diff --git a/changelogs/unreleased/dm-target-branch-slash-command-desc.yml b/changelogs/unreleased/dm-target-branch-slash-command-desc.yml new file mode 100644 index 00000000000..768ddf0416e --- /dev/null +++ b/changelogs/unreleased/dm-target-branch-slash-command-desc.yml @@ -0,0 +1,4 @@ +--- +title: Update /target_branch slash command description to be more consistent +merge_request: +author: diff --git a/changelogs/unreleased/help-landing-page-customizations.yml b/changelogs/unreleased/help-landing-page-customizations.yml new file mode 100644 index 00000000000..58cab751ded --- /dev/null +++ b/changelogs/unreleased/help-landing-page-customizations.yml @@ -0,0 +1,4 @@ +--- +title: Help landing page customizations +merge_request: 11878 +author: Robin Bobbitt diff --git a/changelogs/unreleased/zj-raise-etag-route-regex-miss.yml b/changelogs/unreleased/zj-raise-etag-route-regex-miss.yml new file mode 100644 index 00000000000..57a5f4e44c0 --- /dev/null +++ b/changelogs/unreleased/zj-raise-etag-route-regex-miss.yml @@ -0,0 +1,4 @@ +--- +title: Fix etag route not being a match for environments +merge_request: +author: diff --git a/config/webpack.config.js b/config/webpack.config.js index 120f9d3193d..3c2455ebf35 100644 --- a/config/webpack.config.js +++ b/config/webpack.config.js @@ -61,7 +61,7 @@ var config = { network: './network/network_bundle.js', notebook_viewer: './blob/notebook_viewer.js', pdf_viewer: './blob/pdf_viewer.js', - pipelines: './pipelines/index.js', + pipelines: './pipelines/pipelines_bundle.js', pipelines_details: './pipelines/pipeline_details_bundle.js', profile: './profile/profile_bundle.js', protected_branches: './protected_branches/protected_branches_bundle.js', diff --git a/db/migrate/20170602154736_add_help_page_hide_commercial_content_to_application_settings.rb b/db/migrate/20170602154736_add_help_page_hide_commercial_content_to_application_settings.rb new file mode 100644 index 00000000000..5e8b667b86d --- /dev/null +++ b/db/migrate/20170602154736_add_help_page_hide_commercial_content_to_application_settings.rb @@ -0,0 +1,9 @@ +class AddHelpPageHideCommercialContentToApplicationSettings < ActiveRecord::Migration + include Gitlab::Database::MigrationHelpers + + DOWNTIME = false + + def change + add_column :application_settings, :help_page_hide_commercial_content, :boolean, default: false + end +end diff --git a/db/migrate/20170602154813_add_help_page_support_url_to_application_settings.rb b/db/migrate/20170602154813_add_help_page_support_url_to_application_settings.rb new file mode 100644 index 00000000000..138fe9b2a37 --- /dev/null +++ b/db/migrate/20170602154813_add_help_page_support_url_to_application_settings.rb @@ -0,0 +1,9 @@ +class AddHelpPageSupportUrlToApplicationSettings < ActiveRecord::Migration + include Gitlab::Database::MigrationHelpers + + DOWNTIME = false + + def change + add_column :application_settings, :help_page_support_url, :string + end +end diff --git a/db/schema.rb b/db/schema.rb index b93630a410d..9d79fe162b7 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -12,6 +12,7 @@ # It's strongly recommended that you check this file into your version control system. ActiveRecord::Schema.define(version: 20170606202615) do + # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" enable_extension "pg_trgm" @@ -123,6 +124,8 @@ ActiveRecord::Schema.define(version: 20170606202615) do t.boolean "clientside_sentry_enabled", default: false, null: false t.string "clientside_sentry_dsn" t.boolean "prometheus_metrics_enabled", default: false, null: false + t.boolean "help_page_hide_commercial_content", default: false + t.string "help_page_support_url" end create_table "audit_events", force: :cascade do |t| diff --git a/doc/user/project/integrations/jira.md b/doc/user/project/integrations/jira.md index a048260b033..e8dbf8d08d2 100644 --- a/doc/user/project/integrations/jira.md +++ b/doc/user/project/integrations/jira.md @@ -76,7 +76,7 @@ We have split this stage in steps so it is easier to follow. ![JIRA add user to group](img/jira_add_user_to_group.png) ---- + --- The JIRA configuration is over. Write down the new JIRA username and its password as they will be needed when configuring GitLab in the next section. diff --git a/lib/api/entities.rb b/lib/api/entities.rb index af55c372eea..412443a2405 100644 --- a/lib/api/entities.rb +++ b/lib/api/entities.rb @@ -603,6 +603,9 @@ module API expose :plantuml_url expose :terminal_max_session_time expose :polling_interval_multiplier + expose :help_page_hide_commercial_content + expose :help_page_text + expose :help_page_support_url end class Release < Grape::Entity diff --git a/lib/api/settings.rb b/lib/api/settings.rb index 25027c3b114..d598f9a62a2 100644 --- a/lib/api/settings.rb +++ b/lib/api/settings.rb @@ -39,7 +39,9 @@ module API :email_author_in_body, :enabled_git_access_protocol, :gravatar_enabled, + :help_page_hide_commercial_content, :help_page_text, + :help_page_support_url, :home_page_url, :housekeeping_enabled, :html_emails_enabled, @@ -101,7 +103,9 @@ module API optional :home_page_url, type: String, desc: 'We will redirect non-logged in users to this page' optional :after_sign_out_path, type: String, desc: 'We will redirect users to this page after they sign out' optional :sign_in_text, type: String, desc: 'The sign in text of the GitLab application' + optional :help_page_hide_commercial_content, type: Boolean, desc: 'Hide marketing-related entries from help' optional :help_page_text, type: String, desc: 'Custom text displayed on the help page' + optional :help_page_support_url, type: String, desc: 'Alternate support URL for help page' optional :shared_runners_enabled, type: Boolean, desc: 'Enable shared runners for new projects' given shared_runners_enabled: ->(val) { val } do requires :shared_runners_text, type: String, desc: 'Shared runners text ' diff --git a/lib/banzai/reference_parser/base_parser.rb b/lib/banzai/reference_parser/base_parser.rb index 1e2536231d8..279fca8d043 100644 --- a/lib/banzai/reference_parser/base_parser.rb +++ b/lib/banzai/reference_parser/base_parser.rb @@ -171,7 +171,7 @@ module Banzai collection.where(id: to_query).each { |row| cache[row.id] = row } end - cache.values_at(*ids) + cache.values_at(*ids).compact else collection.where(id: ids) end diff --git a/lib/gitlab/diff/file.rb b/lib/gitlab/diff/file.rb index 4212a0dbe2e..d2863a4da71 100644 --- a/lib/gitlab/diff/file.rb +++ b/lib/gitlab/diff/file.rb @@ -5,7 +5,20 @@ module Gitlab delegate :new_file?, :deleted_file?, :renamed_file?, :old_path, :new_path, :a_mode, :b_mode, :mode_changed?, - :submodule?, :too_large?, :collapsed?, to: :diff, prefix: false + :submodule?, :expanded?, :too_large?, :collapsed?, :line_count, to: :diff, prefix: false + + # Finding a viewer for a diff file happens based only on extension and whether the + # diff file blobs are binary or text, which means 1 diff file should only be matched by 1 viewer, + # and the order of these viewers doesn't really matter. + # + # However, when the diff file blobs are LFS pointers, we cannot know for sure whether the + # file being pointed to is binary or text. In this case, we match only on + # extension, preferring binary viewers over text ones if both exist, since the + # large files referred to in "Large File Storage" are much more likely to be + # binary than text. + RICH_VIEWERS = [ + DiffViewer::Image + ].sort_by { |v| v.binary? ? 0 : 1 }.freeze def initialize(diff, repository:, diff_refs: nil, fallback_diff_refs: nil) @diff = diff @@ -177,6 +190,100 @@ module Gitlab def text? !binary? end + + def external_storage_error? + old_blob&.external_storage_error? || new_blob&.external_storage_error? + end + + def stored_externally? + old_blob&.stored_externally? || new_blob&.stored_externally? + end + + def external_storage + old_blob&.external_storage || new_blob&.external_storage + end + + def content_changed? + old_blob && new_blob && old_blob.id != new_blob.id + end + + def different_type? + old_blob && new_blob && old_blob.binary? != new_blob.binary? + end + + def size + [old_blob&.size, new_blob&.size].compact.sum + end + + def raw_size + [old_blob&.raw_size, new_blob&.raw_size].compact.sum + end + + def raw_binary? + old_blob&.raw_binary? || new_blob&.raw_binary? + end + + def raw_text? + !raw_binary? && !different_type? + end + + def simple_viewer + @simple_viewer ||= simple_viewer_class.new(self) + end + + def rich_viewer + return @rich_viewer if defined?(@rich_viewer) + + @rich_viewer = rich_viewer_class&.new(self) + end + + def rendered_as_text?(ignore_errors: true) + simple_viewer.is_a?(DiffViewer::Text) && (ignore_errors || simple_viewer.render_error.nil?) + end + + private + + def simple_viewer_class + return DiffViewer::NotDiffable unless diffable? + + if content_changed? + if raw_text? + DiffViewer::Text + else + DiffViewer::NoPreview + end + elsif new_file? + if raw_text? + DiffViewer::Text + else + DiffViewer::Added + end + elsif deleted_file? + if raw_text? + DiffViewer::Text + else + DiffViewer::Deleted + end + elsif renamed_file? + DiffViewer::Renamed + elsif mode_changed? + DiffViewer::ModeChanged + end + end + + def rich_viewer_class + viewer_class_from(RICH_VIEWERS) + end + + def viewer_class_from(classes) + return unless diffable? + return if different_type? || external_storage_error? + return unless new_file? || deleted_file? || content_changed? + + verify_binary = !stored_externally? + + classes.find { |viewer_class| viewer_class.can_render?(self, verify_binary: verify_binary) } + end end end end diff --git a/lib/gitlab/etag_caching/middleware.rb b/lib/gitlab/etag_caching/middleware.rb index 7f884183bb1..1d6f5bb5e1c 100644 --- a/lib/gitlab/etag_caching/middleware.rb +++ b/lib/gitlab/etag_caching/middleware.rb @@ -7,7 +7,7 @@ module Gitlab def call(env) request = Rack::Request.new(env) - route = Gitlab::EtagCaching::Router.match(request) + route = Gitlab::EtagCaching::Router.match(request.path_info) return @app.call(env) unless route track_event(:etag_caching_middleware_used, route) diff --git a/lib/gitlab/etag_caching/router.rb b/lib/gitlab/etag_caching/router.rb index dccc66b3918..75167a6b088 100644 --- a/lib/gitlab/etag_caching/router.rb +++ b/lib/gitlab/etag_caching/router.rb @@ -53,8 +53,8 @@ module Gitlab ) ].freeze - def self.match(request) - ROUTES.find { |route| route.regexp.match(request.path_info) } + def self.match(path) + ROUTES.find { |route| route.regexp.match(path) } end end end diff --git a/lib/gitlab/etag_caching/store.rb b/lib/gitlab/etag_caching/store.rb index 0039fc01c8f..072fcfc65e6 100644 --- a/lib/gitlab/etag_caching/store.rb +++ b/lib/gitlab/etag_caching/store.rb @@ -25,6 +25,8 @@ module Gitlab end def redis_key(key) + raise 'Invalid key' if !Rails.env.production? && !Gitlab::EtagCaching::Router.match(key) + "#{REDIS_NAMESPACE}#{key}" end end diff --git a/lib/gitlab/git/diff.rb b/lib/gitlab/git/diff.rb index 88ad760bea3..4b689f0e94f 100644 --- a/lib/gitlab/git/diff.rb +++ b/lib/gitlab/git/diff.rb @@ -17,6 +17,8 @@ module Gitlab attr_accessor :expanded + alias_method :expanded?, :expanded + # We need this accessor because of `to_hash` and `init_from_hash` attr_accessor :too_large diff --git a/lib/gitlab/git/diff_collection.rb b/lib/gitlab/git/diff_collection.rb index 334e06a6eca..555894907cc 100644 --- a/lib/gitlab/git/diff_collection.rb +++ b/lib/gitlab/git/diff_collection.rb @@ -97,7 +97,7 @@ module Gitlab diff = Gitlab::Git::Diff.new(raw, expanded: expanded) - if !expanded && over_safe_limits?(i) + if !expanded && over_safe_limits?(i) && diff.line_count > 0 diff.collapse! end diff --git a/lib/gitlab/kubernetes.rb b/lib/gitlab/kubernetes.rb index 4a6091488c8..c56c1a4322f 100644 --- a/lib/gitlab/kubernetes.rb +++ b/lib/gitlab/kubernetes.rb @@ -8,13 +8,13 @@ module Gitlab ) # Filters an array of pods (as returned by the kubernetes API) by their labels - def filter_pods(pods, labels = {}) - pods.select do |pod| - metadata = pod.fetch("metadata", {}) - pod_labels = metadata.fetch("labels", nil) - next unless pod_labels + def filter_by_label(items, labels = {}) + items.select do |item| + metadata = item.fetch("metadata", {}) + item_labels = metadata.fetch("labels", nil) + next unless item_labels - labels.all? { |k, v| pod_labels[k.to_s] == v } + labels.all? { |k, v| item_labels[k.to_s] == v } end end diff --git a/rubocop/cop/rspec/single_line_hook.rb b/rubocop/cop/rspec/single_line_hook.rb new file mode 100644 index 00000000000..be611054323 --- /dev/null +++ b/rubocop/cop/rspec/single_line_hook.rb @@ -0,0 +1,38 @@ +require 'rubocop-rspec' + +module RuboCop + module Cop + module RSpec + # This cop checks for single-line hook blocks + # + # @example + # + # # bad + # before { do_something } + # after(:each) { undo_something } + # + # # good + # before do + # do_something + # end + # + # after(:each) do + # undo_something + # end + class SingleLineHook < Cop + MESSAGE = "Don't use single-line hook blocks.".freeze + + def_node_search :rspec_hook?, <<~PATTERN + (send nil {:after :around :before} ...) + PATTERN + + def on_block(node) + return unless rspec_hook?(node) + return unless node.single_line? + + add_offense(node, :expression, MESSAGE) + end + end + end + end +end diff --git a/rubocop/rubocop.rb b/rubocop/rubocop.rb index 6b8d127dde6..55d7708fa8c 100644 --- a/rubocop/rubocop.rb +++ b/rubocop/rubocop.rb @@ -15,3 +15,4 @@ require_relative 'cop/migration/remove_index' require_relative 'cop/migration/reversible_add_column_with_default' require_relative 'cop/migration/timestamps' require_relative 'cop/migration/update_column_in_batches' +require_relative 'cop/rspec/single_line_hook' diff --git a/spec/controllers/admin/identities_controller_spec.rb b/spec/controllers/admin/identities_controller_spec.rb index c131d22a30a..a29853bf8df 100644 --- a/spec/controllers/admin/identities_controller_spec.rb +++ b/spec/controllers/admin/identities_controller_spec.rb @@ -2,7 +2,10 @@ require 'spec_helper' describe Admin::IdentitiesController do let(:admin) { create(:admin) } - before { sign_in(admin) } + + before do + sign_in(admin) + end describe 'UPDATE identity' do let(:user) { create(:omniauth_user, provider: 'ldapmain', extern_uid: 'uid=myuser,ou=people,dc=example,dc=com') } diff --git a/spec/controllers/admin/services_controller_spec.rb b/spec/controllers/admin/services_controller_spec.rb index c94616d8508..4ca0cfc74e9 100644 --- a/spec/controllers/admin/services_controller_spec.rb +++ b/spec/controllers/admin/services_controller_spec.rb @@ -3,7 +3,9 @@ require 'spec_helper' describe Admin::ServicesController do let(:admin) { create(:admin) } - before { sign_in(admin) } + before do + sign_in(admin) + end describe 'GET #edit' do let!(:project) { create(:empty_project) } diff --git a/spec/controllers/autocomplete_controller_spec.rb b/spec/controllers/autocomplete_controller_spec.rb index 4c3a5ec49ef..b40f647644d 100644 --- a/spec/controllers/autocomplete_controller_spec.rb +++ b/spec/controllers/autocomplete_controller_spec.rb @@ -200,7 +200,9 @@ describe AutocompleteController do end context 'skip_users parameter included' do - before { sign_in(user) } + before do + sign_in(user) + end it 'skips the user IDs passed' do get(:users, skip_users: [user, user2].map(&:id)) diff --git a/spec/controllers/groups/group_members_controller_spec.rb b/spec/controllers/groups/group_members_controller_spec.rb index ed4ad7b600e..cce53f6697c 100644 --- a/spec/controllers/groups/group_members_controller_spec.rb +++ b/spec/controllers/groups/group_members_controller_spec.rb @@ -16,10 +16,14 @@ describe Groups::GroupMembersController do describe 'POST create' do let(:group_user) { create(:user) } - before { sign_in(user) } + before do + sign_in(user) + end context 'when user does not have enough rights' do - before { group.add_developer(user) } + before do + group.add_developer(user) + end it 'returns 403' do post :create, group_id: group, @@ -32,7 +36,9 @@ describe Groups::GroupMembersController do end context 'when user has enough rights' do - before { group.add_owner(user) } + before do + group.add_owner(user) + end it 'adds user to members' do post :create, group_id: group, @@ -59,7 +65,9 @@ describe Groups::GroupMembersController do describe 'DELETE destroy' do let(:member) { create(:group_member, :developer, group: group) } - before { sign_in(user) } + before do + sign_in(user) + end context 'when member is not found' do it 'returns 403' do @@ -71,7 +79,9 @@ describe Groups::GroupMembersController do context 'when member is found' do context 'when user does not have enough rights' do - before { group.add_developer(user) } + before do + group.add_developer(user) + end it 'returns 403' do delete :destroy, group_id: group, id: member @@ -82,7 +92,9 @@ describe Groups::GroupMembersController do end context 'when user has enough rights' do - before { group.add_owner(user) } + before do + group.add_owner(user) + end it '[HTML] removes user from members' do delete :destroy, group_id: group, id: member @@ -103,7 +115,9 @@ describe Groups::GroupMembersController do end describe 'DELETE leave' do - before { sign_in(user) } + before do + sign_in(user) + end context 'when member is not found' do it 'returns 404' do @@ -115,7 +129,9 @@ describe Groups::GroupMembersController do context 'when member is found' do context 'and is not an owner' do - before { group.add_developer(user) } + before do + group.add_developer(user) + end it 'removes user from members' do delete :leave, group_id: group @@ -134,7 +150,9 @@ describe Groups::GroupMembersController do end context 'and is an owner' do - before { group.add_owner(user) } + before do + group.add_owner(user) + end it 'cannot removes himself from the group' do delete :leave, group_id: group @@ -144,7 +162,9 @@ describe Groups::GroupMembersController do end context 'and is a requester' do - before { group.request_access(user) } + before do + group.request_access(user) + end it 'removes user from members' do delete :leave, group_id: group @@ -159,7 +179,9 @@ describe Groups::GroupMembersController do end describe 'POST request_access' do - before { sign_in(user) } + before do + sign_in(user) + end it 'creates a new GroupMember that is not a team member' do post :request_access, group_id: group @@ -174,7 +196,9 @@ describe Groups::GroupMembersController do describe 'POST approve_access_request' do let(:member) { create(:group_member, :access_request, group: group) } - before { sign_in(user) } + before do + sign_in(user) + end context 'when member is not found' do it 'returns 403' do @@ -186,7 +210,9 @@ describe Groups::GroupMembersController do context 'when member is found' do context 'when user does not have enough rights' do - before { group.add_developer(user) } + before do + group.add_developer(user) + end it 'returns 403' do post :approve_access_request, group_id: group, id: member @@ -197,7 +223,9 @@ describe Groups::GroupMembersController do end context 'when user has enough rights' do - before { group.add_owner(user) } + before do + group.add_owner(user) + end it 'adds user to members' do post :approve_access_request, group_id: group, id: member diff --git a/spec/controllers/notification_settings_controller_spec.rb b/spec/controllers/notification_settings_controller_spec.rb index 9e3a31e1a6b..cf136e72bac 100644 --- a/spec/controllers/notification_settings_controller_spec.rb +++ b/spec/controllers/notification_settings_controller_spec.rb @@ -94,7 +94,10 @@ describe NotificationSettingsController do context 'not authorized' do let(:private_project) { create(:empty_project, :private) } - before { sign_in(user) } + + before do + sign_in(user) + end it 'returns 404' do post :create, @@ -120,7 +123,9 @@ describe NotificationSettingsController do end context 'when authorized' do - before{ sign_in(user) } + before do + sign_in(user) + end it 'returns success' do put :update, @@ -152,7 +157,9 @@ describe NotificationSettingsController do context 'not authorized' do let(:other_user) { create(:user) } - before { sign_in(other_user) } + before do + sign_in(other_user) + end it 'returns 404' do put :update, diff --git a/spec/controllers/profiles/personal_access_tokens_controller_spec.rb b/spec/controllers/profiles/personal_access_tokens_controller_spec.rb index 98a43e278b2..ed08a4c1bf2 100644 --- a/spec/controllers/profiles/personal_access_tokens_controller_spec.rb +++ b/spec/controllers/profiles/personal_access_tokens_controller_spec.rb @@ -4,7 +4,9 @@ describe Profiles::PersonalAccessTokensController do let(:user) { create(:user) } let(:token_attributes) { attributes_for(:personal_access_token) } - before { sign_in(user) } + before do + sign_in(user) + end describe '#create' do def created_token @@ -38,7 +40,9 @@ describe Profiles::PersonalAccessTokensController do let!(:inactive_personal_access_token) { create(:personal_access_token, :revoked, user: user) } let!(:impersonation_personal_access_token) { create(:personal_access_token, :impersonation, user: user) } - before { get :index } + before do + get :index + end it "retrieves active personal access tokens" do expect(assigns(:active_personal_access_tokens)).to include(active_personal_access_token) diff --git a/spec/controllers/projects/commit_controller_spec.rb b/spec/controllers/projects/commit_controller_spec.rb index 69e4706dc71..7fb08df1950 100644 --- a/spec/controllers/projects/commit_controller_spec.rb +++ b/spec/controllers/projects/commit_controller_spec.rb @@ -281,7 +281,9 @@ describe Projects::CommitController do end context 'when the path does not exist in the diff' do - before { diff_for_path(id: commit.id, old_path: existing_path.succ, new_path: existing_path.succ) } + before do + diff_for_path(id: commit.id, old_path: existing_path.succ, new_path: existing_path.succ) + end it 'returns a 404' do expect(response).to have_http_status(404) @@ -302,7 +304,9 @@ describe Projects::CommitController do end context 'when the commit does not exist' do - before { diff_for_path(id: commit.id.succ, old_path: existing_path, new_path: existing_path) } + before do + diff_for_path(id: commit.id.succ, old_path: existing_path, new_path: existing_path) + end it 'returns a 404' do expect(response).to have_http_status(404) diff --git a/spec/controllers/projects/compare_controller_spec.rb b/spec/controllers/projects/compare_controller_spec.rb index 15ac4e0925a..8f4694c9854 100644 --- a/spec/controllers/projects/compare_controller_spec.rb +++ b/spec/controllers/projects/compare_controller_spec.rb @@ -128,7 +128,9 @@ describe Projects::CompareController do end context 'when the path does not exist in the diff' do - before { diff_for_path(from: ref_from, to: ref_to, old_path: existing_path.succ, new_path: existing_path.succ) } + before do + diff_for_path(from: ref_from, to: ref_to, old_path: existing_path.succ, new_path: existing_path.succ) + end it 'returns a 404' do expect(response).to have_http_status(404) @@ -149,7 +151,9 @@ describe Projects::CompareController do end context 'when the from ref does not exist' do - before { diff_for_path(from: ref_from.succ, to: ref_to, old_path: existing_path, new_path: existing_path) } + before do + diff_for_path(from: ref_from.succ, to: ref_to, old_path: existing_path, new_path: existing_path) + end it 'returns a 404' do expect(response).to have_http_status(404) @@ -157,7 +161,9 @@ describe Projects::CompareController do end context 'when the to ref does not exist' do - before { diff_for_path(from: ref_from, to: ref_to.succ, old_path: existing_path, new_path: existing_path) } + before do + diff_for_path(from: ref_from, to: ref_to.succ, old_path: existing_path, new_path: existing_path) + end it 'returns a 404' do expect(response).to have_http_status(404) diff --git a/spec/controllers/projects/forks_controller_spec.rb b/spec/controllers/projects/forks_controller_spec.rb index 8282d79298f..dc8290c438e 100644 --- a/spec/controllers/projects/forks_controller_spec.rb +++ b/spec/controllers/projects/forks_controller_spec.rb @@ -14,7 +14,9 @@ describe Projects::ForksController do end context 'when fork is public' do - before { forked_project.update_attribute(:visibility_level, Project::PUBLIC) } + before do + forked_project.update_attribute(:visibility_level, Project::PUBLIC) + end it 'is visible for non logged in users' do get_forks @@ -35,7 +37,9 @@ describe Projects::ForksController do end context 'when user is logged in' do - before { sign_in(project.creator) } + before do + sign_in(project.creator) + end context 'when user is not a Project member neither a group member' do it 'does not see the Project listed' do @@ -46,7 +50,9 @@ describe Projects::ForksController do end context 'when user is a member of the Project' do - before { forked_project.team << [project.creator, :developer] } + before do + forked_project.team << [project.creator, :developer] + end it 'sees the project listed' do get_forks @@ -56,7 +62,9 @@ describe Projects::ForksController do end context 'when user is a member of the Group' do - before { forked_project.group.add_developer(project.creator) } + before do + forked_project.group.add_developer(project.creator) + end it 'sees the project listed' do get_forks diff --git a/spec/controllers/projects/group_links_controller_spec.rb b/spec/controllers/projects/group_links_controller_spec.rb index ca4a8e871c0..b5435357f53 100644 --- a/spec/controllers/projects/group_links_controller_spec.rb +++ b/spec/controllers/projects/group_links_controller_spec.rb @@ -22,7 +22,10 @@ describe Projects::GroupLinksController do end context 'when user has access to group he want to link project to' do - before { group.add_developer(user) } + before do + group.add_developer(user) + end + include_context 'link project to group' it 'links project with selected group' do diff --git a/spec/controllers/projects/issues_controller_spec.rb b/spec/controllers/projects/issues_controller_spec.rb index b65e9e0dfc0..f853bfe370c 100644 --- a/spec/controllers/projects/issues_controller_spec.rb +++ b/spec/controllers/projects/issues_controller_spec.rb @@ -212,7 +212,9 @@ describe Projects::IssuesController do let(:another_project) { create(:empty_project, :private) } context 'when user has access to move issue' do - before { another_project.team << [user, :reporter] } + before do + another_project.team << [user, :reporter] + end it 'moves issue to another project' do move_issue @@ -250,14 +252,18 @@ describe Projects::IssuesController do end context 'when an issue is identified as spam' do - before { allow_any_instance_of(AkismetService).to receive(:is_spam?).and_return(true) } + before do + allow_any_instance_of(AkismetService).to receive(:is_spam?).and_return(true) + end context 'when captcha is not verified' do def update_spam_issue update_issue(title: 'Spam Title', description: 'Spam lives here') end - before { allow_any_instance_of(described_class).to receive(:verify_recaptcha).and_return(false) } + before do + allow_any_instance_of(described_class).to receive(:verify_recaptcha).and_return(false) + end it 'rejects an issue recognized as a spam' do expect(Gitlab::Recaptcha).to receive(:load_configurations!).and_return(true) @@ -620,14 +626,18 @@ describe Projects::IssuesController do end context 'when an issue is identified as spam' do - before { allow_any_instance_of(AkismetService).to receive(:is_spam?).and_return(true) } + before do + allow_any_instance_of(AkismetService).to receive(:is_spam?).and_return(true) + end context 'when captcha is not verified' do def post_spam_issue post_new_issue(title: 'Spam Title', description: 'Spam lives here') end - before { allow_any_instance_of(described_class).to receive(:verify_recaptcha).and_return(false) } + before do + allow_any_instance_of(described_class).to receive(:verify_recaptcha).and_return(false) + end it 'rejects an issue recognized as a spam' do expect { post_spam_issue }.not_to change(Issue, :count) @@ -739,7 +749,10 @@ describe Projects::IssuesController do describe "DELETE #destroy" do context "when the user is a developer" do - before { sign_in(user) } + before do + sign_in(user) + end + it "rejects a developer to destroy an issue" do delete :destroy, namespace_id: project.namespace, project_id: project, id: issue.iid expect(response).to have_http_status(404) @@ -751,7 +764,9 @@ describe Projects::IssuesController do let(:namespace) { create(:namespace, owner: owner) } let(:project) { create(:empty_project, namespace: namespace) } - before { sign_in(owner) } + before do + sign_in(owner) + end it "deletes the issue" do delete :destroy, namespace_id: project.namespace, project_id: project, id: issue.iid diff --git a/spec/controllers/projects/jobs_controller_spec.rb b/spec/controllers/projects/jobs_controller_spec.rb index 4a737587899..472e5fc51a0 100644 --- a/spec/controllers/projects/jobs_controller_spec.rb +++ b/spec/controllers/projects/jobs_controller_spec.rb @@ -28,7 +28,7 @@ describe Projects::JobsController do get_index(scope: 'running') end - it 'has only running builds' do + it 'has only running jobs' do expect(response).to have_http_status(:ok) expect(assigns(:builds).first.status).to eq('running') end @@ -41,7 +41,7 @@ describe Projects::JobsController do get_index(scope: 'finished') end - it 'has only finished builds' do + it 'has only finished jobs' do expect(response).to have_http_status(:ok) expect(assigns(:builds).first.status).to eq('success') end @@ -67,7 +67,7 @@ describe Projects::JobsController do context 'number of queries' do before do Ci::Build::AVAILABLE_STATUSES.each do |status| - create_build(status, status) + create_job(status, status) end end @@ -76,7 +76,7 @@ describe Projects::JobsController do expect(recorded.count).to be_within(5).of(7) end - def create_build(name, status) + def create_job(name, status) pipeline = create(:ci_pipeline, project: project) create(:ci_build, :tags, :triggered, :artifacts, pipeline: pipeline, name: name, status: status) @@ -94,21 +94,21 @@ describe Projects::JobsController do end describe 'GET show' do - let!(:build) { create(:ci_build, :failed, pipeline: pipeline) } + let!(:job) { create(:ci_build, :failed, pipeline: pipeline) } context 'when requesting HTML' do - context 'when build exists' do + context 'when job exists' do before do - get_show(id: build.id) + get_show(id: job.id) end - it 'has a build' do + it 'has a job' do expect(response).to have_http_status(:ok) - expect(assigns(:build).id).to eq(build.id) + expect(assigns(:build).id).to eq(job.id) end end - context 'when build does not exist' do + context 'when job does not exist' do before do get_show(id: 1234) end @@ -128,12 +128,12 @@ describe Projects::JobsController do allow_any_instance_of(Ci::Build).to receive(:merge_request).and_return(merge_request) - get_show(id: build.id, format: :json) + get_show(id: job.id, format: :json) end it 'exposes needed information' do expect(response).to have_http_status(:ok) - expect(json_response['raw_path']).to match(/builds\/\d+\/raw\z/) + expect(json_response['raw_path']).to match(/jobs\/\d+\/raw\z/) expect(json_response.dig('merge_request', 'path')).to match(/merge_requests\/\d+\z/) expect(json_response['new_issue_path']) .to include('/issues/new') @@ -155,35 +155,35 @@ describe Projects::JobsController do get_trace end - context 'when build has a trace' do - let(:build) { create(:ci_build, :trace, pipeline: pipeline) } + context 'when job has a trace' do + let(:job) { create(:ci_build, :trace, pipeline: pipeline) } it 'returns a trace' do expect(response).to have_http_status(:ok) - expect(json_response['id']).to eq build.id - expect(json_response['status']).to eq build.status + expect(json_response['id']).to eq job.id + expect(json_response['status']).to eq job.status expect(json_response['html']).to eq('BUILD TRACE') end end - context 'when build has no traces' do - let(:build) { create(:ci_build, pipeline: pipeline) } + context 'when job has no traces' do + let(:job) { create(:ci_build, pipeline: pipeline) } it 'returns no traces' do expect(response).to have_http_status(:ok) - expect(json_response['id']).to eq build.id - expect(json_response['status']).to eq build.status + expect(json_response['id']).to eq job.id + expect(json_response['status']).to eq job.status expect(json_response['html']).to be_nil end end - context 'when build has a trace with ANSI sequence and Unicode' do - let(:build) { create(:ci_build, :unicode_trace, pipeline: pipeline) } + context 'when job has a trace with ANSI sequence and Unicode' do + let(:job) { create(:ci_build, :unicode_trace, pipeline: pipeline) } it 'returns a trace with Unicode' do expect(response).to have_http_status(:ok) - expect(json_response['id']).to eq build.id - expect(json_response['status']).to eq build.status + expect(json_response['id']).to eq job.id + expect(json_response['status']).to eq job.status expect(json_response['html']).to include("ヾ(´༎ຶД༎ຶ`)ノ") end end @@ -191,23 +191,23 @@ describe Projects::JobsController do def get_trace get :trace, namespace_id: project.namespace, project_id: project, - id: build.id, + id: job.id, format: :json end end describe 'GET status.json' do - let(:build) { create(:ci_build, pipeline: pipeline) } - let(:status) { build.detailed_status(double('user')) } + let(:job) { create(:ci_build, pipeline: pipeline) } + let(:status) { job.detailed_status(double('user')) } before do get :status, namespace_id: project.namespace, project_id: project, - id: build.id, + id: job.id, format: :json end - it 'return a detailed build status in json' do + it 'return a detailed job status in json' do expect(response).to have_http_status(:ok) expect(json_response['text']).to eq status.text expect(json_response['label']).to eq status.label @@ -224,17 +224,17 @@ describe Projects::JobsController do post_retry end - context 'when build is retryable' do - let(:build) { create(:ci_build, :retryable, pipeline: pipeline) } + context 'when job is retryable' do + let(:job) { create(:ci_build, :retryable, pipeline: pipeline) } - it 'redirects to the retried build page' do + it 'redirects to the retried job page' do expect(response).to have_http_status(:found) expect(response).to redirect_to(namespace_project_job_path(id: Ci::Build.last.id)) end end - context 'when build is not retryable' do - let(:build) { create(:ci_build, pipeline: pipeline) } + context 'when job is not retryable' do + let(:job) { create(:ci_build, pipeline: pipeline) } it 'renders unprocessable_entity' do expect(response).to have_http_status(:unprocessable_entity) @@ -244,7 +244,7 @@ describe Projects::JobsController do def post_retry post :retry, namespace_id: project.namespace, project_id: project, - id: build.id + id: job.id end end @@ -260,21 +260,21 @@ describe Projects::JobsController do post_play end - context 'when build is playable' do - let(:build) { create(:ci_build, :playable, pipeline: pipeline) } + context 'when job is playable' do + let(:job) { create(:ci_build, :playable, pipeline: pipeline) } - it 'redirects to the played build page' do + it 'redirects to the played job page' do expect(response).to have_http_status(:found) - expect(response).to redirect_to(namespace_project_job_path(id: build.id)) + expect(response).to redirect_to(namespace_project_job_path(id: job.id)) end it 'transits to pending' do - expect(build.reload).to be_pending + expect(job.reload).to be_pending end end - context 'when build is not playable' do - let(:build) { create(:ci_build, pipeline: pipeline) } + context 'when job is not playable' do + let(:job) { create(:ci_build, pipeline: pipeline) } it 'renders unprocessable_entity' do expect(response).to have_http_status(:unprocessable_entity) @@ -284,7 +284,7 @@ describe Projects::JobsController do def post_play post :play, namespace_id: project.namespace, project_id: project, - id: build.id + id: job.id end end @@ -296,21 +296,21 @@ describe Projects::JobsController do post_cancel end - context 'when build is cancelable' do - let(:build) { create(:ci_build, :cancelable, pipeline: pipeline) } + context 'when job is cancelable' do + let(:job) { create(:ci_build, :cancelable, pipeline: pipeline) } - it 'redirects to the canceled build page' do + it 'redirects to the canceled job page' do expect(response).to have_http_status(:found) - expect(response).to redirect_to(namespace_project_job_path(id: build.id)) + expect(response).to redirect_to(namespace_project_job_path(id: job.id)) end it 'transits to canceled' do - expect(build.reload).to be_canceled + expect(job.reload).to be_canceled end end - context 'when build is not cancelable' do - let(:build) { create(:ci_build, :canceled, pipeline: pipeline) } + context 'when job is not cancelable' do + let(:job) { create(:ci_build, :canceled, pipeline: pipeline) } it 'returns unprocessable_entity' do expect(response).to have_http_status(:unprocessable_entity) @@ -320,7 +320,7 @@ describe Projects::JobsController do def post_cancel post :cancel, namespace_id: project.namespace, project_id: project, - id: build.id + id: job.id end end @@ -330,7 +330,7 @@ describe Projects::JobsController do sign_in(user) end - context 'when builds are cancelable' do + context 'when jobs are cancelable' do before do create_list(:ci_build, 2, :cancelable, pipeline: pipeline) @@ -347,7 +347,7 @@ describe Projects::JobsController do end end - context 'when builds are not cancelable' do + context 'when jobs are not cancelable' do before do create_list(:ci_build, 2, :canceled, pipeline: pipeline) @@ -374,26 +374,26 @@ describe Projects::JobsController do post_erase end - context 'when build is erasable' do - let(:build) { create(:ci_build, :erasable, :trace, pipeline: pipeline) } + context 'when job is erasable' do + let(:job) { create(:ci_build, :erasable, :trace, pipeline: pipeline) } - it 'redirects to the erased build page' do + it 'redirects to the erased job page' do expect(response).to have_http_status(:found) - expect(response).to redirect_to(namespace_project_job_path(id: build.id)) + expect(response).to redirect_to(namespace_project_job_path(id: job.id)) end it 'erases artifacts' do - expect(build.artifacts_file.exists?).to be_falsey - expect(build.artifacts_metadata.exists?).to be_falsey + expect(job.artifacts_file.exists?).to be_falsey + expect(job.artifacts_metadata.exists?).to be_falsey end it 'erases trace' do - expect(build.trace.exist?).to be_falsey + expect(job.trace.exist?).to be_falsey end end - context 'when build is not erasable' do - let(:build) { create(:ci_build, :erased, pipeline: pipeline) } + context 'when job is not erasable' do + let(:job) { create(:ci_build, :erased, pipeline: pipeline) } it 'returns unprocessable_entity' do expect(response).to have_http_status(:unprocessable_entity) @@ -403,7 +403,7 @@ describe Projects::JobsController do def post_erase post :erase, namespace_id: project.namespace, project_id: project, - id: build.id + id: job.id end end @@ -412,8 +412,8 @@ describe Projects::JobsController do get_raw end - context 'when build has a trace file' do - let(:build) { create(:ci_build, :trace, pipeline: pipeline) } + context 'when job has a trace file' do + let(:job) { create(:ci_build, :trace, pipeline: pipeline) } it 'send a trace file' do expect(response).to have_http_status(:ok) @@ -422,8 +422,8 @@ describe Projects::JobsController do end end - context 'when build does not have a trace file' do - let(:build) { create(:ci_build, pipeline: pipeline) } + context 'when job does not have a trace file' do + let(:job) { create(:ci_build, pipeline: pipeline) } it 'returns not_found' do expect(response).to have_http_status(:not_found) @@ -433,7 +433,7 @@ describe Projects::JobsController do def get_raw post :raw, namespace_id: project.namespace, project_id: project, - id: build.id + id: job.id end end end diff --git a/spec/controllers/projects/merge_requests_controller_spec.rb b/spec/controllers/projects/merge_requests_controller_spec.rb index 6e1c91738db..d8a3a510f97 100644 --- a/spec/controllers/projects/merge_requests_controller_spec.rb +++ b/spec/controllers/projects/merge_requests_controller_spec.rb @@ -19,7 +19,10 @@ describe Projects::MergeRequestsController do render_views let(:fork_project) { create(:forked_project_with_submodules) } - before { fork_project.team << [user, :master] } + + before do + fork_project.team << [user, :master] + end context 'when rendering HTML response' do it 'renders new merge request widget template' do @@ -328,7 +331,9 @@ describe Projects::MergeRequestsController do end context 'when the sha parameter does not match the source SHA' do - before { post :merge, base_params.merge(sha: 'foo') } + before do + post :merge, base_params.merge(sha: 'foo') + end it 'returns :sha_mismatch' do expect(json_response).to eq('status' => 'sha_mismatch') @@ -473,7 +478,9 @@ describe Projects::MergeRequestsController do let(:namespace) { create(:namespace, owner: owner) } let(:project) { create(:project, namespace: namespace) } - before { sign_in owner } + before do + sign_in owner + end it "deletes the merge request" do delete :destroy, namespace_id: project.namespace, project_id: project, id: merge_request.iid @@ -505,7 +512,9 @@ describe Projects::MergeRequestsController do context 'with default params' do context 'as html' do - before { go(format: 'html') } + before do + go(format: 'html') + end it 'renders the diff template' do expect(response).to render_template('diffs') @@ -513,7 +522,9 @@ describe Projects::MergeRequestsController do end context 'as json' do - before { go(format: 'json') } + before do + go(format: 'json') + end it 'renders the diffs template to a string' do expect(response).to render_template('projects/merge_requests/show/_diffs') @@ -544,7 +555,9 @@ describe Projects::MergeRequestsController do context 'with ignore_whitespace_change' do context 'as html' do - before { go(format: 'html', w: 1) } + before do + go(format: 'html', w: 1) + end it 'renders the diff template' do expect(response).to render_template('diffs') @@ -552,7 +565,9 @@ describe Projects::MergeRequestsController do end context 'as json' do - before { go(format: 'json', w: 1) } + before do + go(format: 'json', w: 1) + end it 'renders the diffs template to a string' do expect(response).to render_template('projects/merge_requests/show/_diffs') @@ -562,7 +577,9 @@ describe Projects::MergeRequestsController do end context 'with view' do - before { go(view: 'parallel') } + before do + go(view: 'parallel') + end it 'saves the preferred diff view in a cookie' do expect(response.cookies['diff_view']).to eq('parallel') @@ -605,7 +622,9 @@ describe Projects::MergeRequestsController do end context 'when the path does not exist in the diff' do - before { diff_for_path(id: merge_request.iid, old_path: 'files/ruby/nopen.rb', new_path: 'files/ruby/nopen.rb') } + before do + diff_for_path(id: merge_request.iid, old_path: 'files/ruby/nopen.rb', new_path: 'files/ruby/nopen.rb') + end it 'returns a 404' do expect(response).to have_http_status(404) @@ -626,7 +645,9 @@ describe Projects::MergeRequestsController do end context 'when the merge request does not exist' do - before { diff_for_path(id: merge_request.iid.succ, old_path: existing_path, new_path: existing_path) } + before do + diff_for_path(id: merge_request.iid.succ, old_path: existing_path, new_path: existing_path) + end it 'returns a 404' do expect(response).to have_http_status(404) @@ -670,7 +691,9 @@ describe Projects::MergeRequestsController do context 'when the source branch is in a different project to the target' do let(:other_project) { create(:project) } - before { other_project.team << [user, :master] } + before do + other_project.team << [user, :master] + end context 'when the path exists in the diff' do it 'disables diff notes' do @@ -690,7 +713,9 @@ describe Projects::MergeRequestsController do end context 'when the path does not exist in the diff' do - before { diff_for_path(old_path: 'files/ruby/nopen.rb', new_path: 'files/ruby/nopen.rb', merge_request: { source_project: other_project, source_branch: 'feature', target_branch: 'master' }) } + before do + diff_for_path(old_path: 'files/ruby/nopen.rb', new_path: 'files/ruby/nopen.rb', merge_request: { source_project: other_project, source_branch: 'feature', target_branch: 'master' }) + end it 'returns a 404' do expect(response).to have_http_status(404) @@ -913,7 +938,9 @@ describe Projects::MergeRequestsController do end context 'when the file does not exist cannot be resolved in the UI' do - before { conflict_for_path('files/ruby/regexp.rb') } + before do + conflict_for_path('files/ruby/regexp.rb') + end it 'returns a 404 status code' do expect(response).to have_http_status(:not_found) @@ -923,7 +950,9 @@ describe Projects::MergeRequestsController do context 'with an existing file' do let(:path) { 'files/ruby/regex.rb' } - before { conflict_for_path(path) } + before do + conflict_for_path(path) + end it 'returns a 200 status code' do expect(response).to have_http_status(:ok) @@ -1195,7 +1224,9 @@ describe Projects::MergeRequestsController do end context 'when head_pipeline does not exist' do - before { get_pipeline_status } + before do + get_pipeline_status + end it 'return empty' do expect(response).to have_http_status(:ok) diff --git a/spec/controllers/projects/project_members_controller_spec.rb b/spec/controllers/projects/project_members_controller_spec.rb index 2294d5df581..f2b59ba82ca 100644 --- a/spec/controllers/projects/project_members_controller_spec.rb +++ b/spec/controllers/projects/project_members_controller_spec.rb @@ -16,10 +16,14 @@ describe Projects::ProjectMembersController do describe 'POST create' do let(:project_user) { create(:user) } - before { sign_in(user) } + before do + sign_in(user) + end context 'when user does not have enough rights' do - before { project.team << [user, :developer] } + before do + project.team << [user, :developer] + end it 'returns 404' do post :create, namespace_id: project.namespace, @@ -33,7 +37,9 @@ describe Projects::ProjectMembersController do end context 'when user has enough rights' do - before { project.team << [user, :master] } + before do + project.team << [user, :master] + end it 'adds user to members' do expect_any_instance_of(Members::CreateService).to receive(:execute).and_return(status: :success) @@ -64,7 +70,9 @@ describe Projects::ProjectMembersController do describe 'DELETE destroy' do let(:member) { create(:project_member, :developer, project: project) } - before { sign_in(user) } + before do + sign_in(user) + end context 'when member is not found' do it 'returns 404' do @@ -78,7 +86,9 @@ describe Projects::ProjectMembersController do context 'when member is found' do context 'when user does not have enough rights' do - before { project.team << [user, :developer] } + before do + project.team << [user, :developer] + end it 'returns 404' do delete :destroy, namespace_id: project.namespace, @@ -91,7 +101,9 @@ describe Projects::ProjectMembersController do end context 'when user has enough rights' do - before { project.team << [user, :master] } + before do + project.team << [user, :master] + end it '[HTML] removes user from members' do delete :destroy, namespace_id: project.namespace, @@ -117,7 +129,9 @@ describe Projects::ProjectMembersController do end describe 'DELETE leave' do - before { sign_in(user) } + before do + sign_in(user) + end context 'when member is not found' do it 'returns 404' do @@ -130,7 +144,9 @@ describe Projects::ProjectMembersController do context 'when member is found' do context 'and is not an owner' do - before { project.team << [user, :developer] } + before do + project.team << [user, :developer] + end it 'removes user from members' do delete :leave, namespace_id: project.namespace, @@ -145,7 +161,9 @@ describe Projects::ProjectMembersController do context 'and is an owner' do let(:project) { create(:empty_project, namespace: user.namespace) } - before { project.team << [user, :master] } + before do + project.team << [user, :master] + end it 'cannot remove himself from the project' do delete :leave, namespace_id: project.namespace, @@ -156,7 +174,9 @@ describe Projects::ProjectMembersController do end context 'and is a requester' do - before { project.request_access(user) } + before do + project.request_access(user) + end it 'removes user from members' do delete :leave, namespace_id: project.namespace, @@ -172,7 +192,9 @@ describe Projects::ProjectMembersController do end describe 'POST request_access' do - before { sign_in(user) } + before do + sign_in(user) + end it 'creates a new ProjectMember that is not a team member' do post :request_access, namespace_id: project.namespace, @@ -190,7 +212,9 @@ describe Projects::ProjectMembersController do describe 'POST approve' do let(:member) { create(:project_member, :access_request, project: project) } - before { sign_in(user) } + before do + sign_in(user) + end context 'when member is not found' do it 'returns 404' do @@ -204,7 +228,9 @@ describe Projects::ProjectMembersController do context 'when member is found' do context 'when user does not have enough rights' do - before { project.team << [user, :developer] } + before do + project.team << [user, :developer] + end it 'returns 404' do post :approve_access_request, namespace_id: project.namespace, @@ -217,7 +243,9 @@ describe Projects::ProjectMembersController do end context 'when user has enough rights' do - before { project.team << [user, :master] } + before do + project.team << [user, :master] + end it 'adds user to members' do post :approve_access_request, namespace_id: project.namespace, @@ -252,7 +280,10 @@ describe Projects::ProjectMembersController do end context 'when user can access source project members' do - before { another_project.team << [user, :guest] } + before do + another_project.team << [user, :guest] + end + include_context 'import applied' it 'imports source project members' do diff --git a/spec/controllers/projects/snippets_controller_spec.rb b/spec/controllers/projects/snippets_controller_spec.rb index 8c23c46798e..2434f822c6f 100644 --- a/spec/controllers/projects/snippets_controller_spec.rb +++ b/spec/controllers/projects/snippets_controller_spec.rb @@ -46,7 +46,9 @@ describe Projects::SnippetsController do end context 'when signed in as the author' do - before { sign_in(user) } + before do + sign_in(user) + end it 'renders the snippet' do get :index, namespace_id: project.namespace, project_id: project @@ -57,7 +59,9 @@ describe Projects::SnippetsController do end context 'when signed in as a project member' do - before { sign_in(user2) } + before do + sign_in(user2) + end it 'renders the snippet' do get :index, namespace_id: project.namespace, project_id: project @@ -317,7 +321,9 @@ describe Projects::SnippetsController do end context 'when signed in as the author' do - before { sign_in(user) } + before do + sign_in(user) + end it 'renders the snippet' do get action, namespace_id: project.namespace, project_id: project, id: project_snippet.to_param @@ -328,7 +334,9 @@ describe Projects::SnippetsController do end context 'when signed in as a project member' do - before { sign_in(user2) } + before do + sign_in(user2) + end it 'renders the snippet' do get action, namespace_id: project.namespace, project_id: project, id: project_snippet.to_param @@ -349,7 +357,9 @@ describe Projects::SnippetsController do end context 'when signed in' do - before { sign_in(user) } + before do + sign_in(user) + end it 'responds with status 404' do get action, namespace_id: project.namespace, project_id: project, id: 42 diff --git a/spec/controllers/projects/tags_controller_spec.rb b/spec/controllers/projects/tags_controller_spec.rb index fc97bac64cd..c48f41ca12e 100644 --- a/spec/controllers/projects/tags_controller_spec.rb +++ b/spec/controllers/projects/tags_controller_spec.rb @@ -6,7 +6,9 @@ describe Projects::TagsController do let!(:invalid_release) { create(:release, project: project, tag: 'does-not-exist') } describe 'GET index' do - before { get :index, namespace_id: project.namespace.to_param, project_id: project } + before do + get :index, namespace_id: project.namespace.to_param, project_id: project + end it 'returns the tags for the page' do expect(assigns(:tags).map(&:name)).to eq(['v1.1.0', 'v1.0.0']) @@ -19,7 +21,9 @@ describe Projects::TagsController do end describe 'GET show' do - before { get :show, namespace_id: project.namespace.to_param, project_id: project, id: id } + before do + get :show, namespace_id: project.namespace.to_param, project_id: project, id: id + end context "valid tag" do let(:id) { 'v1.0.0' } diff --git a/spec/controllers/projects_controller_spec.rb b/spec/controllers/projects_controller_spec.rb index 4f6fc6691be..240a81367d0 100644 --- a/spec/controllers/projects_controller_spec.rb +++ b/spec/controllers/projects_controller_spec.rb @@ -29,7 +29,9 @@ describe ProjectsController do describe "GET show" do context "user not project member" do - before { sign_in(user) } + before do + sign_in(user) + end context "user does not have access to project" do let(:private_project) { create(:empty_project, :private) } @@ -108,7 +110,9 @@ describe ProjectsController do context "project with empty repo" do let(:empty_project) { create(:project_empty_repo, :public) } - before { sign_in(user) } + before do + sign_in(user) + end User.project_views.keys.each do |project_view| context "with #{project_view} view set" do @@ -128,7 +132,9 @@ describe ProjectsController do context "project with broken repo" do let(:empty_project) { create(:project_broken_repo, :public) } - before { sign_in(user) } + before do + sign_in(user) + end User.project_views.keys.each do |project_view| context "with #{project_view} view set" do diff --git a/spec/controllers/search_controller_spec.rb b/spec/controllers/search_controller_spec.rb index 3173aae664c..a3708ad0908 100644 --- a/spec/controllers/search_controller_spec.rb +++ b/spec/controllers/search_controller_spec.rb @@ -18,7 +18,9 @@ describe SearchController do context 'on restricted projects' do context 'when signed out' do - before { sign_out(user) } + before do + sign_out(user) + end it "doesn't expose comments on issues" do project = create(:empty_project, :public, :issues_private) diff --git a/spec/controllers/sent_notifications_controller_spec.rb b/spec/controllers/sent_notifications_controller_spec.rb index 954fc2eaf21..0cc8a3b68eb 100644 --- a/spec/controllers/sent_notifications_controller_spec.rb +++ b/spec/controllers/sent_notifications_controller_spec.rb @@ -14,7 +14,9 @@ describe SentNotificationsController, type: :controller do describe 'GET unsubscribe' do context 'when the user is not logged in' do context 'when the force param is passed' do - before { get(:unsubscribe, id: sent_notification.reply_key, force: true) } + before do + get(:unsubscribe, id: sent_notification.reply_key, force: true) + end it 'unsubscribes the user' do expect(issue.subscribed?(user, project)).to be_falsey @@ -30,7 +32,9 @@ describe SentNotificationsController, type: :controller do end context 'when the force param is not passed' do - before { get(:unsubscribe, id: sent_notification.reply_key) } + before do + get(:unsubscribe, id: sent_notification.reply_key) + end it 'does not unsubscribe the user' do expect(issue.subscribed?(user, project)).to be_truthy @@ -47,10 +51,14 @@ describe SentNotificationsController, type: :controller do end context 'when the user is logged in' do - before { sign_in(user) } + before do + sign_in(user) + end context 'when the ID passed does not exist' do - before { get(:unsubscribe, id: sent_notification.reply_key.reverse) } + before do + get(:unsubscribe, id: sent_notification.reply_key.reverse) + end it 'does not unsubscribe the user' do expect(issue.subscribed?(user, project)).to be_truthy @@ -66,7 +74,9 @@ describe SentNotificationsController, type: :controller do end context 'when the force param is passed' do - before { get(:unsubscribe, id: sent_notification.reply_key, force: true) } + before do + get(:unsubscribe, id: sent_notification.reply_key, force: true) + end it 'unsubscribes the user' do expect(issue.subscribed?(user, project)).to be_falsey @@ -89,7 +99,10 @@ describe SentNotificationsController, type: :controller do end end let(:sent_notification) { create(:sent_notification, project: project, noteable: merge_request, recipient: user) } - before { get(:unsubscribe, id: sent_notification.reply_key) } + + before do + get(:unsubscribe, id: sent_notification.reply_key) + end it 'unsubscribes the user' do expect(merge_request.subscribed?(user, project)).to be_falsey diff --git a/spec/controllers/sessions_controller_spec.rb b/spec/controllers/sessions_controller_spec.rb index e87e24a33a1..03f4b0ba343 100644 --- a/spec/controllers/sessions_controller_spec.rb +++ b/spec/controllers/sessions_controller_spec.rb @@ -142,7 +142,9 @@ describe SessionsController do end context 'when OTP is invalid' do - before { authenticate_2fa(otp_attempt: 'invalid') } + before do + authenticate_2fa(otp_attempt: 'invalid') + end it 'does not authenticate' do expect(subject.current_user).not_to eq user @@ -169,7 +171,9 @@ describe SessionsController do end context 'when OTP is invalid' do - before { authenticate_2fa(otp_attempt: 'invalid') } + before do + authenticate_2fa(otp_attempt: 'invalid') + end it 'does not authenticate' do expect(subject.current_user).not_to eq user diff --git a/spec/controllers/snippets_controller_spec.rb b/spec/controllers/snippets_controller_spec.rb index 9073c39f562..b1339b2a185 100644 --- a/spec/controllers/snippets_controller_spec.rb +++ b/spec/controllers/snippets_controller_spec.rb @@ -437,7 +437,9 @@ describe SnippetsController do end context 'when signed in user is the author' do - before { get :raw, id: personal_snippet.to_param } + before do + get :raw, id: personal_snippet.to_param + end it 'responds with status 200' do expect(assigns(:snippet)).to eq(personal_snippet) diff --git a/spec/controllers/users_controller_spec.rb b/spec/controllers/users_controller_spec.rb index d33e2ba1e53..842d82cdbe9 100644 --- a/spec/controllers/users_controller_spec.rb +++ b/spec/controllers/users_controller_spec.rb @@ -43,7 +43,9 @@ describe UsersController do end context 'when logged in' do - before { sign_in(user) } + before do + sign_in(user) + end it 'renders show' do get :show, username: user.username @@ -62,7 +64,9 @@ describe UsersController do end context 'when logged in' do - before { sign_in(user) } + before do + sign_in(user) + end it 'renders 404' do get :show, username: 'nonexistent' diff --git a/spec/features/admin/admin_runners_spec.rb b/spec/features/admin/admin_runners_spec.rb index 5dcc7d35d82..bc11b090fdb 100644 --- a/spec/features/admin/admin_runners_spec.rb +++ b/spec/features/admin/admin_runners_spec.rb @@ -134,7 +134,10 @@ describe "Admin Runners" do describe 'runners registration token' do let!(:token) { current_application_settings.runners_registration_token } - before { visit admin_runners_path } + + before do + visit admin_runners_path + end it 'has a registration token' do expect(page).to have_content("Registration token is #{token}") diff --git a/spec/features/admin/admin_settings_spec.rb b/spec/features/admin/admin_settings_spec.rb index 5099441dce2..27bc25be580 100644 --- a/spec/features/admin/admin_settings_spec.rb +++ b/spec/features/admin/admin_settings_spec.rb @@ -20,10 +20,15 @@ feature 'Admin updates settings', feature: true do uncheck 'Gravatar enabled' fill_in 'Home page URL', with: 'https://about.gitlab.com/' fill_in 'Help page text', with: 'Example text' + check 'Hide marketing-related entries from help' + fill_in 'Support page URL', with: 'http://example.com/help' click_button 'Save' expect(current_application_settings.gravatar_enabled).to be_falsey expect(current_application_settings.home_page_url).to eq "https://about.gitlab.com/" + expect(current_application_settings.help_page_text).to eq "Example text" + expect(current_application_settings.help_page_hide_commercial_content).to be_truthy + expect(current_application_settings.help_page_support_url).to eq "http://example.com/help" expect(page).to have_content "Application settings saved successfully" end diff --git a/spec/features/admin/admin_users_impersonation_tokens_spec.rb b/spec/features/admin/admin_users_impersonation_tokens_spec.rb index 0fb4baeb71c..849ec829f75 100644 --- a/spec/features/admin/admin_users_impersonation_tokens_spec.rb +++ b/spec/features/admin/admin_users_impersonation_tokens_spec.rb @@ -12,7 +12,9 @@ describe 'Admin > Users > Impersonation Tokens', feature: true, js: true do find(".table.inactive-tokens") end - before { login_as(admin) } + before do + login_as(admin) + end describe "token creation" do it "allows creation of a token" do diff --git a/spec/features/admin/admin_users_spec.rb b/spec/features/admin/admin_users_spec.rb index 301a47169a4..f72651667ee 100644 --- a/spec/features/admin/admin_users_spec.rb +++ b/spec/features/admin/admin_users_spec.rb @@ -124,7 +124,10 @@ describe "Admin::Users", feature: true do describe 'Impersonation' do let(:another_user) { create(:user) } - before { visit admin_user_path(another_user) } + + before do + visit admin_user_path(another_user) + end context 'before impersonating' do it 'shows impersonate button for other users' do @@ -149,7 +152,9 @@ describe "Admin::Users", feature: true do end context 'when impersonating' do - before { click_link 'Impersonate' } + before do + click_link 'Impersonate' + end it 'logs in as the user when impersonate is clicked' do expect(page.find(:css, '.header-user .profile-link')['data-user']).to eql(another_user.username) diff --git a/spec/features/dashboard/merge_requests_spec.rb b/spec/features/dashboard/merge_requests_spec.rb index 9cebe52c444..bcb52f602b0 100644 --- a/spec/features/dashboard/merge_requests_spec.rb +++ b/spec/features/dashboard/merge_requests_spec.rb @@ -12,7 +12,9 @@ describe 'Dashboard Merge Requests' do end describe 'new merge request dropdown' do - before { visit merge_requests_dashboard_path } + before do + visit merge_requests_dashboard_path + end it 'shows projects only with merge requests feature enabled', js: true do find('.new-project-item-select-button').trigger('click') diff --git a/spec/features/dashboard/project_member_activity_index_spec.rb b/spec/features/dashboard/project_member_activity_index_spec.rb index cdf919af9b5..0ba87d921d0 100644 --- a/spec/features/dashboard/project_member_activity_index_spec.rb +++ b/spec/features/dashboard/project_member_activity_index_spec.rb @@ -17,19 +17,25 @@ feature 'Project member activity', feature: true, js: true do subject { page.find(".event-title").text } context 'when a user joins the project' do - before { visit_activities_and_wait_with_event(Event::JOINED) } + before do + visit_activities_and_wait_with_event(Event::JOINED) + end it { is_expected.to eq("#{user.name} joined project") } end context 'when a user leaves the project' do - before { visit_activities_and_wait_with_event(Event::LEFT) } + before do + visit_activities_and_wait_with_event(Event::LEFT) + end it { is_expected.to eq("#{user.name} left project") } end context 'when a users membership expires for the project' do - before { visit_activities_and_wait_with_event(Event::EXPIRED) } + before do + visit_activities_and_wait_with_event(Event::EXPIRED) + end it "presents the correct message" do message = "#{user.name} removed due to membership expiration from project" diff --git a/spec/features/expand_collapse_diffs_spec.rb b/spec/features/expand_collapse_diffs_spec.rb index c4d5077e5e1..36b0c371e6e 100644 --- a/spec/features/expand_collapse_diffs_spec.rb +++ b/spec/features/expand_collapse_diffs_spec.rb @@ -140,7 +140,9 @@ feature 'Expand and collapse diffs', js: true, feature: true do end context 'reloading the page' do - before { refresh } + before do + refresh + end it 'collapses the large diff by default' do expect(large_diff).not_to have_selector('.code') @@ -262,7 +264,7 @@ feature 'Expand and collapse diffs', js: true, feature: true do # Wait for elements to appear to ensure full page reload expect(page).to have_content('This diff was suppressed by a .gitattributes entry') - expect(page).to have_content('This diff could not be displayed because it is too large.') + expect(page).to have_content('This source diff could not be displayed because it is too large.') expect(page).to have_content('too_large_image.jpg') find('.note-textarea') diff --git a/spec/features/groups/group_settings_spec.rb b/spec/features/groups/group_settings_spec.rb index cc25db4ad60..6afde1d0bed 100644 --- a/spec/features/groups/group_settings_spec.rb +++ b/spec/features/groups/group_settings_spec.rb @@ -52,9 +52,14 @@ feature 'Edit group settings', feature: true do given!(:project) { create(:project, group: group, path: 'project') } given(:old_project_full_path) { "/#{group.path}/#{project.path}" } given(:new_project_full_path) { "/#{new_group_path}/#{project.path}" } - - before(:context) { TestEnv.clean_test_path } - after(:example) { TestEnv.clean_test_path } + + before(:context) do + TestEnv.clean_test_path + end + + after(:example) do + TestEnv.clean_test_path + end scenario 'the project is accessible via the new path' do update_path(new_group_path) diff --git a/spec/features/groups_spec.rb b/spec/features/groups_spec.rb index 24ea7aba0cc..5737ca39b4e 100644 --- a/spec/features/groups_spec.rb +++ b/spec/features/groups_spec.rb @@ -12,7 +12,9 @@ feature 'Group', feature: true do end describe 'create a group' do - before { visit new_group_path } + before do + visit new_group_path + end describe 'with space in group path' do it 'renders new group form with validation errors' do @@ -138,7 +140,9 @@ feature 'Group', feature: true do let(:path) { edit_group_path(group) } let(:new_name) { 'new-name' } - before { visit path } + before do + visit path + end it 'saves new settings' do fill_in 'group_name', with: new_name diff --git a/spec/features/help_pages_spec.rb b/spec/features/help_pages_spec.rb index 31014f5cad2..18102146b5f 100644 --- a/spec/features/help_pages_spec.rb +++ b/spec/features/help_pages_spec.rb @@ -37,7 +37,7 @@ describe 'Help Pages', feature: true do context 'in a production environment with version check enabled', :js do before do allow(Rails.env).to receive(:production?) { true } - allow(current_application_settings).to receive(:version_check_enabled) { true } + allow_any_instance_of(ApplicationSetting).to receive(:version_check_enabled) { true } allow_any_instance_of(VersionCheck).to receive(:url) { '/version-check-url' } login_as :user @@ -53,4 +53,27 @@ describe 'Help Pages', feature: true do expect(find('.js-version-status-badge', visible: false)).not_to be_visible end end + + describe 'when help page is customized' do + before do + allow_any_instance_of(ApplicationSetting).to receive(:help_page_hide_commercial_content?) { true } + allow_any_instance_of(ApplicationSetting).to receive(:help_page_text) { "My Custom Text" } + allow_any_instance_of(ApplicationSetting).to receive(:help_page_support_url) { "http://example.com/help" } + + login_as :user + visit help_path + end + + it 'should display custom help page text' do + expect(page).to have_text "My Custom Text" + end + + it 'should hide marketing content when enabled' do + expect(page).not_to have_link "Get a support subscription" + end + + it 'should use a custom support url' do + expect(page).to have_link "See our website for getting help", href: "http://example.com/help" + end + end end diff --git a/spec/features/issuables/default_sort_order_spec.rb b/spec/features/issuables/default_sort_order_spec.rb index bfe43bff10f..56c9b10e757 100644 --- a/spec/features/issuables/default_sort_order_spec.rb +++ b/spec/features/issuables/default_sort_order_spec.rb @@ -153,7 +153,9 @@ describe 'Projects > Issuables > Default sort order', feature: true do context 'when the sort in the URL is id_desc' do let(:issuable_type) { :issue } - before { visit_issues(project, sort: 'id_desc') } + before do + visit_issues(project, sort: 'id_desc') + end it 'shows the sort order as last created' do expect(find('.issues-other-filters')).to have_content('Last created') @@ -165,7 +167,9 @@ describe 'Projects > Issuables > Default sort order', feature: true do context 'when the sort in the URL is id_asc' do let(:issuable_type) { :issue } - before { visit_issues(project, sort: 'id_asc') } + before do + visit_issues(project, sort: 'id_asc') + end it 'shows the sort order as oldest created' do expect(find('.issues-other-filters')).to have_content('Oldest created') diff --git a/spec/features/issues_spec.rb b/spec/features/issues_spec.rb index eecc565d2bd..2cff53539f3 100644 --- a/spec/features/issues_spec.rb +++ b/spec/features/issues_spec.rb @@ -246,7 +246,10 @@ describe 'Issues', feature: true do context 'with a filter on labels' do let(:label) { create(:label, project: project) } - before { create(:label_link, label: label, target: foo) } + + before do + create(:label_link, label: label, target: foo) + end it 'sorts by least recently due date by excluding nil due dates' do bar.update(due_date: nil) diff --git a/spec/features/login_spec.rb b/spec/features/login_spec.rb index c82e8c03343..4763f454810 100644 --- a/spec/features/login_spec.rb +++ b/spec/features/login_spec.rb @@ -202,10 +202,12 @@ feature 'Login', feature: true do # TODO: otp_grace_period_started_at context 'global setting' do - before(:each) { stub_application_setting(require_two_factor_authentication: true) } + before do + stub_application_setting(require_two_factor_authentication: true) + end context 'with grace period defined' do - before(:each) do + before do stub_application_setting(two_factor_grace_period: 48) login_with(user) end @@ -242,7 +244,7 @@ feature 'Login', feature: true do end context 'without grace period defined' do - before(:each) do + before do stub_application_setting(two_factor_grace_period: 0) login_with(user) end @@ -265,7 +267,7 @@ feature 'Login', feature: true do end context 'with grace period defined' do - before(:each) do + before do stub_application_setting(two_factor_grace_period: 48) login_with(user) end @@ -306,7 +308,7 @@ feature 'Login', feature: true do end context 'without grace period defined' do - before(:each) do + before do stub_application_setting(two_factor_grace_period: 0) login_with(user) end diff --git a/spec/features/merge_requests/conflicts_spec.rb b/spec/features/merge_requests/conflicts_spec.rb index 27e2d5d16f3..9409c32104b 100644 --- a/spec/features/merge_requests/conflicts_spec.rb +++ b/spec/features/merge_requests/conflicts_spec.rb @@ -85,14 +85,18 @@ feature 'Merge request conflict resolution', js: true, feature: true do context 'the conflicts are resolvable' do let(:merge_request) { create_merge_request('conflict-resolvable') } - before { visit namespace_project_merge_request_path(project.namespace, project, merge_request) } + before do + visit namespace_project_merge_request_path(project.namespace, project, merge_request) + end it 'shows a link to the conflict resolution page' do expect(page).to have_link('conflicts', href: /\/conflicts\Z/) end context 'in Inline view mode' do - before { click_link('conflicts', href: /\/conflicts\Z/) } + before do + click_link('conflicts', href: /\/conflicts\Z/) + end include_examples "conflicts are resolved in Interactive mode" include_examples "conflicts are resolved in Edit inline mode" diff --git a/spec/features/merge_requests/merge_immediately_with_pipeline_spec.rb b/spec/features/merge_requests/merge_immediately_with_pipeline_spec.rb index c1d4d508e57..836a7b6e09a 100644 --- a/spec/features/merge_requests/merge_immediately_with_pipeline_spec.rb +++ b/spec/features/merge_requests/merge_immediately_with_pipeline_spec.rb @@ -18,7 +18,9 @@ feature 'Merge immediately', :feature, :js do sha: project.repository.commit('master').id) end - before { project.team << [user, :master] } + before do + project.team << [user, :master] + end context 'when there is active pipeline for merge request' do background do diff --git a/spec/features/milestones/milestones_spec.rb b/spec/features/milestones/milestones_spec.rb index b3dfd6d0e81..c8a4d23f695 100644 --- a/spec/features/milestones/milestones_spec.rb +++ b/spec/features/milestones/milestones_spec.rb @@ -37,6 +37,14 @@ describe 'Milestone draggable', feature: true, js: true do expect(issue_target).to have_selector('.issuable-row') end + + it 'assigns issue when it has been dragged to ongoing list' do + login_as(:admin) + create_and_drag_issue + + expect(@issue.reload.assignees).not_to be_empty + expect(page).to have_selector("#sortable_issue_#{@issue.iid} .assignee-icon img", count: 1) + end end context 'merge requests' do @@ -72,7 +80,7 @@ describe 'Milestone draggable', feature: true, js: true do end def create_and_drag_issue(params = {}) - create(:issue, params.merge(title: 'Foo', project: project, milestone: milestone)) + @issue = create(:issue, params.merge(title: 'Foo', project: project, milestone: milestone)) visit namespace_project_milestone_path(project.namespace, project, milestone) scroll_into_view('.milestone-content') diff --git a/spec/features/profiles/account_spec.rb b/spec/features/profiles/account_spec.rb index 05a7587f8d4..89868c737f7 100644 --- a/spec/features/profiles/account_spec.rb +++ b/spec/features/profiles/account_spec.rb @@ -31,8 +31,13 @@ feature 'Profile > Account', feature: true do given(:new_project_path) { "/#{new_username}/#{project.path}" } given(:old_project_path) { "/#{user.username}/#{project.path}" } - before(:context) { TestEnv.clean_test_path } - after(:example) { TestEnv.clean_test_path } + before(:context) do + TestEnv.clean_test_path + end + + after(:example) do + TestEnv.clean_test_path + end scenario 'the project is accessible via the new path' do update_username(new_username) diff --git a/spec/features/projects/blobs/blob_show_spec.rb b/spec/features/projects/blobs/blob_show_spec.rb index 45fdb36e506..71ffa352f80 100644 --- a/spec/features/projects/blobs/blob_show_spec.rb +++ b/spec/features/projects/blobs/blob_show_spec.rb @@ -17,6 +17,7 @@ feature 'File blob', :js, feature: true do it 'displays the blob' do aggregate_failures do # shows highlighted Ruby code + expect(page).to have_css(".js-syntax-highlight") expect(page).to have_content("require 'fileutils'") # does not show a viewer switcher @@ -71,6 +72,7 @@ feature 'File blob', :js, feature: true do expect(page).to have_selector('.blob-viewer[data-type="rich"]', visible: false) # shows highlighted Markdown code + expect(page).to have_css(".js-syntax-highlight") expect(page).to have_content("[PEP-8](http://www.python.org/dev/peps/pep-0008/)") # shows an enabled copy button @@ -114,6 +116,7 @@ feature 'File blob', :js, feature: true do expect(page).to have_selector('#LC1.hll') # shows highlighted Markdown code + expect(page).to have_css(".js-syntax-highlight") expect(page).to have_content("[PEP-8](http://www.python.org/dev/peps/pep-0008/)") # shows an enabled copy button diff --git a/spec/features/projects/diffs/diff_show_spec.rb b/spec/features/projects/diffs/diff_show_spec.rb new file mode 100644 index 00000000000..48b7f1e0f34 --- /dev/null +++ b/spec/features/projects/diffs/diff_show_spec.rb @@ -0,0 +1,133 @@ +require 'spec_helper' + +feature 'Diff file viewer', :js, feature: true do + let(:project) { create(:project, :public, :repository) } + + def visit_commit(sha, anchor: nil) + visit namespace_project_commit_path(project.namespace, project, sha, anchor: anchor) + + wait_for_requests + end + + context 'Ruby file' do + before do + visit_commit('570e7b2abdd848b95f2f578043fc23bd6f6fd24d') + end + + it 'shows highlighted Ruby code' do + within('.diff-file[id="2f6fcd96b88b36ce98c38da085c795a27d92a3dd"]') do + expect(page).to have_css(".js-syntax-highlight") + expect(page).to have_content("def popen(cmd, path=nil)") + end + end + end + + context 'Ruby file (stored in LFS)' do + before do + project.add_master(project.creator) + + @commit_id = Files::CreateService.new( + project, + project.creator, + start_branch: 'master', + branch_name: 'master', + commit_message: "Add Ruby file in LFS", + file_path: 'files/lfs/ruby.rb', + file_content: project.repository.blob_at('master', 'files/lfs/lfs_object.iso').data + ).execute[:result] + end + + context 'when LFS is enabled on the project' do + before do + allow(Gitlab.config.lfs).to receive(:enabled).and_return(true) + project.update_attribute(:lfs_enabled, true) + + visit_commit(@commit_id) + end + + it 'shows an error message' do + expect(page).to have_content('This source diff could not be displayed because it is stored in LFS. You can view the blob instead.') + end + end + + context 'when LFS is disabled on the project' do + before do + visit_commit(@commit_id) + end + + it 'displays the diff' do + expect(page).to have_content('size 1575078') + end + end + end + + context 'Image file' do + before do + visit_commit('2f63565e7aac07bcdadb654e253078b727143ec4') + end + + it 'shows a rendered image' do + within('.diff-file[id="e986451b8f7397b617dbb6fffcb5539328c56921"]') do + expect(page).to have_css('img[alt="files/images/6049019_460s.jpg"]') + end + end + end + + context 'ISO file (stored in LFS)' do + context 'when LFS is enabled on the project' do + before do + allow(Gitlab.config.lfs).to receive(:enabled).and_return(true) + project.update_attribute(:lfs_enabled, true) + + visit_commit('048721d90c449b244b7b4c53a9186b04330174ec') + end + + it 'shows that file was added' do + expect(page).to have_content('File added') + end + end + + context 'when LFS is disabled on the project' do + before do + visit_commit('048721d90c449b244b7b4c53a9186b04330174ec') + end + + it 'displays the diff' do + expect(page).to have_content('size 1575078') + end + end + end + + context 'ZIP file' do + before do + visit_commit('ae73cb07c9eeaf35924a10f713b364d32b2dd34f') + end + + it 'shows that file was added' do + expect(page).to have_content('File added') + end + end + + context 'binary file that appears to be text in the first 1024 bytes' do + before do + visit_commit('7b1cf4336b528e0f3d1d140ee50cafdbc703597c') + end + + it 'shows the diff is collapsed' do + expect(page).to have_content('This diff is collapsed. Click to expand it.') + end + + context 'expanding the diff' do + before do + # We can't use `click_link` because the "link" doesn't have an `href`. + find('a.click-to-expand').click + + wait_for_requests + end + + it 'shows there is no preview' do + expect(page).to have_content('No preview for this file type') + end + end + end +end diff --git a/spec/features/projects/jobs_spec.rb b/spec/features/projects/jobs_spec.rb index 727ae7081b0..31c93c75d25 100644 --- a/spec/features/projects/jobs_spec.rb +++ b/spec/features/projects/jobs_spec.rb @@ -8,8 +8,8 @@ feature 'Jobs', :feature do let(:namespace) { project.namespace } let(:pipeline) { create(:ci_pipeline, project: project) } - let(:build) { create(:ci_build, :trace, pipeline: pipeline) } - let(:build2) { create(:ci_build) } + let(:job) { create(:ci_build, :trace, pipeline: pipeline) } + let(:job2) { create(:ci_build) } let(:artifacts_file) do fixture_file_upload(Rails.root + 'spec/fixtures/banana_sample.gif', 'image/gif') @@ -21,7 +21,7 @@ feature 'Jobs', :feature do end describe "GET /:project/jobs" do - let!(:build) { create(:ci_build, pipeline: pipeline) } + let!(:job) { create(:ci_build, pipeline: pipeline) } context "Pending scope" do before do @@ -31,30 +31,30 @@ feature 'Jobs', :feature do it "shows Pending tab jobs" do expect(page).to have_link 'Cancel running' expect(page).to have_selector('.nav-links li.active', text: 'Pending') - expect(page).to have_content build.short_sha - expect(page).to have_content build.ref - expect(page).to have_content build.name + expect(page).to have_content job.short_sha + expect(page).to have_content job.ref + expect(page).to have_content job.name end end context "Running scope" do before do - build.run! + job.run! visit namespace_project_jobs_path(project.namespace, project, scope: :running) end it "shows Running tab jobs" do expect(page).to have_selector('.nav-links li.active', text: 'Running') expect(page).to have_link 'Cancel running' - expect(page).to have_content build.short_sha - expect(page).to have_content build.ref - expect(page).to have_content build.name + expect(page).to have_content job.short_sha + expect(page).to have_content job.ref + expect(page).to have_content job.name end end context "Finished scope" do before do - build.run! + job.run! visit namespace_project_jobs_path(project.namespace, project, scope: :finished) end @@ -73,9 +73,9 @@ feature 'Jobs', :feature do it "shows All tab jobs" do expect(page).to have_selector('.nav-links li.active', text: 'All') - expect(page).to have_content build.short_sha - expect(page).to have_content build.ref - expect(page).to have_content build.name + expect(page).to have_content job.short_sha + expect(page).to have_content job.ref + expect(page).to have_content job.name expect(page).not_to have_link 'Cancel running' end end @@ -97,7 +97,7 @@ feature 'Jobs', :feature do describe "POST /:project/jobs/:id/cancel_all" do before do - build.run! + job.run! visit namespace_project_jobs_path(project.namespace, project) click_link "Cancel running" end @@ -105,19 +105,19 @@ feature 'Jobs', :feature do it 'shows all necessary content' do expect(page).to have_selector('.nav-links li.active', text: 'All') expect(page).to have_content 'canceled' - expect(page).to have_content build.short_sha - expect(page).to have_content build.ref - expect(page).to have_content build.name + expect(page).to have_content job.short_sha + expect(page).to have_content job.ref + expect(page).to have_content job.name expect(page).not_to have_link 'Cancel running' end end describe "GET /:project/jobs/:id" do context "Job from project" do - let(:build) { create(:ci_build, :success, pipeline: pipeline) } + let(:job) { create(:ci_build, :success, pipeline: pipeline) } before do - visit namespace_project_job_path(project.namespace, project, build) + visit namespace_project_job_path(project.namespace, project, job) end it 'shows status name', :js do @@ -131,33 +131,33 @@ feature 'Jobs', :feature do expect(page).to have_content pipeline.git_author_name end - it 'shows active build' do + it 'shows active job' do expect(page).to have_selector('.build-job.active') end end context 'when job is not running', :js do - let(:build) { create(:ci_build, :success, pipeline: pipeline) } + let(:job) { create(:ci_build, :success, pipeline: pipeline) } before do - visit namespace_project_job_path(project.namespace, project, build) + visit namespace_project_job_path(project.namespace, project, job) end it 'shows retry button' do expect(page).to have_link('Retry') end - context 'if build passed' do + context 'if job passed' do it 'does not show New issue button' do expect(page).not_to have_link('New issue') end end - context 'if build failed' do - let(:build) { create(:ci_build, :failed, pipeline: pipeline) } + context 'if job failed' do + let(:job) { create(:ci_build, :failed, pipeline: pipeline) } before do - visit namespace_project_job_path(namespace, project, build) + visit namespace_project_job_path(namespace, project, job) end it 'shows New issue button' do @@ -165,9 +165,9 @@ feature 'Jobs', :feature do end it 'links to issues/new with the title and description filled in' do - button_title = "Build Failed ##{build.id}" - build_path = namespace_project_job_path(namespace, project, build) - options = { issue: { title: button_title, description: build_path } } + button_title = "Build Failed ##{job.id}" + job_path = namespace_project_job_path(namespace, project, job) + options = { issue: { title: button_title, description: job_path } } href = new_namespace_project_issue_path(namespace, project, options) @@ -180,7 +180,7 @@ feature 'Jobs', :feature do context "Job from other project" do before do - visit namespace_project_job_path(project.namespace, project, build2) + visit namespace_project_job_path(project.namespace, project, job2) end it { expect(page.status_code).to eq(404) } @@ -188,8 +188,8 @@ feature 'Jobs', :feature do context "Download artifacts" do before do - build.update_attributes(artifacts_file: artifacts_file) - visit namespace_project_job_path(project.namespace, project, build) + job.update_attributes(artifacts_file: artifacts_file) + visit namespace_project_job_path(project.namespace, project, job) end it 'has button to download artifacts' do @@ -199,10 +199,10 @@ feature 'Jobs', :feature do context 'Artifacts expire date' do before do - build.update_attributes(artifacts_file: artifacts_file, - artifacts_expire_at: expire_at) + job.update_attributes(artifacts_file: artifacts_file, + artifacts_expire_at: expire_at) - visit namespace_project_job_path(project.namespace, project, build) + visit namespace_project_job_path(project.namespace, project, job) end context 'no expire date defined' do @@ -248,7 +248,7 @@ feature 'Jobs', :feature do context "when visiting old URL" do let(:job_url) do - namespace_project_job_path(project.namespace, project, build) + namespace_project_job_path(project.namespace, project, job) end before do @@ -262,9 +262,9 @@ feature 'Jobs', :feature do feature 'Raw trace' do before do - build.run! + job.run! - visit namespace_project_job_path(project.namespace, project, build) + visit namespace_project_job_path(project.namespace, project, job) end it do @@ -274,16 +274,16 @@ feature 'Jobs', :feature do feature 'HTML trace', :js do before do - build.run! + job.run! - visit namespace_project_job_path(project.namespace, project, build) + visit namespace_project_job_path(project.namespace, project, job) end context 'when job has an initial trace' do it 'loads job trace' do expect(page).to have_content 'BUILD TRACE' - build.trace.write do |stream| + job.trace.write do |stream| stream.append(' and more trace', 11) end @@ -295,12 +295,12 @@ feature 'Jobs', :feature do feature 'Variables' do let(:trigger_request) { create(:ci_trigger_request_with_variables) } - let(:build) do + let(:job) do create :ci_build, pipeline: pipeline, trigger_request: trigger_request end before do - visit namespace_project_job_path(project.namespace, project, build) + visit namespace_project_job_path(project.namespace, project, job) end it 'shows variable key and value after click', js: true do @@ -322,20 +322,20 @@ feature 'Jobs', :feature do context 'job is successfull and has deployment' do let(:deployment) { create(:deployment) } - let(:build) { create(:ci_build, :success, environment: environment.name, deployments: [deployment], pipeline: pipeline) } + let(:job) { create(:ci_build, :success, environment: environment.name, deployments: [deployment], pipeline: pipeline) } it 'shows a link for the job' do - visit namespace_project_job_path(project.namespace, project, build) + visit namespace_project_job_path(project.namespace, project, job) expect(page).to have_link environment.name end end context 'job is complete and not successful' do - let(:build) { create(:ci_build, :failed, environment: environment.name, pipeline: pipeline) } + let(:job) { create(:ci_build, :failed, environment: environment.name, pipeline: pipeline) } it 'shows a link for the job' do - visit namespace_project_job_path(project.namespace, project, build) + visit namespace_project_job_path(project.namespace, project, job) expect(page).to have_link environment.name end @@ -343,10 +343,10 @@ feature 'Jobs', :feature do context 'job creates a new deployment' do let!(:deployment) { create(:deployment, environment: environment, sha: project.commit.id) } - let(:build) { create(:ci_build, :success, environment: environment.name, pipeline: pipeline) } + let(:job) { create(:ci_build, :success, environment: environment.name, pipeline: pipeline) } it 'shows a link to latest deployment' do - visit namespace_project_job_path(project.namespace, project, build) + visit namespace_project_job_path(project.namespace, project, job) expect(page).to have_link('latest deployment') end @@ -357,8 +357,8 @@ feature 'Jobs', :feature do describe "POST /:project/jobs/:id/cancel", :js do context "Job from project" do before do - build.run! - visit namespace_project_job_path(project.namespace, project, build) + job.run! + visit namespace_project_job_path(project.namespace, project, job) find('.js-cancel-job').click() end @@ -372,8 +372,8 @@ feature 'Jobs', :feature do describe "POST /:project/jobs/:id/retry" do context "Job from project", :js do before do - build.run! - visit namespace_project_job_path(project.namespace, project, build) + job.run! + visit namespace_project_job_path(project.namespace, project, job) find('.js-cancel-job').click() find('.js-retry-button').trigger('click') end @@ -388,13 +388,13 @@ feature 'Jobs', :feature do context "Job that current user is not allowed to retry" do before do - build.run! - build.cancel! + job.run! + job.cancel! project.update(visibility_level: Gitlab::VisibilityLevel::PUBLIC) logout_direct login_with(create(:user)) - visit namespace_project_job_path(project.namespace, project, build) + visit namespace_project_job_path(project.namespace, project, job) end it 'does not show the Retry button' do @@ -407,15 +407,15 @@ feature 'Jobs', :feature do describe "GET /:project/jobs/:id/download" do before do - build.update_attributes(artifacts_file: artifacts_file) - visit namespace_project_job_path(project.namespace, project, build) + job.update_attributes(artifacts_file: artifacts_file) + visit namespace_project_job_path(project.namespace, project, job) click_link 'Download' end context "Build from other project" do before do - build2.update_attributes(artifacts_file: artifacts_file) - visit download_namespace_project_job_artifacts_path(project.namespace, project, build2) + job2.update_attributes(artifacts_file: artifacts_file) + visit download_namespace_project_job_artifacts_path(project.namespace, project, job2) end it { expect(page.status_code).to eq(404) } @@ -427,23 +427,23 @@ feature 'Jobs', :feature do context 'job from project' do before do Capybara.current_session.driver.headers = { 'X-Sendfile-Type' => 'X-Sendfile' } - build.run! - visit namespace_project_job_path(project.namespace, project, build) + job.run! + visit namespace_project_job_path(project.namespace, project, job) find('.js-raw-link-controller').click() end it 'sends the right headers' do expect(page.status_code).to eq(200) expect(page.response_headers['Content-Type']).to eq('text/plain; charset=utf-8') - expect(page.response_headers['X-Sendfile']).to eq(build.trace.send(:current_path)) + expect(page.response_headers['X-Sendfile']).to eq(job.trace.send(:current_path)) end end context 'job from other project' do before do Capybara.current_session.driver.headers = { 'X-Sendfile-Type' => 'X-Sendfile' } - build2.run! - visit raw_namespace_project_job_path(project.namespace, project, build2) + job2.run! + visit raw_namespace_project_job_path(project.namespace, project, job2) end it 'sends the right headers' do @@ -458,16 +458,16 @@ feature 'Jobs', :feature do before do Capybara.current_session.driver.headers = { 'X-Sendfile-Type' => 'X-Sendfile' } - build.run! + job.run! end - context 'when build has trace in file', :js do + context 'when job has trace in file', :js do before do allow_any_instance_of(Gitlab::Ci::Trace) .to receive(:paths) .and_return([existing_file]) - visit namespace_project_job_path(namespace, project, build) + visit namespace_project_job_path(namespace, project, job) find('.js-raw-link-controller').click end @@ -485,7 +485,7 @@ feature 'Jobs', :feature do .to receive(:paths) .and_return([]) - visit namespace_project_job_path(namespace, project, build) + visit namespace_project_job_path(namespace, project, job) end it 'sends the right headers' do @@ -496,7 +496,7 @@ feature 'Jobs', :feature do context "when visiting old URL" do let(:raw_job_url) do - raw_namespace_project_job_path(project.namespace, project, build) + raw_namespace_project_job_path(project.namespace, project, job) end before do @@ -512,7 +512,7 @@ feature 'Jobs', :feature do describe "GET /:project/jobs/:id/trace.json" do context "Job from project" do before do - visit trace_namespace_project_job_path(project.namespace, project, build, format: :json) + visit trace_namespace_project_job_path(project.namespace, project, job, format: :json) end it { expect(page.status_code).to eq(200) } @@ -520,7 +520,7 @@ feature 'Jobs', :feature do context "Job from other project" do before do - visit trace_namespace_project_job_path(project.namespace, project, build2, format: :json) + visit trace_namespace_project_job_path(project.namespace, project, job2, format: :json) end it { expect(page.status_code).to eq(404) } @@ -530,7 +530,7 @@ feature 'Jobs', :feature do describe "GET /:project/jobs/:id/status" do context "Job from project" do before do - visit status_namespace_project_job_path(project.namespace, project, build) + visit status_namespace_project_job_path(project.namespace, project, job) end it { expect(page.status_code).to eq(200) } @@ -538,7 +538,7 @@ feature 'Jobs', :feature do context "Job from other project" do before do - visit status_namespace_project_job_path(project.namespace, project, build2) + visit status_namespace_project_job_path(project.namespace, project, job2) end it { expect(page.status_code).to eq(404) } diff --git a/spec/features/projects/pipelines/pipeline_spec.rb b/spec/features/projects/pipelines/pipeline_spec.rb index 36a3ddca6ef..12c5ad45baf 100644 --- a/spec/features/projects/pipelines/pipeline_spec.rb +++ b/spec/features/projects/pipelines/pipeline_spec.rb @@ -47,7 +47,9 @@ describe 'Pipeline', :feature, :js do let(:project) { create(:project) } let(:pipeline) { create(:ci_pipeline, project: project, ref: 'master', sha: project.commit.id, user: user) } - before { visit namespace_project_pipeline_path(project.namespace, project, pipeline) } + before do + visit namespace_project_pipeline_path(project.namespace, project, pipeline) + end it 'shows the pipeline graph' do expect(page).to have_selector('.pipeline-visualization') @@ -164,7 +166,9 @@ describe 'Pipeline', :feature, :js do it { expect(page).not_to have_content('retried') } context 'when retrying' do - before { find('.js-retry-button').trigger('click') } + before do + find('.js-retry-button').trigger('click') + end it { expect(page).not_to have_content('Retry') } end @@ -174,7 +178,9 @@ describe 'Pipeline', :feature, :js do it { expect(page).not_to have_selector('.ci-canceled') } context 'when canceling' do - before { click_on 'Cancel running' } + before do + click_on 'Cancel running' + end it { expect(page).not_to have_content('Cancel running') } end @@ -226,7 +232,9 @@ describe 'Pipeline', :feature, :js do it { expect(page).not_to have_content('retried') } context 'when retrying' do - before { find('.js-retry-button').trigger('click') } + before do + find('.js-retry-button').trigger('click') + end it { expect(page).not_to have_content('Retry') } end @@ -236,7 +244,9 @@ describe 'Pipeline', :feature, :js do it { expect(page).not_to have_selector('.ci-canceled') } context 'when canceling' do - before { click_on 'Cancel running' } + before do + click_on 'Cancel running' + end it { expect(page).not_to have_content('Cancel running') } end diff --git a/spec/features/projects/pipelines/pipelines_spec.rb b/spec/features/projects/pipelines/pipelines_spec.rb index 05c2bf350f1..026e2ce5b68 100644 --- a/spec/features/projects/pipelines/pipelines_spec.rb +++ b/spec/features/projects/pipelines/pipelines_spec.rb @@ -149,7 +149,9 @@ describe 'Pipelines', :feature, :js do create(:ci_pipeline, :invalid, project: project) end - before { visit_project_pipelines } + before do + visit_project_pipelines + end it 'contains badge that indicates errors' do expect(page).to have_content 'yaml invalid' @@ -171,7 +173,9 @@ describe 'Pipelines', :feature, :js do commands: 'test') end - before { visit_project_pipelines } + before do + visit_project_pipelines + end it 'has a dropdown with play button' do expect(page).to have_selector('.dropdown-toggle.btn.btn-default .icon-play') @@ -204,7 +208,9 @@ describe 'Pipelines', :feature, :js do stage: 'test') end - before { visit_project_pipelines } + before do + visit_project_pipelines + end it 'is cancelable' do expect(page).to have_selector('.js-pipelines-cancel-button') @@ -215,7 +221,9 @@ describe 'Pipelines', :feature, :js do end context 'when canceling' do - before { find('.js-pipelines-cancel-button').trigger('click') } + before do + find('.js-pipelines-cancel-button').trigger('click') + end it 'indicates that pipeline was canceled' do expect(page).not_to have_selector('.js-pipelines-cancel-button') @@ -255,7 +263,9 @@ describe 'Pipelines', :feature, :js do stage: 'test') end - before { visit_project_pipelines } + before do + visit_project_pipelines + end it 'has artifats' do expect(page).to have_selector('.build-artifacts') @@ -284,7 +294,9 @@ describe 'Pipelines', :feature, :js do stage: 'test') end - before { visit_project_pipelines } + before do + visit_project_pipelines + end it { expect(page).not_to have_selector('.build-artifacts') } end @@ -297,7 +309,9 @@ describe 'Pipelines', :feature, :js do stage: 'test') end - before { visit_project_pipelines } + before do + visit_project_pipelines + end it { expect(page).not_to have_selector('.build-artifacts') } end @@ -310,7 +324,9 @@ describe 'Pipelines', :feature, :js do name: 'build') end - before { visit_project_pipelines } + before do + visit_project_pipelines + end it 'should render a mini pipeline graph' do expect(page).to have_selector('.js-mini-pipeline-graph') @@ -437,7 +453,9 @@ describe 'Pipelines', :feature, :js do end context 'with gitlab-ci.yml' do - before { stub_ci_pipeline_to_return_yaml_file } + before do + stub_ci_pipeline_to_return_yaml_file + end it 'creates a new pipeline' do expect { click_on 'Create pipeline' } @@ -448,7 +466,9 @@ describe 'Pipelines', :feature, :js do end context 'without gitlab-ci.yml' do - before { click_on 'Create pipeline' } + before do + click_on 'Create pipeline' + end it { expect(page).to have_content('Missing .gitlab-ci.yml file') } end diff --git a/spec/features/projects/project_settings_spec.rb b/spec/features/projects/project_settings_spec.rb index 11dcab4d737..2a9b32ea07e 100644 --- a/spec/features/projects/project_settings_spec.rb +++ b/spec/features/projects/project_settings_spec.rb @@ -58,8 +58,13 @@ describe 'Edit Project Settings', feature: true do # Not using empty project because we need a repo to exist let(:project) { create(:project, namespace: user.namespace, name: 'gitlabhq') } - before(:context) { TestEnv.clean_test_path } - after(:example) { TestEnv.clean_test_path } + before(:context) do + TestEnv.clean_test_path + end + + after(:example) do + TestEnv.clean_test_path + end specify 'the project is accessible via the new path' do rename_project(project, path: 'bar') @@ -96,9 +101,17 @@ describe 'Edit Project Settings', feature: true do let!(:project) { create(:project, namespace: user.namespace, name: 'gitlabhq') } let!(:group) { create(:group) } - before(:context) { TestEnv.clean_test_path } - before(:example) { group.add_owner(user) } - after(:example) { TestEnv.clean_test_path } + before(:context) do + TestEnv.clean_test_path + end + + before(:example) do + group.add_owner(user) + end + + after(:example) do + TestEnv.clean_test_path + end specify 'the project is accessible via the new path' do transfer_project(project, group) diff --git a/spec/features/protected_branches_spec.rb b/spec/features/protected_branches_spec.rb index 667895bffa5..aa9164dd979 100644 --- a/spec/features/protected_branches_spec.rb +++ b/spec/features/protected_branches_spec.rb @@ -4,7 +4,9 @@ feature 'Protected Branches', feature: true, js: true do let(:user) { create(:user, :admin) } let(:project) { create(:project, :repository) } - before { login_as(user) } + before do + login_as(user) + end def set_protected_branch_name(branch_name) find(".js-protected-branch-select").trigger('click') diff --git a/spec/features/protected_tags_spec.rb b/spec/features/protected_tags_spec.rb index 66236dbc7fc..63a20585776 100644 --- a/spec/features/protected_tags_spec.rb +++ b/spec/features/protected_tags_spec.rb @@ -4,7 +4,9 @@ feature 'Projected Tags', feature: true, js: true do let(:user) { create(:user, :admin) } let(:project) { create(:project, :repository) } - before { login_as(user) } + before do + login_as(user) + end def set_protected_tag_name(tag_name) find(".js-protected-tag-select").click diff --git a/spec/features/runners_spec.rb b/spec/features/runners_spec.rb index 0e1cc9a0f73..e87d52f5c8f 100644 --- a/spec/features/runners_spec.rb +++ b/spec/features/runners_spec.rb @@ -4,7 +4,10 @@ describe "Runners" do include GitlabRoutingHelper let(:user) { create(:user) } - before { login_as(user) } + + before do + login_as(user) + end describe "specific runners" do before do @@ -127,7 +130,9 @@ describe "Runners" do end context 'when runner has tags' do - before { runner.update_attribute(:tag_list, ['tag']) } + before do + runner.update_attribute(:tag_list, ['tag']) + end scenario 'user wants to prevent runner from running untagged job' do visit runners_path(project) diff --git a/spec/features/search_spec.rb b/spec/features/search_spec.rb index 7834807b1f1..89d4f536b20 100644 --- a/spec/features/search_spec.rb +++ b/spec/features/search_spec.rb @@ -83,7 +83,9 @@ describe "Search", feature: true do let(:project) { create(:project, :repository) } let(:note) { create(:note_on_commit, author: user, project: project, commit_id: project.repository.commit.id, note: 'Bug here') } - before { note.update_attributes(commit_id: 12345678) } + before do + note.update_attributes(commit_id: 12345678) + end it 'finds comment' do visit namespace_project_path(project.namespace, project) diff --git a/spec/features/security/project/internal_access_spec.rb b/spec/features/security/project/internal_access_spec.rb index 2a2655bbdb5..f33406a40a7 100644 --- a/spec/features/security/project/internal_access_spec.rb +++ b/spec/features/security/project/internal_access_spec.rb @@ -337,7 +337,9 @@ describe "Internal Project Access", feature: true do subject { namespace_project_jobs_path(project.namespace, project) } context "when allowed for public and internal" do - before { project.update(public_builds: true) } + before do + project.update(public_builds: true) + end it { is_expected.to be_allowed_for(:admin) } it { is_expected.to be_allowed_for(:owner).of(project) } @@ -351,7 +353,9 @@ describe "Internal Project Access", feature: true do end context "when disallowed for public and internal" do - before { project.update(public_builds: false) } + before do + project.update(public_builds: false) + end it { is_expected.to be_allowed_for(:admin) } it { is_expected.to be_allowed_for(:owner).of(project) } @@ -371,7 +375,9 @@ describe "Internal Project Access", feature: true do subject { namespace_project_job_path(project.namespace, project, build.id) } context "when allowed for public and internal" do - before { project.update(public_builds: true) } + before do + project.update(public_builds: true) + end it { is_expected.to be_allowed_for(:admin) } it { is_expected.to be_allowed_for(:owner).of(project) } @@ -385,7 +391,9 @@ describe "Internal Project Access", feature: true do end context "when disallowed for public and internal" do - before { project.update(public_builds: false) } + before do + project.update(public_builds: false) + end it { is_expected.to be_allowed_for(:admin) } it { is_expected.to be_allowed_for(:owner).of(project) } diff --git a/spec/features/security/project/public_access_spec.rb b/spec/features/security/project/public_access_spec.rb index 35d5163941e..16a1331b2f3 100644 --- a/spec/features/security/project/public_access_spec.rb +++ b/spec/features/security/project/public_access_spec.rb @@ -157,7 +157,9 @@ describe "Public Project Access", feature: true do subject { namespace_project_jobs_path(project.namespace, project) } context "when allowed for public" do - before { project.update(public_builds: true) } + before do + project.update(public_builds: true) + end it { is_expected.to be_allowed_for(:admin) } it { is_expected.to be_allowed_for(:owner).of(project) } @@ -171,7 +173,9 @@ describe "Public Project Access", feature: true do end context "when disallowed for public" do - before { project.update(public_builds: false) } + before do + project.update(public_builds: false) + end it { is_expected.to be_allowed_for(:admin) } it { is_expected.to be_allowed_for(:owner).of(project) } @@ -191,7 +195,9 @@ describe "Public Project Access", feature: true do subject { namespace_project_job_path(project.namespace, project, build.id) } context "when allowed for public" do - before { project.update(public_builds: true) } + before do + project.update(public_builds: true) + end it { is_expected.to be_allowed_for(:admin) } it { is_expected.to be_allowed_for(:owner).of(project) } @@ -205,7 +211,9 @@ describe "Public Project Access", feature: true do end context "when disallowed for public" do - before { project.update(public_builds: false) } + before do + project.update(public_builds: false) + end it { is_expected.to be_allowed_for(:admin) } it { is_expected.to be_allowed_for(:owner).of(project) } diff --git a/spec/features/signup_spec.rb b/spec/features/signup_spec.rb index d7b6dda4946..5d6d1e79af2 100644 --- a/spec/features/signup_spec.rb +++ b/spec/features/signup_spec.rb @@ -3,7 +3,9 @@ require 'spec_helper' feature 'Signup', feature: true do describe 'signup with no errors' do context "when sending confirmation email" do - before { stub_application_setting(send_user_confirmation_email: true) } + before do + stub_application_setting(send_user_confirmation_email: true) + end it 'creates the user account and sends a confirmation email' do user = build(:user) @@ -23,7 +25,9 @@ feature 'Signup', feature: true do end context "when not sending confirmation email" do - before { stub_application_setting(send_user_confirmation_email: false) } + before do + stub_application_setting(send_user_confirmation_email: false) + end it 'creates the user account and goes to dashboard' do user = build(:user) diff --git a/spec/features/task_lists_spec.rb b/spec/features/task_lists_spec.rb index 563e65d3cc5..51b1b8e2328 100644 --- a/spec/features/task_lists_spec.rb +++ b/spec/features/task_lists_spec.rb @@ -144,7 +144,9 @@ feature 'Task Lists', feature: true do describe 'nested tasks', js: true do let(:issue) { create(:issue, description: nested_tasks_markdown, author: user, project: project) } - before { visit_issue(project, issue) } + before do + visit_issue(project, issue) + end it 'renders' do expect(page).to have_selector('ul.task-list', count: 2) diff --git a/spec/features/todos/todos_sorting_spec.rb b/spec/features/todos/todos_sorting_spec.rb index 4d5bd476301..f012d250887 100644 --- a/spec/features/todos/todos_sorting_spec.rb +++ b/spec/features/todos/todos_sorting_spec.rb @@ -8,7 +8,9 @@ describe "Dashboard > User sorts todos", feature: true do let(:label_2) { create(:label, title: 'label_2', project: project, priority: 2) } let(:label_3) { create(:label, title: 'label_3', project: project, priority: 3) } - before { project.team << [user, :developer] } + before do + project.team << [user, :developer] + end context 'sort options' do let(:issue_1) { create(:issue, title: 'issue_1', project: project) } diff --git a/spec/features/triggers_spec.rb b/spec/features/triggers_spec.rb index c1ae6db00c6..2ea9992173d 100644 --- a/spec/features/triggers_spec.rb +++ b/spec/features/triggers_spec.rb @@ -5,7 +5,10 @@ feature 'Triggers', feature: true, js: true do let(:user) { create(:user) } let(:user2) { create(:user) } let(:guest_user) { create(:user) } - before { login_as(user) } + + before do + login_as(user) + end before do @project = create(:empty_project) diff --git a/spec/features/u2f_spec.rb b/spec/features/u2f_spec.rb index 2fed8067042..dc21637967f 100644 --- a/spec/features/u2f_spec.rb +++ b/spec/features/u2f_spec.rb @@ -1,7 +1,9 @@ require 'spec_helper' feature 'Using U2F (Universal 2nd Factor) Devices for Authentication', :js do - before { allow_any_instance_of(U2fHelper).to receive(:inject_u2f_api?).and_return(true) } + before do + allow_any_instance_of(U2fHelper).to receive(:inject_u2f_api?).and_return(true) + end def manage_two_factor_authentication click_on 'Manage two-factor authentication' @@ -28,7 +30,9 @@ feature 'Using U2F (Universal 2nd Factor) Devices for Authentication', :js do end describe 'when 2FA via OTP is disabled' do - before { user.update_attribute(:otp_required_for_login, false) } + before do + user.update_attribute(:otp_required_for_login, false) + end it 'does not allow registering a new device' do visit profile_account_path diff --git a/spec/features/unsubscribe_links_spec.rb b/spec/features/unsubscribe_links_spec.rb index 8509551ce4a..0a8db15c75f 100644 --- a/spec/features/unsubscribe_links_spec.rb +++ b/spec/features/unsubscribe_links_spec.rb @@ -56,7 +56,9 @@ describe 'Unsubscribe links', feature: true do end context 'when logged in' do - before { login_as(recipient) } + before do + login_as(recipient) + end it 'unsubscribes from the issue when visiting the link from the email body' do visit body_link diff --git a/spec/features/users_spec.rb b/spec/features/users_spec.rb index fbe078bd136..c241dae12cf 100644 --- a/spec/features/users_spec.rb +++ b/spec/features/users_spec.rb @@ -45,7 +45,9 @@ feature 'Users', feature: true, js: true do end describe 'redirect alias routes' do - before { user } + before do + expect(user).to be_persisted + end scenario '/u/user1 redirects to user page' do visit '/u/user1' diff --git a/spec/finders/issues_finder_spec.rb b/spec/finders/issues_finder_spec.rb index 96151689359..8f2d60f2f1b 100644 --- a/spec/finders/issues_finder_spec.rb +++ b/spec/finders/issues_finder_spec.rb @@ -148,7 +148,9 @@ describe IssuesFinder do let(:params) { { label_name: [label.title, label2.title].join(',') } } let(:label2) { create(:label, project: project2) } - before { create(:label_link, label: label2, target: issue2) } + before do + create(:label_link, label: label2, target: issue2) + end it 'returns the unique issues with any of those labels' do expect(issues).to contain_exactly(issue2) diff --git a/spec/finders/personal_access_tokens_finder_spec.rb b/spec/finders/personal_access_tokens_finder_spec.rb index fd92664ca24..3f22b3a253d 100644 --- a/spec/finders/personal_access_tokens_finder_spec.rb +++ b/spec/finders/personal_access_tokens_finder_spec.rb @@ -25,49 +25,65 @@ describe PersonalAccessTokensFinder do end describe 'without impersonation' do - before { params[:impersonation] = false } + before do + params[:impersonation] = false + end it { is_expected.to contain_exactly(active_personal_access_token, revoked_personal_access_token, expired_personal_access_token) } describe 'with active state' do - before { params[:state] = 'active' } + before do + params[:state] = 'active' + end it { is_expected.to contain_exactly(active_personal_access_token) } end describe 'with inactive state' do - before { params[:state] = 'inactive' } + before do + params[:state] = 'inactive' + end it { is_expected.to contain_exactly(revoked_personal_access_token, expired_personal_access_token) } end end describe 'with impersonation' do - before { params[:impersonation] = true } + before do + params[:impersonation] = true + end it { is_expected.to contain_exactly(active_impersonation_token, revoked_impersonation_token, expired_impersonation_token) } describe 'with active state' do - before { params[:state] = 'active' } + before do + params[:state] = 'active' + end it { is_expected.to contain_exactly(active_impersonation_token) } end describe 'with inactive state' do - before { params[:state] = 'inactive' } + before do + params[:state] = 'inactive' + end it { is_expected.to contain_exactly(revoked_impersonation_token, expired_impersonation_token) } end end describe 'with active state' do - before { params[:state] = 'active' } + before do + params[:state] = 'active' + end it { is_expected.to contain_exactly(active_personal_access_token, active_impersonation_token) } end describe 'with inactive state' do - before { params[:state] = 'inactive' } + before do + params[:state] = 'inactive' + end it do is_expected.to contain_exactly(expired_personal_access_token, revoked_personal_access_token, @@ -81,7 +97,9 @@ describe PersonalAccessTokensFinder do it { is_expected.to eq(active_personal_access_token) } describe 'with impersonation' do - before { params[:impersonation] = true } + before do + params[:impersonation] = true + end it { is_expected.to be_nil } end @@ -93,7 +111,9 @@ describe PersonalAccessTokensFinder do it { is_expected.to eq(active_personal_access_token) } describe 'with impersonation' do - before { params[:impersonation] = true } + before do + params[:impersonation] = true + end it { is_expected.to be_nil } end @@ -109,7 +129,9 @@ describe PersonalAccessTokensFinder do let!(:other_user_expired_impersonation_token) { create(:personal_access_token, :expired, :impersonation, user: user2) } let!(:other_user_revoked_impersonation_token) { create(:personal_access_token, :revoked, :impersonation, user: user2) } - before { params[:user] = user } + before do + params[:user] = user + end it do is_expected.to contain_exactly(active_personal_access_token, active_impersonation_token, @@ -118,49 +140,65 @@ describe PersonalAccessTokensFinder do end describe 'without impersonation' do - before { params[:impersonation] = false } + before do + params[:impersonation] = false + end it { is_expected.to contain_exactly(active_personal_access_token, revoked_personal_access_token, expired_personal_access_token) } describe 'with active state' do - before { params[:state] = 'active' } + before do + params[:state] = 'active' + end it { is_expected.to contain_exactly(active_personal_access_token) } end describe 'with inactive state' do - before { params[:state] = 'inactive' } + before do + params[:state] = 'inactive' + end it { is_expected.to contain_exactly(revoked_personal_access_token, expired_personal_access_token) } end end describe 'with impersonation' do - before { params[:impersonation] = true } + before do + params[:impersonation] = true + end it { is_expected.to contain_exactly(active_impersonation_token, revoked_impersonation_token, expired_impersonation_token) } describe 'with active state' do - before { params[:state] = 'active' } + before do + params[:state] = 'active' + end it { is_expected.to contain_exactly(active_impersonation_token) } end describe 'with inactive state' do - before { params[:state] = 'inactive' } + before do + params[:state] = 'inactive' + end it { is_expected.to contain_exactly(revoked_impersonation_token, expired_impersonation_token) } end end describe 'with active state' do - before { params[:state] = 'active' } + before do + params[:state] = 'active' + end it { is_expected.to contain_exactly(active_personal_access_token, active_impersonation_token) } end describe 'with inactive state' do - before { params[:state] = 'inactive' } + before do + params[:state] = 'inactive' + end it do is_expected.to contain_exactly(expired_personal_access_token, revoked_personal_access_token, @@ -174,7 +212,9 @@ describe PersonalAccessTokensFinder do it { is_expected.to eq(active_personal_access_token) } describe 'with impersonation' do - before { params[:impersonation] = true } + before do + params[:impersonation] = true + end it { is_expected.to be_nil } end @@ -186,7 +226,9 @@ describe PersonalAccessTokensFinder do it { is_expected.to eq(active_personal_access_token) } describe 'with impersonation' do - before { params[:impersonation] = true } + before do + params[:impersonation] = true + end it { is_expected.to be_nil } end diff --git a/spec/finders/personal_projects_finder_spec.rb b/spec/finders/personal_projects_finder_spec.rb index e0e17af681a..304b0fb67fb 100644 --- a/spec/finders/personal_projects_finder_spec.rb +++ b/spec/finders/personal_projects_finder_spec.rb @@ -32,7 +32,9 @@ describe PersonalProjectsFinder do end context 'external' do - before { current_user.update_attributes(external: true) } + before do + current_user.update_attributes(external: true) + end it { is_expected.to eq([private_project, public_project]) } end diff --git a/spec/finders/todos_finder_spec.rb b/spec/finders/todos_finder_spec.rb index f7e7e733cf7..8be447418b0 100644 --- a/spec/finders/todos_finder_spec.rb +++ b/spec/finders/todos_finder_spec.rb @@ -6,7 +6,9 @@ describe TodosFinder do let(:project) { create(:empty_project) } let(:finder) { described_class } - before { project.team << [user, :developer] } + before do + project.team << [user, :developer] + end describe '#sort' do context 'by date' do diff --git a/spec/helpers/application_helper_spec.rb b/spec/helpers/application_helper_spec.rb index 49df91b236f..cc7f889b927 100644 --- a/spec/helpers/application_helper_spec.rb +++ b/spec/helpers/application_helper_spec.rb @@ -257,4 +257,24 @@ describe ApplicationHelper do it { expect(helper.active_when(true)).to eq('active') } it { expect(helper.active_when(false)).to eq(nil) } end + + describe '#support_url' do + context 'when alternate support url is specified' do + let(:alternate_url) { 'http://company.example.com/getting-help' } + + before do + allow(current_application_settings).to receive(:help_page_support_url) { alternate_url } + end + + it 'returns the alternate support url' do + expect(helper.support_url).to eq(alternate_url) + end + end + + context 'when alternate support url is not specified' do + it 'builds the support url from the promo_url' do + expect(helper.support_url).to eq(helper.promo_url + '/getting-help/') + end + end + end end diff --git a/spec/helpers/diff_helper_spec.rb b/spec/helpers/diff_helper_spec.rb index a74615e07f9..0ac030d3171 100644 --- a/spec/helpers/diff_helper_spec.rb +++ b/spec/helpers/diff_helper_spec.rb @@ -8,7 +8,7 @@ describe DiffHelper do let(:commit) { project.commit(sample_commit.id) } let(:diffs) { commit.raw_diffs } let(:diff) { diffs.first } - let(:diff_refs) { [commit.parent, commit] } + let(:diff_refs) { commit.diff_refs } let(:diff_file) { Gitlab::Diff::File.new(diff, diff_refs: diff_refs, repository: repository) } describe 'diff_view' do @@ -207,4 +207,41 @@ describe DiffHelper do expect(output).not_to have_css 'td:nth-child(3)' end end + + context 'viewer related' do + let(:viewer) { diff_file.simple_viewer } + + before do + assign(:project, project) + end + + describe '#diff_render_error_reason' do + context 'for error :too_large' do + before do + expect(viewer).to receive(:render_error).and_return(:too_large) + end + + it 'returns an error message' do + expect(helper.diff_render_error_reason(viewer)).to eq('it is too large') + end + end + + context 'for error :server_side_but_stored_externally' do + before do + expect(viewer).to receive(:render_error).and_return(:server_side_but_stored_externally) + expect(diff_file).to receive(:external_storage).and_return(:lfs) + end + + it 'returns an error message' do + expect(helper.diff_render_error_reason(viewer)).to eq('it is stored in LFS') + end + end + end + + describe '#diff_render_error_options' do + it 'includes a "view the blob" link' do + expect(helper.diff_render_error_options(viewer)).to include(/view the blob/) + end + end + end end diff --git a/spec/helpers/projects_helper_spec.rb b/spec/helpers/projects_helper_spec.rb index 3ed0b0a756b..9a4086725d2 100644 --- a/spec/helpers/projects_helper_spec.rb +++ b/spec/helpers/projects_helper_spec.rb @@ -250,7 +250,9 @@ describe ProjectsHelper do end context "when project is private" do - before { project.update_attributes(visibility_level: Gitlab::VisibilityLevel::PRIVATE) } + before do + project.update_attributes(visibility_level: Gitlab::VisibilityLevel::PRIVATE) + end it "shows only allowed options" do helper.instance_variable_set(:@project, project) diff --git a/spec/javascripts/notes_spec.js b/spec/javascripts/notes_spec.js index bfd8b8648a6..c6f218e4dac 100644 --- a/spec/javascripts/notes_spec.js +++ b/spec/javascripts/notes_spec.js @@ -126,6 +126,7 @@ import '~/notes'; const deferred = $.Deferred(); spyOn($, 'ajax').and.returnValue(deferred.promise()); spyOn(this.notes, 'revertNoteEditForm'); + spyOn(this.notes, 'setupNewNote'); $('.js-comment-button').click(); deferred.resolve(noteEntity); @@ -136,6 +137,46 @@ import '~/notes'; this.notes.updateNote(updatedNote, $targetNote); expect(this.notes.revertNoteEditForm).toHaveBeenCalledWith($targetNote); + expect(this.notes.setupNewNote).toHaveBeenCalled(); + }); + }); + + describe('updateNoteTargetSelector', () => { + const hash = 'note_foo'; + let $note; + + beforeEach(() => { + $note = $(`<div id="${hash}"></div>`); + spyOn($note, 'filter').and.callThrough(); + spyOn($note, 'toggleClass').and.callThrough(); + }); + + it('sets target when hash matches', () => { + spyOn(gl.utils, 'getLocationHash'); + gl.utils.getLocationHash.and.returnValue(hash); + + Notes.updateNoteTargetSelector($note); + + expect($note.filter).toHaveBeenCalledWith(`#${hash}`); + expect($note.toggleClass).toHaveBeenCalledWith('target', true); + }); + + it('unsets target when hash does not match', () => { + spyOn(gl.utils, 'getLocationHash'); + gl.utils.getLocationHash.and.returnValue('note_doesnotexist'); + + Notes.updateNoteTargetSelector($note); + + expect($note.toggleClass).toHaveBeenCalledWith('target', false); + }); + + it('unsets target when there is not a hash fragment anymore', () => { + spyOn(gl.utils, 'getLocationHash'); + gl.utils.getLocationHash.and.returnValue(null); + + Notes.updateNoteTargetSelector($note); + + expect($note.toggleClass).toHaveBeenCalledWith('target', null); }); }); @@ -189,9 +230,13 @@ import '~/notes'; Notes.isUpdatedNote.and.returnValue(true); const $note = $('<div>'); $notesList.find.and.returnValue($note); + const $newNote = $(note.html); + Notes.animateUpdateNote.and.returnValue($newNote); + Notes.prototype.renderNote.call(notes, note, null, $notesList); expect(Notes.animateUpdateNote).toHaveBeenCalledWith(note.html, $note); + expect(notes.setupNewNote).toHaveBeenCalledWith($newNote); }); describe('while editing', () => { @@ -378,6 +423,23 @@ import '~/notes'; }); }); + describe('putEditFormInPlace', () => { + it('should call gl.GLForm with GFM parameter passed through', () => { + spyOn(gl, 'GLForm'); + + const $el = jasmine.createSpyObj('$form', ['find', 'closest']); + $el.find.and.returnValue($('<div>')); + $el.closest.and.returnValue($('<div>')); + + Notes.prototype.putEditFormInPlace.call({ + getEditFormSelector: () => '', + enableGFM: true + }, $el); + + expect(gl.GLForm).toHaveBeenCalledWith(jasmine.any(Object), true); + }); + }); + describe('postComment & updateComment', () => { const sampleComment = 'foo'; const updatedComment = 'bar'; diff --git a/spec/javascripts/pipelines/pipelines_actions_spec.js b/spec/javascripts/pipelines/pipelines_actions_spec.js index c89dacbcd93..8a58b77f1e3 100644 --- a/spec/javascripts/pipelines/pipelines_actions_spec.js +++ b/spec/javascripts/pipelines/pipelines_actions_spec.js @@ -1,5 +1,5 @@ import Vue from 'vue'; -import pipelinesActionsComp from '~/pipelines/components/pipelines_actions'; +import pipelinesActionsComp from '~/pipelines/components/pipelines_actions.vue'; describe('Pipelines Actions dropdown', () => { let component; diff --git a/spec/javascripts/pipelines/pipelines_artifacts_spec.js b/spec/javascripts/pipelines/pipelines_artifacts_spec.js index 9724b63d957..acb67d0ec21 100644 --- a/spec/javascripts/pipelines/pipelines_artifacts_spec.js +++ b/spec/javascripts/pipelines/pipelines_artifacts_spec.js @@ -1,5 +1,5 @@ import Vue from 'vue'; -import artifactsComp from '~/pipelines/components/pipelines_artifacts'; +import artifactsComp from '~/pipelines/components/pipelines_artifacts.vue'; describe('Pipelines Artifacts dropdown', () => { let component; diff --git a/spec/javascripts/pipelines/pipelines_spec.js b/spec/javascripts/pipelines/pipelines_spec.js index 3a56156358b..c30abb2edb0 100644 --- a/spec/javascripts/pipelines/pipelines_spec.js +++ b/spec/javascripts/pipelines/pipelines_spec.js @@ -1,5 +1,5 @@ import Vue from 'vue'; -import pipelinesComp from '~/pipelines/pipelines'; +import pipelinesComp from '~/pipelines/components/pipelines.vue'; import Store from '~/pipelines/stores/pipelines_store'; describe('Pipelines', () => { diff --git a/spec/javascripts/pipelines/time_ago_spec.js b/spec/javascripts/pipelines/time_ago_spec.js index 24581e8c672..42b34c82f89 100644 --- a/spec/javascripts/pipelines/time_ago_spec.js +++ b/spec/javascripts/pipelines/time_ago_spec.js @@ -1,5 +1,5 @@ import Vue from 'vue'; -import timeAgo from '~/pipelines/components/time_ago'; +import timeAgo from '~/pipelines/components/time_ago.vue'; describe('Timeago component', () => { let TimeAgo; diff --git a/spec/javascripts/vue_shared/components/commit_spec.js b/spec/javascripts/vue_shared/components/commit_spec.js index 540245fe71e..1c3188cdda2 100644 --- a/spec/javascripts/vue_shared/components/commit_spec.js +++ b/spec/javascripts/vue_shared/components/commit_spec.js @@ -1,5 +1,5 @@ import Vue from 'vue'; -import commitComp from '~/vue_shared/components/commit'; +import commitComp from '~/vue_shared/components/commit.vue'; describe('Commit component', () => { let props; diff --git a/spec/javascripts/vue_shared/components/pipelines_table_row_spec.js b/spec/javascripts/vue_shared/components/pipelines_table_row_spec.js index 67419cfcbea..346fd0ae010 100644 --- a/spec/javascripts/vue_shared/components/pipelines_table_row_spec.js +++ b/spec/javascripts/vue_shared/components/pipelines_table_row_spec.js @@ -1,5 +1,5 @@ import Vue from 'vue'; -import tableRowComp from '~/vue_shared/components/pipelines_table_row'; +import tableRowComp from '~/vue_shared/components/pipelines_table_row.vue'; describe('Pipelines Table Row', () => { const jsonFixtureName = 'pipelines/pipelines.json'; diff --git a/spec/javascripts/vue_shared/components/pipelines_table_spec.js b/spec/javascripts/vue_shared/components/pipelines_table_spec.js index 6cc178b8f1d..c362cfb7a96 100644 --- a/spec/javascripts/vue_shared/components/pipelines_table_spec.js +++ b/spec/javascripts/vue_shared/components/pipelines_table_spec.js @@ -1,5 +1,5 @@ import Vue from 'vue'; -import pipelinesTableComp from '~/vue_shared/components/pipelines_table'; +import pipelinesTableComp from '~/vue_shared/components/pipelines_table.vue'; import '~/lib/utils/datetime_utility'; describe('Pipelines Table', () => { diff --git a/spec/lib/banzai/filter/external_issue_reference_filter_spec.rb b/spec/lib/banzai/filter/external_issue_reference_filter_spec.rb index fbf7a461fa5..76cefe112fb 100644 --- a/spec/lib/banzai/filter/external_issue_reference_filter_spec.rb +++ b/spec/lib/banzai/filter/external_issue_reference_filter_spec.rb @@ -82,7 +82,9 @@ describe Banzai::Filter::ExternalIssueReferenceFilter, lib: true do context 'with RequestStore enabled' do let(:reference_filter) { HTML::Pipeline.new([described_class]) } - before { allow(RequestStore).to receive(:active?).and_return(true) } + before do + allow(RequestStore).to receive(:active?).and_return(true) + end it 'queries the collection on the first call' do expect_any_instance_of(Project).to receive(:default_issues_tracker?).once.and_call_original diff --git a/spec/lib/banzai/filter/redactor_filter_spec.rb b/spec/lib/banzai/filter/redactor_filter_spec.rb index 7c4a0f32c7b..97504aebed5 100644 --- a/spec/lib/banzai/filter/redactor_filter_spec.rb +++ b/spec/lib/banzai/filter/redactor_filter_spec.rb @@ -39,7 +39,9 @@ describe Banzai::Filter::RedactorFilter, lib: true do end context 'valid projects' do - before { allow_any_instance_of(Banzai::ReferenceParser::BaseParser).to receive(:can_read_reference?).and_return(true) } + before do + allow_any_instance_of(Banzai::ReferenceParser::BaseParser).to receive(:can_read_reference?).and_return(true) + end it 'allows permitted Project references' do user = create(:user) @@ -54,7 +56,9 @@ describe Banzai::Filter::RedactorFilter, lib: true do end context 'invalid projects' do - before { allow_any_instance_of(Banzai::ReferenceParser::BaseParser).to receive(:can_read_reference?).and_return(false) } + before do + allow_any_instance_of(Banzai::ReferenceParser::BaseParser).to receive(:can_read_reference?).and_return(false) + end it 'removes unpermitted references' do user = create(:user) diff --git a/spec/lib/banzai/reference_parser/base_parser_spec.rb b/spec/lib/banzai/reference_parser/base_parser_spec.rb index f4f42bfc3ed..76fab93821a 100644 --- a/spec/lib/banzai/reference_parser/base_parser_spec.rb +++ b/spec/lib/banzai/reference_parser/base_parser_spec.rb @@ -114,7 +114,7 @@ describe Banzai::ReferenceParser::BaseParser, lib: true do expect(hash).to eq({ link => user }) end - it 'returns an empty Hash when entry does not exist in the database' do + it 'returns an empty Hash when entry does not exist in the database', :request_store do link = double(:link) expect(link).to receive(:has_attribute?). diff --git a/spec/lib/banzai/reference_parser/commit_parser_spec.rb b/spec/lib/banzai/reference_parser/commit_parser_spec.rb index 412ffa77c36..583ce63a8ab 100644 --- a/spec/lib/banzai/reference_parser/commit_parser_spec.rb +++ b/spec/lib/banzai/reference_parser/commit_parser_spec.rb @@ -10,7 +10,9 @@ describe Banzai::ReferenceParser::CommitParser, lib: true do describe '#nodes_visible_to_user' do context 'when the link has a data-issue attribute' do - before { link['data-commit'] = 123 } + before do + link['data-commit'] = 123 + end it_behaves_like "referenced feature visibility", "repository" end diff --git a/spec/lib/banzai/reference_parser/commit_range_parser_spec.rb b/spec/lib/banzai/reference_parser/commit_range_parser_spec.rb index 96e55b0997a..8c0f5d7df97 100644 --- a/spec/lib/banzai/reference_parser/commit_range_parser_spec.rb +++ b/spec/lib/banzai/reference_parser/commit_range_parser_spec.rb @@ -10,7 +10,9 @@ describe Banzai::ReferenceParser::CommitRangeParser, lib: true do describe '#nodes_visible_to_user' do context 'when the link has a data-issue attribute' do - before { link['data-commit-range'] = '123..456' } + before do + link['data-commit-range'] = '123..456' + end it_behaves_like "referenced feature visibility", "repository" end diff --git a/spec/lib/banzai/reference_parser/external_issue_parser_spec.rb b/spec/lib/banzai/reference_parser/external_issue_parser_spec.rb index 0af36776a54..d212bbac619 100644 --- a/spec/lib/banzai/reference_parser/external_issue_parser_spec.rb +++ b/spec/lib/banzai/reference_parser/external_issue_parser_spec.rb @@ -10,7 +10,9 @@ describe Banzai::ReferenceParser::ExternalIssueParser, lib: true do describe '#nodes_visible_to_user' do context 'when the link has a data-issue attribute' do - before { link['data-external-issue'] = 123 } + before do + link['data-external-issue'] = 123 + end levels = [ProjectFeature::DISABLED, ProjectFeature::PRIVATE, ProjectFeature::ENABLED] diff --git a/spec/lib/banzai/reference_parser/label_parser_spec.rb b/spec/lib/banzai/reference_parser/label_parser_spec.rb index 8c540d35ddd..ddd699f3c25 100644 --- a/spec/lib/banzai/reference_parser/label_parser_spec.rb +++ b/spec/lib/banzai/reference_parser/label_parser_spec.rb @@ -11,7 +11,9 @@ describe Banzai::ReferenceParser::LabelParser, lib: true do describe '#nodes_visible_to_user' do context 'when the link has a data-issue attribute' do - before { link['data-label'] = label.id.to_s } + before do + link['data-label'] = label.id.to_s + end it_behaves_like "referenced feature visibility", "issues", "merge_requests" end diff --git a/spec/lib/banzai/reference_parser/milestone_parser_spec.rb b/spec/lib/banzai/reference_parser/milestone_parser_spec.rb index 2d4d589ae34..72d4f3bc18e 100644 --- a/spec/lib/banzai/reference_parser/milestone_parser_spec.rb +++ b/spec/lib/banzai/reference_parser/milestone_parser_spec.rb @@ -11,7 +11,9 @@ describe Banzai::ReferenceParser::MilestoneParser, lib: true do describe '#nodes_visible_to_user' do context 'when the link has a data-issue attribute' do - before { link['data-milestone'] = milestone.id.to_s } + before do + link['data-milestone'] = milestone.id.to_s + end it_behaves_like "referenced feature visibility", "issues", "merge_requests" end diff --git a/spec/lib/extracts_path_spec.rb b/spec/lib/extracts_path_spec.rb index 33ab005667a..2b26a318583 100644 --- a/spec/lib/extracts_path_spec.rb +++ b/spec/lib/extracts_path_spec.rb @@ -77,7 +77,10 @@ describe ExtractsPath, lib: true do context 'without a path' do let(:params) { { ref: 'v1.0.0.atom' } } - before { assign_ref_vars } + + before do + assign_ref_vars + end it 'sets the un-suffixed version as @ref' do expect(@ref).to eq('v1.0.0') diff --git a/spec/lib/gitlab/auth/unique_ips_limiter_spec.rb b/spec/lib/gitlab/auth/unique_ips_limiter_spec.rb index 94dcddcc30c..fc72df575be 100644 --- a/spec/lib/gitlab/auth/unique_ips_limiter_spec.rb +++ b/spec/lib/gitlab/auth/unique_ips_limiter_spec.rb @@ -40,7 +40,9 @@ describe Gitlab::Auth::UniqueIpsLimiter, :redis, lib: true do end context 'allow 2 unique ips' do - before { current_application_settings.update!(unique_ips_limit_per_user: 2) } + before do + current_application_settings.update!(unique_ips_limit_per_user: 2) + end it 'blocks user trying to login from third ip' do change_ip('ip1') diff --git a/spec/lib/gitlab/badge/build/status_spec.rb b/spec/lib/gitlab/badge/build/status_spec.rb index 3c5414701a7..6abf4ca46a9 100644 --- a/spec/lib/gitlab/badge/build/status_spec.rb +++ b/spec/lib/gitlab/badge/build/status_spec.rb @@ -29,7 +29,9 @@ describe Gitlab::Badge::Build::Status do let!(:build) { create_build(project, sha, branch) } context 'build success' do - before { build.success! } + before do + build.success! + end describe '#status' do it 'is successful' do @@ -39,7 +41,9 @@ describe Gitlab::Badge::Build::Status do end context 'build failed' do - before { build.drop! } + before do + build.drop! + end describe '#status' do it 'failed' do diff --git a/spec/lib/gitlab/chat_commands/presenters/issue_search_spec.rb b/spec/lib/gitlab/chat_commands/presenters/issue_search_spec.rb index ec6d3e34a96..3799a324db4 100644 --- a/spec/lib/gitlab/chat_commands/presenters/issue_search_spec.rb +++ b/spec/lib/gitlab/chat_commands/presenters/issue_search_spec.rb @@ -4,7 +4,9 @@ describe Gitlab::ChatCommands::Presenters::IssueSearch do let(:project) { create(:empty_project) } let(:message) { subject[:text] } - before { create_list(:issue, 2, project: project) } + before do + create_list(:issue, 2, project: project) + end subject { described_class.new(project.issues).present } diff --git a/spec/lib/gitlab/checks/change_access_spec.rb b/spec/lib/gitlab/checks/change_access_spec.rb index c0c309d8179..643e590438a 100644 --- a/spec/lib/gitlab/checks/change_access_spec.rb +++ b/spec/lib/gitlab/checks/change_access_spec.rb @@ -20,7 +20,9 @@ describe Gitlab::Checks::ChangeAccess, lib: true do ).exec end - before { project.add_developer(user) } + before do + project.add_developer(user) + end context 'without failed checks' do it "doesn't raise an error" do @@ -50,7 +52,9 @@ describe Gitlab::Checks::ChangeAccess, lib: true do let!(:protected_tag) { create(:protected_tag, project: project, name: 'v*') } context 'as master' do - before { project.add_master(user) } + before do + project.add_master(user) + end context 'deletion' do let(:oldrev) { 'be93687618e4b132087f430a4d8fc3a609c9b77c' } diff --git a/spec/lib/gitlab/ci/config/entry/cache_spec.rb b/spec/lib/gitlab/ci/config/entry/cache_spec.rb index 2ed120f356a..878b1d6b862 100644 --- a/spec/lib/gitlab/ci/config/entry/cache_spec.rb +++ b/spec/lib/gitlab/ci/config/entry/cache_spec.rb @@ -4,7 +4,9 @@ describe Gitlab::Ci::Config::Entry::Cache do let(:entry) { described_class.new(config) } describe 'validations' do - before { entry.compose! } + before do + entry.compose! + end context 'when entry config value is correct' do let(:config) do diff --git a/spec/lib/gitlab/ci/config/entry/environment_spec.rb b/spec/lib/gitlab/ci/config/entry/environment_spec.rb index c330e609337..3c0007f4d57 100644 --- a/spec/lib/gitlab/ci/config/entry/environment_spec.rb +++ b/spec/lib/gitlab/ci/config/entry/environment_spec.rb @@ -3,7 +3,9 @@ require 'spec_helper' describe Gitlab::Ci::Config::Entry::Environment do let(:entry) { described_class.new(config) } - before { entry.compose! } + before do + entry.compose! + end context 'when configuration is a string' do let(:config) { 'production' } diff --git a/spec/lib/gitlab/ci/config/entry/global_spec.rb b/spec/lib/gitlab/ci/config/entry/global_spec.rb index e5f85c712ca..293f112b2b0 100644 --- a/spec/lib/gitlab/ci/config/entry/global_spec.rb +++ b/spec/lib/gitlab/ci/config/entry/global_spec.rb @@ -33,7 +33,9 @@ describe Gitlab::Ci::Config::Entry::Global do end describe '#compose!' do - before { global.compose! } + before do + global.compose! + end it 'creates nodes hash' do expect(global.descendants).to be_an Array @@ -79,7 +81,9 @@ describe Gitlab::Ci::Config::Entry::Global do end context 'when composed' do - before { global.compose! } + before do + global.compose! + end describe '#errors' do it 'has no errors' do @@ -175,7 +179,9 @@ describe Gitlab::Ci::Config::Entry::Global do end context 'when most of entires not defined' do - before { global.compose! } + before do + global.compose! + end let(:hash) do { cache: { key: 'a' }, rspec: { script: %w[ls] } } @@ -218,7 +224,9 @@ describe Gitlab::Ci::Config::Entry::Global do # details. # context 'when entires specified but not defined' do - before { global.compose! } + before do + global.compose! + end let(:hash) do { variables: nil, rspec: { script: 'rspec' } } @@ -233,7 +241,9 @@ describe Gitlab::Ci::Config::Entry::Global do end context 'when configuration is not valid' do - before { global.compose! } + before do + global.compose! + end context 'when before script is not an array' do let(:hash) do @@ -297,7 +307,9 @@ describe Gitlab::Ci::Config::Entry::Global do end describe '#[]' do - before { global.compose! } + before do + global.compose! + end let(:hash) do { cache: { key: 'a' }, rspec: { script: 'ls' } } diff --git a/spec/lib/gitlab/ci/config/entry/job_spec.rb b/spec/lib/gitlab/ci/config/entry/job_spec.rb index 8dc94a4eb33..92cba689f47 100644 --- a/spec/lib/gitlab/ci/config/entry/job_spec.rb +++ b/spec/lib/gitlab/ci/config/entry/job_spec.rb @@ -18,7 +18,9 @@ describe Gitlab::Ci::Config::Entry::Job do end describe 'validations' do - before { entry.compose! } + before do + entry.compose! + end context 'when entry config value is correct' do let(:config) { { script: 'rspec' } } @@ -97,7 +99,9 @@ describe Gitlab::Ci::Config::Entry::Job do let(:deps) { double('deps', '[]' => unspecified) } context 'when job config overrides global config' do - before { entry.compose!(deps) } + before do + entry.compose!(deps) + end let(:config) do { script: 'rspec', image: 'some_image', cache: { key: 'test' } } @@ -125,10 +129,14 @@ describe Gitlab::Ci::Config::Entry::Job do end context 'when composed' do - before { entry.compose! } + before do + entry.compose! + end describe '#value' do - before { entry.compose! } + before do + entry.compose! + end context 'when entry is correct' do let(:config) do diff --git a/spec/lib/gitlab/ci/config/entry/jobs_spec.rb b/spec/lib/gitlab/ci/config/entry/jobs_spec.rb index 7d104372ac6..c0a2b6517e3 100644 --- a/spec/lib/gitlab/ci/config/entry/jobs_spec.rb +++ b/spec/lib/gitlab/ci/config/entry/jobs_spec.rb @@ -4,7 +4,9 @@ describe Gitlab::Ci::Config::Entry::Jobs do let(:entry) { described_class.new(config) } describe 'validations' do - before { entry.compose! } + before do + entry.compose! + end context 'when entry config value is correct' do let(:config) { { rspec: { script: 'rspec' } } } @@ -48,7 +50,9 @@ describe Gitlab::Ci::Config::Entry::Jobs do end context 'when valid job entries composed' do - before { entry.compose! } + before do + entry.compose! + end let(:config) do { rspec: { script: 'rspec' }, diff --git a/spec/lib/gitlab/ci/config/entry/service_spec.rb b/spec/lib/gitlab/ci/config/entry/service_spec.rb index 2376de74554..7202fe525e4 100644 --- a/spec/lib/gitlab/ci/config/entry/service_spec.rb +++ b/spec/lib/gitlab/ci/config/entry/service_spec.rb @@ -3,7 +3,9 @@ require 'spec_helper' describe Gitlab::Ci::Config::Entry::Service do let(:entry) { described_class.new(config) } - before { entry.compose! } + before do + entry.compose! + end context 'when configuration is a string' do let(:config) { 'postgresql:9.5' } diff --git a/spec/lib/gitlab/ci/config/entry/services_spec.rb b/spec/lib/gitlab/ci/config/entry/services_spec.rb index b32e52f8f26..7c4319aee63 100644 --- a/spec/lib/gitlab/ci/config/entry/services_spec.rb +++ b/spec/lib/gitlab/ci/config/entry/services_spec.rb @@ -3,7 +3,9 @@ require 'spec_helper' describe Gitlab::Ci::Config::Entry::Services do let(:entry) { described_class.new(config) } - before { entry.compose! } + before do + entry.compose! + end context 'when configuration is valid' do let(:config) { ['postgresql:9.5', { name: 'postgresql:9.1', alias: 'postgres_old' }] } diff --git a/spec/lib/gitlab/ci/status/build/cancelable_spec.rb b/spec/lib/gitlab/ci/status/build/cancelable_spec.rb index 8ad9b7cdf07..114d2490490 100644 --- a/spec/lib/gitlab/ci/status/build/cancelable_spec.rb +++ b/spec/lib/gitlab/ci/status/build/cancelable_spec.rb @@ -47,7 +47,9 @@ describe Gitlab::Ci::Status::Build::Cancelable do describe '#has_action?' do context 'when user is allowed to update build' do - before { build.project.team << [user, :developer] } + before do + build.project.team << [user, :developer] + end it { is_expected.to have_action } end diff --git a/spec/lib/gitlab/ci/status/build/common_spec.rb b/spec/lib/gitlab/ci/status/build/common_spec.rb index 72bd7c4eb93..03d1f46b517 100644 --- a/spec/lib/gitlab/ci/status/build/common_spec.rb +++ b/spec/lib/gitlab/ci/status/build/common_spec.rb @@ -17,13 +17,17 @@ describe Gitlab::Ci::Status::Build::Common do describe '#has_details?' do context 'when user has access to read build' do - before { project.team << [user, :developer] } + before do + project.team << [user, :developer] + end it { is_expected.to have_details } end context 'when user does not have access to read build' do - before { project.update(public_builds: false) } + before do + project.update(public_builds: false) + end it { is_expected.not_to have_details } end diff --git a/spec/lib/gitlab/ci/status/build/factory_spec.rb b/spec/lib/gitlab/ci/status/build/factory_spec.rb index 3f30b2c38f2..c8a97016f20 100644 --- a/spec/lib/gitlab/ci/status/build/factory_spec.rb +++ b/spec/lib/gitlab/ci/status/build/factory_spec.rb @@ -6,7 +6,9 @@ describe Gitlab::Ci::Status::Build::Factory do let(:status) { factory.fabricate! } let(:factory) { described_class.new(build, user) } - before { project.team << [user, :developer] } + before do + project.team << [user, :developer] + end context 'when build is successful' do let(:build) { create(:ci_build, :success) } diff --git a/spec/lib/gitlab/ci/status/build/play_spec.rb b/spec/lib/gitlab/ci/status/build/play_spec.rb index 0e15a5f3c6b..32b2e62e4e0 100644 --- a/spec/lib/gitlab/ci/status/build/play_spec.rb +++ b/spec/lib/gitlab/ci/status/build/play_spec.rb @@ -28,7 +28,9 @@ describe Gitlab::Ci::Status::Build::Play do end context 'when user can not push to the branch' do - before { build.project.add_developer(user) } + before do + build.project.add_developer(user) + end it { is_expected.not_to have_action } end diff --git a/spec/lib/gitlab/ci/status/build/retryable_spec.rb b/spec/lib/gitlab/ci/status/build/retryable_spec.rb index 2db0f8d29bd..099d873fc01 100644 --- a/spec/lib/gitlab/ci/status/build/retryable_spec.rb +++ b/spec/lib/gitlab/ci/status/build/retryable_spec.rb @@ -47,7 +47,9 @@ describe Gitlab::Ci::Status::Build::Retryable do describe '#has_action?' do context 'when user is allowed to update build' do - before { build.project.team << [user, :developer] } + before do + build.project.team << [user, :developer] + end it { is_expected.to have_action } end diff --git a/spec/lib/gitlab/ci/status/build/stop_spec.rb b/spec/lib/gitlab/ci/status/build/stop_spec.rb index 8d021c35a69..23902f26b1a 100644 --- a/spec/lib/gitlab/ci/status/build/stop_spec.rb +++ b/spec/lib/gitlab/ci/status/build/stop_spec.rb @@ -19,7 +19,9 @@ describe Gitlab::Ci::Status::Build::Stop do describe '#has_action?' do context 'when user is allowed to update build' do - before { build.project.team << [user, :developer] } + before do + build.project.team << [user, :developer] + end it { is_expected.to have_action } end diff --git a/spec/lib/gitlab/ci/status/external/common_spec.rb b/spec/lib/gitlab/ci/status/external/common_spec.rb index e58f5d8d4df..b38fbee2486 100644 --- a/spec/lib/gitlab/ci/status/external/common_spec.rb +++ b/spec/lib/gitlab/ci/status/external/common_spec.rb @@ -28,7 +28,9 @@ describe Gitlab::Ci::Status::External::Common do describe '#has_details?' do context 'when user has access to read commit status' do - before { project.team << [user, :developer] } + before do + project.team << [user, :developer] + end it { is_expected.to have_details } end diff --git a/spec/lib/gitlab/ci/status/pipeline/common_spec.rb b/spec/lib/gitlab/ci/status/pipeline/common_spec.rb index d665674bf70..f5fd31e8d03 100644 --- a/spec/lib/gitlab/ci/status/pipeline/common_spec.rb +++ b/spec/lib/gitlab/ci/status/pipeline/common_spec.rb @@ -17,7 +17,9 @@ describe Gitlab::Ci::Status::Pipeline::Common do describe '#has_details?' do context 'when user has access to read pipeline' do - before { project.team << [user, :developer] } + before do + project.team << [user, :developer] + end it { is_expected.to have_details } end diff --git a/spec/lib/gitlab/database_spec.rb b/spec/lib/gitlab/database_spec.rb index 9b1d66a1b1c..26e5d73d333 100644 --- a/spec/lib/gitlab/database_spec.rb +++ b/spec/lib/gitlab/database_spec.rb @@ -53,14 +53,18 @@ describe Gitlab::Database, lib: true do describe '.nulls_last_order' do context 'when using PostgreSQL' do - before { expect(described_class).to receive(:postgresql?).and_return(true) } + before do + expect(described_class).to receive(:postgresql?).and_return(true) + end it { expect(described_class.nulls_last_order('column', 'ASC')).to eq 'column ASC NULLS LAST'} it { expect(described_class.nulls_last_order('column', 'DESC')).to eq 'column DESC NULLS LAST'} end context 'when using MySQL' do - before { expect(described_class).to receive(:postgresql?).and_return(false) } + before do + expect(described_class).to receive(:postgresql?).and_return(false) + end it { expect(described_class.nulls_last_order('column', 'ASC')).to eq 'column IS NULL, column ASC'} it { expect(described_class.nulls_last_order('column', 'DESC')).to eq 'column DESC'} @@ -69,14 +73,18 @@ describe Gitlab::Database, lib: true do describe '.nulls_first_order' do context 'when using PostgreSQL' do - before { expect(described_class).to receive(:postgresql?).and_return(true) } + before do + expect(described_class).to receive(:postgresql?).and_return(true) + end it { expect(described_class.nulls_first_order('column', 'ASC')).to eq 'column ASC NULLS FIRST'} it { expect(described_class.nulls_first_order('column', 'DESC')).to eq 'column DESC NULLS FIRST'} end context 'when using MySQL' do - before { expect(described_class).to receive(:postgresql?).and_return(false) } + before do + expect(described_class).to receive(:postgresql?).and_return(false) + end it { expect(described_class.nulls_first_order('column', 'ASC')).to eq 'column ASC'} it { expect(described_class.nulls_first_order('column', 'DESC')).to eq 'column IS NULL, column DESC'} diff --git a/spec/lib/gitlab/diff/file_spec.rb b/spec/lib/gitlab/diff/file_spec.rb index a9953bb0d01..f289131cc3a 100644 --- a/spec/lib/gitlab/diff/file_spec.rb +++ b/spec/lib/gitlab/diff/file_spec.rb @@ -92,4 +92,305 @@ describe Gitlab::Diff::File, lib: true do expect(diff_file.diffable?).to be_falsey end end + + describe '#content_changed?' do + context 'when created' do + let(:commit) { project.commit('33f3729a45c02fc67d00adb1b8bca394b0e761d9') } + let(:diff_file) { commit.diffs.diff_file_with_new_path('files/images/6049019_460s.jpg') } + + it 'returns false' do + expect(diff_file.content_changed?).to be_falsey + end + end + + context 'when deleted' do + let(:commit) { project.commit('d59c60028b053793cecfb4022de34602e1a9218e') } + let(:diff_file) { commit.diffs.diff_file_with_old_path('files/js/commit.js.coffee') } + + it 'returns false' do + expect(diff_file.content_changed?).to be_falsey + end + end + + context 'when renamed' do + let(:commit) { project.commit('6907208d755b60ebeacb2e9dfea74c92c3449a1f') } + let(:diff_file) { commit.diffs.diff_file_with_new_path('files/js/commit.coffee') } + + before do + allow(diff_file.new_blob).to receive(:id).and_return(diff_file.old_blob.id) + end + + it 'returns false' do + expect(diff_file.content_changed?).to be_falsey + end + end + + context 'when content changed' do + context 'when binary' do + let(:commit) { project.commit('2f63565e7aac07bcdadb654e253078b727143ec4') } + let(:diff_file) { commit.diffs.diff_file_with_new_path('files/images/6049019_460s.jpg') } + + it 'returns true' do + expect(diff_file.content_changed?).to be_truthy + end + end + + context 'when not binary' do + let(:commit) { project.commit('570e7b2abdd848b95f2f578043fc23bd6f6fd24d') } + let(:diff_file) { commit.diffs.diff_file_with_new_path('files/ruby/popen.rb') } + + it 'returns true' do + expect(diff_file.content_changed?).to be_truthy + end + end + end + end + + describe '#simple_viewer' do + context 'when the file is not diffable' do + before do + allow(diff_file).to receive(:diffable?).and_return(false) + end + + it 'returns a Not Diffable viewer' do + expect(diff_file.simple_viewer).to be_a(DiffViewer::NotDiffable) + end + end + + context 'when the content changed' do + context 'when the file represented by the diff file is binary' do + before do + allow(diff_file).to receive(:raw_binary?).and_return(true) + end + + it 'returns a No Preview viewer' do + expect(diff_file.simple_viewer).to be_a(DiffViewer::NoPreview) + end + end + + context 'when the diff file old and new blob types are different' do + before do + allow(diff_file).to receive(:different_type?).and_return(true) + end + + it 'returns a No Preview viewer' do + expect(diff_file.simple_viewer).to be_a(DiffViewer::NoPreview) + end + end + + context 'when the file represented by the diff file is text-based' do + it 'returns a text viewer' do + expect(diff_file.simple_viewer).to be_a(DiffViewer::Text) + end + end + end + + context 'when created' do + let(:commit) { project.commit('913c66a37b4a45b9769037c55c2d238bd0942d2e') } + let(:diff_file) { commit.diffs.diff_file_with_new_path('files/ruby/popen.rb') } + + before do + allow(diff_file).to receive(:content_changed?).and_return(nil) + end + + context 'when the file represented by the diff file is binary' do + before do + allow(diff_file).to receive(:raw_binary?).and_return(true) + end + + it 'returns an Added viewer' do + expect(diff_file.simple_viewer).to be_a(DiffViewer::Added) + end + end + + context 'when the diff file old and new blob types are different' do + before do + allow(diff_file).to receive(:different_type?).and_return(true) + end + + it 'returns an Added viewer' do + expect(diff_file.simple_viewer).to be_a(DiffViewer::Added) + end + end + + context 'when the file represented by the diff file is text-based' do + it 'returns a text viewer' do + expect(diff_file.simple_viewer).to be_a(DiffViewer::Text) + end + end + end + + context 'when deleted' do + let(:commit) { project.commit('d59c60028b053793cecfb4022de34602e1a9218e') } + let(:diff_file) { commit.diffs.diff_file_with_old_path('files/js/commit.js.coffee') } + + before do + allow(diff_file).to receive(:content_changed?).and_return(nil) + end + + context 'when the file represented by the diff file is binary' do + before do + allow(diff_file).to receive(:raw_binary?).and_return(true) + end + + it 'returns a Deleted viewer' do + expect(diff_file.simple_viewer).to be_a(DiffViewer::Deleted) + end + end + + context 'when the diff file old and new blob types are different' do + before do + allow(diff_file).to receive(:different_type?).and_return(true) + end + + it 'returns a Deleted viewer' do + expect(diff_file.simple_viewer).to be_a(DiffViewer::Deleted) + end + end + + context 'when the file represented by the diff file is text-based' do + it 'returns a text viewer' do + expect(diff_file.simple_viewer).to be_a(DiffViewer::Text) + end + end + end + + context 'when renamed' do + let(:commit) { project.commit('6907208d755b60ebeacb2e9dfea74c92c3449a1f') } + let(:diff_file) { commit.diffs.diff_file_with_new_path('files/js/commit.coffee') } + + before do + allow(diff_file).to receive(:content_changed?).and_return(nil) + end + + it 'returns a Renamed viewer' do + expect(diff_file.simple_viewer).to be_a(DiffViewer::Renamed) + end + end + + context 'when mode changed' do + before do + allow(diff_file).to receive(:content_changed?).and_return(nil) + allow(diff_file).to receive(:mode_changed?).and_return(true) + end + + it 'returns a Mode Changed viewer' do + expect(diff_file.simple_viewer).to be_a(DiffViewer::ModeChanged) + end + end + end + + describe '#rich_viewer' do + let(:commit) { project.commit('2f63565e7aac07bcdadb654e253078b727143ec4') } + let(:diff_file) { commit.diffs.diff_file_with_new_path('files/images/6049019_460s.jpg') } + + context 'when the diff file has a matching viewer' do + context 'when the diff file content did not change' do + before do + allow(diff_file).to receive(:content_changed?).and_return(false) + end + + it 'returns nil' do + expect(diff_file.rich_viewer).to be_nil + end + end + + context 'when the diff file is not diffable' do + before do + allow(diff_file).to receive(:diffable?).and_return(false) + end + + it 'returns nil' do + expect(diff_file.rich_viewer).to be_nil + end + end + + context 'when the diff file old and new blob types are different' do + before do + allow(diff_file).to receive(:different_type?).and_return(true) + end + + it 'returns nil' do + expect(diff_file.rich_viewer).to be_nil + end + end + + context 'when the diff file has an external storage error' do + before do + allow(diff_file).to receive(:external_storage_error?).and_return(true) + end + + it 'returns nil' do + expect(diff_file.rich_viewer).to be_nil + end + end + + context 'when everything is right' do + it 'returns the viewer' do + expect(diff_file.rich_viewer).to be_a(DiffViewer::Image) + end + end + end + + context 'when the diff file does not have a matching viewer' do + let(:commit) { project.commit('570e7b2abdd848b95f2f578043fc23bd6f6fd24d') } + let(:diff_file) { commit.diffs.diff_file_with_new_path('files/ruby/popen.rb') } + + it 'returns nil' do + expect(diff_file.rich_viewer).to be_nil + end + end + end + + describe '#rendered_as_text?' do + context 'when the simple viewer is text-based' do + let(:commit) { project.commit('570e7b2abdd848b95f2f578043fc23bd6f6fd24d') } + let(:diff_file) { commit.diffs.diff_file_with_new_path('files/ruby/popen.rb') } + + context 'when ignoring errors' do + context 'when the viewer has render errors' do + before do + diff_file.diff.too_large! + end + + it 'returns true' do + expect(diff_file.rendered_as_text?).to be_truthy + end + end + + context "when the viewer doesn't have render errors" do + it 'returns true' do + expect(diff_file.rendered_as_text?).to be_truthy + end + end + end + + context 'when not ignoring errors' do + context 'when the viewer has render errors' do + before do + diff_file.diff.too_large! + end + + it 'returns false' do + expect(diff_file.rendered_as_text?(ignore_errors: false)).to be_falsey + end + end + + context "when the viewer doesn't have render errors" do + it 'returns true' do + expect(diff_file.rendered_as_text?(ignore_errors: false)).to be_truthy + end + end + end + end + + context 'when the simple viewer is binary' do + let(:commit) { project.commit('2f63565e7aac07bcdadb654e253078b727143ec4') } + let(:diff_file) { commit.diffs.diff_file_with_new_path('files/images/6049019_460s.jpg') } + + it 'returns false' do + expect(diff_file.rendered_as_text?).to be_falsey + end + end + end end diff --git a/spec/lib/gitlab/etag_caching/middleware_spec.rb b/spec/lib/gitlab/etag_caching/middleware_spec.rb index 3c6ef7c7ccb..4acf4f047f1 100644 --- a/spec/lib/gitlab/etag_caching/middleware_spec.rb +++ b/spec/lib/gitlab/etag_caching/middleware_spec.rb @@ -15,13 +15,13 @@ describe Gitlab::EtagCaching::Middleware do end it 'does not add ETag header' do - _, headers, _ = middleware.call(build_env(path, if_none_match)) + _, headers, _ = middleware.call(build_request(path, if_none_match)) expect(headers['ETag']).to be_nil end it 'passes status code from app' do - status, _, _ = middleware.call(build_env(path, if_none_match)) + status, _, _ = middleware.call(build_request(path, if_none_match)) expect(status).to eq app_status_code end @@ -39,7 +39,7 @@ describe Gitlab::EtagCaching::Middleware do expect_any_instance_of(Gitlab::EtagCaching::Store) .to receive(:touch).and_return('123') - middleware.call(build_env(path, if_none_match)) + middleware.call(build_request(path, if_none_match)) end context 'when If-None-Match header was specified' do @@ -51,7 +51,7 @@ describe Gitlab::EtagCaching::Middleware do expect(Gitlab::Metrics).to receive(:add_event) .with(:etag_caching_key_not_found, endpoint: 'issue_notes') - middleware.call(build_env(path, if_none_match)) + middleware.call(build_request(path, if_none_match)) end end end @@ -65,7 +65,7 @@ describe Gitlab::EtagCaching::Middleware do end it 'returns this value as header' do - _, headers, _ = middleware.call(build_env(path, if_none_match)) + _, headers, _ = middleware.call(build_request(path, if_none_match)) expect(headers['ETag']).to eq 'W/"123"' end @@ -82,17 +82,17 @@ describe Gitlab::EtagCaching::Middleware do it 'does not call app' do expect(app).not_to receive(:call) - middleware.call(build_env(path, if_none_match)) + middleware.call(build_request(path, if_none_match)) end it 'returns status code 304' do - status, _, _ = middleware.call(build_env(path, if_none_match)) + status, _, _ = middleware.call(build_request(path, if_none_match)) expect(status).to eq 304 end it 'returns empty body' do - _, _, body = middleware.call(build_env(path, if_none_match)) + _, _, body = middleware.call(build_request(path, if_none_match)) expect(body).to be_empty end @@ -103,7 +103,7 @@ describe Gitlab::EtagCaching::Middleware do expect(Gitlab::Metrics).to receive(:add_event) .with(:etag_caching_cache_hit, endpoint: 'issue_notes') - middleware.call(build_env(path, if_none_match)) + middleware.call(build_request(path, if_none_match)) end context 'when polling is disabled' do @@ -113,7 +113,7 @@ describe Gitlab::EtagCaching::Middleware do end it 'returns status code 429' do - status, _, _ = middleware.call(build_env(path, if_none_match)) + status, _, _ = middleware.call(build_request(path, if_none_match)) expect(status).to eq 429 end @@ -131,7 +131,7 @@ describe Gitlab::EtagCaching::Middleware do it 'calls app' do expect(app).to receive(:call).and_return([app_status_code, {}, ['body']]) - middleware.call(build_env(path, if_none_match)) + middleware.call(build_request(path, if_none_match)) end it 'tracks "etag_caching_resource_changed" event' do @@ -142,7 +142,7 @@ describe Gitlab::EtagCaching::Middleware do expect(Gitlab::Metrics).to receive(:add_event) .with(:etag_caching_resource_changed, endpoint: 'issue_notes') - middleware.call(build_env(path, if_none_match)) + middleware.call(build_request(path, if_none_match)) end end @@ -160,7 +160,7 @@ describe Gitlab::EtagCaching::Middleware do expect(Gitlab::Metrics).to receive(:add_event) .with(:etag_caching_header_missing, endpoint: 'issue_notes') - middleware.call(build_env(path, if_none_match)) + middleware.call(build_request(path, if_none_match)) end end @@ -192,10 +192,7 @@ describe Gitlab::EtagCaching::Middleware do .to receive(:get).and_return(value) end - def build_env(path, if_none_match) - { - 'PATH_INFO' => path, - 'HTTP_IF_NONE_MATCH' => if_none_match - } + def build_request(path, if_none_match) + { 'PATH_INFO' => path, 'HTTP_IF_NONE_MATCH' => if_none_match } end end diff --git a/spec/lib/gitlab/etag_caching/router_spec.rb b/spec/lib/gitlab/etag_caching/router_spec.rb index 2bb40827fcf..f69cb502ca6 100644 --- a/spec/lib/gitlab/etag_caching/router_spec.rb +++ b/spec/lib/gitlab/etag_caching/router_spec.rb @@ -2,115 +2,91 @@ require 'spec_helper' describe Gitlab::EtagCaching::Router do it 'matches issue notes endpoint' do - request = build_request( + result = described_class.match( '/my-group/and-subgroup/here-comes-the-project/noteable/issue/1/notes' ) - result = described_class.match(request) - expect(result).to be_present expect(result.name).to eq 'issue_notes' end it 'matches issue title endpoint' do - request = build_request( + result = described_class.match( '/my-group/my-project/issues/123/realtime_changes' ) - result = described_class.match(request) - expect(result).to be_present expect(result.name).to eq 'issue_title' end it 'matches project pipelines endpoint' do - request = build_request( + result = described_class.match( '/my-group/my-project/pipelines.json' ) - result = described_class.match(request) - expect(result).to be_present expect(result.name).to eq 'project_pipelines' end it 'matches commit pipelines endpoint' do - request = build_request( + result = described_class.match( '/my-group/my-project/commit/aa8260d253a53f73f6c26c734c72fdd600f6e6d4/pipelines.json' ) - result = described_class.match(request) - expect(result).to be_present expect(result.name).to eq 'commit_pipelines' end it 'matches new merge request pipelines endpoint' do - request = build_request( + result = described_class.match( '/my-group/my-project/merge_requests/new.json' ) - result = described_class.match(request) - expect(result).to be_present expect(result.name).to eq 'new_merge_request_pipelines' end it 'matches merge request pipelines endpoint' do - request = build_request( + result = described_class.match( '/my-group/my-project/merge_requests/234/pipelines.json' ) - result = described_class.match(request) - expect(result).to be_present expect(result.name).to eq 'merge_request_pipelines' end it 'matches build endpoint' do - request = build_request( + result = described_class.match( '/my-group/my-project/builds/234.json' ) - result = described_class.match(request) - expect(result).to be_present expect(result.name).to eq 'project_build' end it 'does not match blob with confusing name' do - request = build_request( + result = described_class.match( '/my-group/my-project/blob/master/pipelines.json' ) - result = described_class.match(request) - expect(result).to be_blank end it 'matches the environments path' do - request = build_request( + result = described_class.match( '/my-group/my-project/environments.json' ) - result = described_class.match(request) expect(result).to be_present - expect(result.name).to eq 'environments' end it 'matches pipeline#show endpoint' do - request = build_request( + result = described_class.match( '/my-group/my-project/pipelines/2.json' ) - result = described_class.match(request) - expect(result).to be_present expect(result.name).to eq 'project_pipeline' end - - def build_request(path) - double(path_info: path) - end end diff --git a/spec/lib/gitlab/gfm/reference_rewriter_spec.rb b/spec/lib/gitlab/gfm/reference_rewriter_spec.rb index 5d416c9eec3..eaec699ad90 100644 --- a/spec/lib/gitlab/gfm/reference_rewriter_spec.rb +++ b/spec/lib/gitlab/gfm/reference_rewriter_spec.rb @@ -6,7 +6,9 @@ describe Gitlab::Gfm::ReferenceRewriter do let(:new_project) { create(:empty_project, name: 'new-project') } let(:user) { create(:user) } - before { old_project.team << [user, :reporter] } + before do + old_project.team << [user, :reporter] + end describe '#rewrite' do subject do diff --git a/spec/lib/gitlab/git/repository_spec.rb b/spec/lib/gitlab/git/repository_spec.rb index e1e4aa9fde9..eee4c9eab6d 100644 --- a/spec/lib/gitlab/git/repository_spec.rb +++ b/spec/lib/gitlab/git/repository_spec.rb @@ -16,7 +16,9 @@ describe Gitlab::Git::Repository, seed_helper: true do describe '#root_ref' do context 'with gitaly disabled' do - before { allow(Gitlab::GitalyClient).to receive(:feature_enabled?).and_return(false) } + before do + allow(Gitlab::GitalyClient).to receive(:feature_enabled?).and_return(false) + end it 'calls #discover_default_branch' do expect(repository).to receive(:discover_default_branch) @@ -25,8 +27,13 @@ describe Gitlab::Git::Repository, seed_helper: true do end context 'with gitaly enabled' do - before { stub_gitaly } - after { Gitlab::GitalyClient.clear_stubs! } + before do + stub_gitaly + end + + after do + Gitlab::GitalyClient.clear_stubs! + end it 'gets the branch name from GitalyClient' do expect_any_instance_of(Gitlab::GitalyClient::Ref).to receive(:default_branch_name) @@ -120,8 +127,13 @@ describe Gitlab::Git::Repository, seed_helper: true do it { is_expected.not_to include("branch-from-space") } context 'with gitaly enabled' do - before { stub_gitaly } - after { Gitlab::GitalyClient.clear_stubs! } + before do + stub_gitaly + end + + after do + Gitlab::GitalyClient.clear_stubs! + end it 'gets the branch names from GitalyClient' do expect_any_instance_of(Gitlab::GitalyClient::Ref).to receive(:branch_names) @@ -158,8 +170,13 @@ describe Gitlab::Git::Repository, seed_helper: true do it { is_expected.not_to include("v5.0.0") } context 'with gitaly enabled' do - before { stub_gitaly } - after { Gitlab::GitalyClient.clear_stubs! } + before do + stub_gitaly + end + + after do + Gitlab::GitalyClient.clear_stubs! + end it 'gets the tag names from GitalyClient' do expect_any_instance_of(Gitlab::GitalyClient::Ref).to receive(:tag_names) @@ -1280,8 +1297,13 @@ describe Gitlab::Git::Repository, seed_helper: true do end context 'with gitaly enabled' do - before { stub_gitaly } - after { Gitlab::GitalyClient.clear_stubs! } + before do + stub_gitaly + end + + after do + Gitlab::GitalyClient.clear_stubs! + end it 'gets the branches from GitalyClient' do expect_any_instance_of(Gitlab::GitalyClient::Ref).to receive(:local_branches). diff --git a/spec/lib/gitlab/git_access_spec.rb b/spec/lib/gitlab/git_access_spec.rb index 36d1d777583..3dcc20c48e8 100644 --- a/spec/lib/gitlab/git_access_spec.rb +++ b/spec/lib/gitlab/git_access_spec.rb @@ -60,7 +60,9 @@ describe Gitlab::GitAccess, lib: true do let(:actor) { deploy_key } context 'when the DeployKey has access to the project' do - before { deploy_key.projects << project } + before do + deploy_key.projects << project + end it 'allows pull access' do expect { pull_access_check }.not_to raise_error @@ -84,7 +86,9 @@ describe Gitlab::GitAccess, lib: true do context 'when actor is a User' do context 'when the User can read the project' do - before { project.team << [user, :master] } + before do + project.team << [user, :master] + end it 'allows pull access' do expect { pull_access_check }.not_to raise_error @@ -159,7 +163,9 @@ describe Gitlab::GitAccess, lib: true do end describe '#check_command_disabled!' do - before { project.team << [user, :master] } + before do + project.team << [user, :master] + end context 'over http' do let(:protocol) { 'http' } @@ -196,7 +202,9 @@ describe Gitlab::GitAccess, lib: true do describe '#check_download_access!' do describe 'master permissions' do - before { project.team << [user, :master] } + before do + project.team << [user, :master] + end context 'pull code' do it { expect { pull_access_check }.not_to raise_error } @@ -204,7 +212,9 @@ describe Gitlab::GitAccess, lib: true do end describe 'guest permissions' do - before { project.team << [user, :guest] } + before do + project.team << [user, :guest] + end context 'pull code' do it { expect { pull_access_check }.to raise_unauthorized('You are not allowed to download code from this project.') } @@ -253,7 +263,9 @@ describe Gitlab::GitAccess, lib: true do context 'pull code' do context 'when project is authorized' do - before { key.projects << project } + before do + key.projects << project + end it { expect { pull_access_check }.not_to raise_error } end @@ -292,7 +304,9 @@ describe Gitlab::GitAccess, lib: true do end describe 'reporter user' do - before { project.team << [user, :reporter] } + before do + project.team << [user, :reporter] + end context 'pull code' do it { expect { pull_access_check }.not_to raise_error } @@ -303,7 +317,9 @@ describe Gitlab::GitAccess, lib: true do let(:user) { create(:admin) } context 'when member of the project' do - before { project.team << [user, :reporter] } + before do + project.team << [user, :reporter] + end context 'pull code' do it { expect { pull_access_check }.not_to raise_error } @@ -328,7 +344,9 @@ describe Gitlab::GitAccess, lib: true do end describe '#check_push_access!' do - before { merge_into_protected_branch } + before do + merge_into_protected_branch + end let(:unprotected_branch) { 'unprotected_branch' } let(:changes) do @@ -457,19 +475,25 @@ describe Gitlab::GitAccess, lib: true do [%w(feature exact), ['feat*', 'wildcard']].each do |protected_branch_name, protected_branch_type| context do - before { create(:protected_branch, name: protected_branch_name, project: project) } + before do + create(:protected_branch, name: protected_branch_name, project: project) + end run_permission_checks(permissions_matrix) end context "when developers are allowed to push into the #{protected_branch_type} protected branch" do - before { create(:protected_branch, :developers_can_push, name: protected_branch_name, project: project) } + before do + create(:protected_branch, :developers_can_push, name: protected_branch_name, project: project) + end run_permission_checks(permissions_matrix.deep_merge(developer: { push_protected_branch: true, push_all: true, merge_into_protected_branch: true })) end context "developers are allowed to merge into the #{protected_branch_type} protected branch" do - before { create(:protected_branch, :developers_can_merge, name: protected_branch_name, project: project) } + before do + create(:protected_branch, :developers_can_merge, name: protected_branch_name, project: project) + end context "when a merge request exists for the given source/target branch" do context "when the merge request is in progress" do @@ -496,13 +520,17 @@ describe Gitlab::GitAccess, lib: true do end context "when developers are allowed to push and merge into the #{protected_branch_type} protected branch" do - before { create(:protected_branch, :developers_can_merge, :developers_can_push, name: protected_branch_name, project: project) } + before do + create(:protected_branch, :developers_can_merge, :developers_can_push, name: protected_branch_name, project: project) + end run_permission_checks(permissions_matrix.deep_merge(developer: { push_protected_branch: true, push_all: true, merge_into_protected_branch: true })) end context "when no one is allowed to push to the #{protected_branch_name} protected branch" do - before { create(:protected_branch, :no_one_can_push, name: protected_branch_name, project: project) } + before do + create(:protected_branch, :no_one_can_push, name: protected_branch_name, project: project) + end run_permission_checks(permissions_matrix.deep_merge(developer: { push_protected_branch: false, push_all: false, merge_into_protected_branch: false }, master: { push_protected_branch: false, push_all: false, merge_into_protected_branch: false }, @@ -515,7 +543,9 @@ describe Gitlab::GitAccess, lib: true do let(:authentication_abilities) { build_authentication_abilities } context 'when project is authorized' do - before { project.team << [user, :reporter] } + before do + project.team << [user, :reporter] + end it { expect { push_access_check }.to raise_unauthorized('You are not allowed to upload code for this project.') } end @@ -549,7 +579,9 @@ describe Gitlab::GitAccess, lib: true do let(:can_push) { true } context 'when project is authorized' do - before { key.projects << project } + before do + key.projects << project + end it { expect { push_access_check }.not_to raise_error } end @@ -579,7 +611,9 @@ describe Gitlab::GitAccess, lib: true do let(:can_push) { false } context 'when project is authorized' do - before { key.projects << project } + before do + key.projects << project + end it { expect { push_access_check }.to raise_unauthorized('This deploy key does not have write access to this project.') } end diff --git a/spec/lib/gitlab/gitaly_client_spec.rb b/spec/lib/gitlab/gitaly_client_spec.rb index 95ecba67532..ce7b18b784a 100644 --- a/spec/lib/gitlab/gitaly_client_spec.rb +++ b/spec/lib/gitlab/gitaly_client_spec.rb @@ -5,7 +5,9 @@ require 'spec_helper' describe Gitlab::GitalyClient, lib: true, skip_gitaly_mock: true do describe '.stub' do # Notice that this is referring to gRPC "stubs", not rspec stubs - before { described_class.clear_stubs! } + before do + described_class.clear_stubs! + end context 'when passed a UNIX socket address' do it 'passes the address as-is to GRPC' do @@ -41,7 +43,9 @@ describe Gitlab::GitalyClient, lib: true, skip_gitaly_mock: true do let(:real_feature_name) { "gitaly_#{feature_name}" } context 'when Gitaly is disabled' do - before { allow(described_class).to receive(:enabled?).and_return(false) } + before do + allow(described_class).to receive(:enabled?).and_return(false) + end it 'returns false' do expect(described_class.feature_enabled?(feature_name)).to be(false) @@ -66,7 +70,9 @@ describe Gitlab::GitalyClient, lib: true, skip_gitaly_mock: true do end context "when the feature flag is set to disable" do - before { Feature.get(real_feature_name).disable } + before do + Feature.get(real_feature_name).disable + end it 'returns false' do expect(described_class.feature_enabled?(feature_name, status: feature_status)).to be(false) @@ -74,7 +80,9 @@ describe Gitlab::GitalyClient, lib: true, skip_gitaly_mock: true do end context "when the feature flag is set to enable" do - before { Feature.get(real_feature_name).enable } + before do + Feature.get(real_feature_name).enable + end it 'returns true' do expect(described_class.feature_enabled?(feature_name, status: feature_status)).to be(true) @@ -82,7 +90,9 @@ describe Gitlab::GitalyClient, lib: true, skip_gitaly_mock: true do end context "when the feature flag is set to a percentage of time" do - before { Feature.get(real_feature_name).enable_percentage_of_time(70) } + before do + Feature.get(real_feature_name).enable_percentage_of_time(70) + end it 'bases the result on pseudo-random numbers' do expect(Random).to receive(:rand).and_return(0.3) @@ -104,7 +114,9 @@ describe Gitlab::GitalyClient, lib: true, skip_gitaly_mock: true do end context "when the feature flag is set to disable" do - before { Feature.get(real_feature_name).disable } + before do + Feature.get(real_feature_name).disable + end it 'returns false' do expect(described_class.feature_enabled?(feature_name, status: feature_status)).to be(false) diff --git a/spec/lib/gitlab/highlight_spec.rb b/spec/lib/gitlab/highlight_spec.rb index c2bb9f9a166..fdc5b484ef1 100644 --- a/spec/lib/gitlab/highlight_spec.rb +++ b/spec/lib/gitlab/highlight_spec.rb @@ -15,7 +15,9 @@ describe Gitlab::Highlight, lib: true do Gitlab::Highlight.new(blob.path, blob.data, repository: repository) end - before { project.change_head('gitattributes') } + before do + project.change_head('gitattributes') + end describe 'basic language selection' do let(:path) { 'custom-highlighting/test.gitlab-custom' } diff --git a/spec/lib/gitlab/i18n_spec.rb b/spec/lib/gitlab/i18n_spec.rb index a3dbeaa3753..0dba4132101 100644 --- a/spec/lib/gitlab/i18n_spec.rb +++ b/spec/lib/gitlab/i18n_spec.rb @@ -4,7 +4,9 @@ describe Gitlab::I18n, lib: true do let(:user) { create(:user, preferred_language: 'es') } describe '.locale=' do - after { described_class.use_default_locale } + after do + described_class.use_default_locale + end it 'sets the locale based on current user preferred language' do described_class.locale = user.preferred_language diff --git a/spec/lib/gitlab/kubernetes_spec.rb b/spec/lib/gitlab/kubernetes_spec.rb index 91f9d06b85a..e8c599a95ee 100644 --- a/spec/lib/gitlab/kubernetes_spec.rb +++ b/spec/lib/gitlab/kubernetes_spec.rb @@ -1,6 +1,7 @@ require 'spec_helper' describe Gitlab::Kubernetes do + include KubernetesHelpers include described_class describe '#container_exec_url' do @@ -36,4 +37,13 @@ describe Gitlab::Kubernetes do it { expect(result.query).to match(/\Acontainer=container\+1&/) } end end + + describe '#filter_by_label' do + it 'returns matching labels' do + matching_items = [kube_pod(app: 'foo')] + items = matching_items + [kube_pod] + + expect(filter_by_label(items, app: 'foo')).to eq(matching_items) + end + end end diff --git a/spec/lib/gitlab/ldap/adapter_spec.rb b/spec/lib/gitlab/ldap/adapter_spec.rb index 563c074017a..9454878b057 100644 --- a/spec/lib/gitlab/ldap/adapter_spec.rb +++ b/spec/lib/gitlab/ldap/adapter_spec.rb @@ -74,13 +74,17 @@ describe Gitlab::LDAP::Adapter, lib: true do subject { adapter.dn_matches_filter?(:dn, :filter) } context "when the search result is non-empty" do - before { allow(adapter).to receive(:ldap_search).and_return([:foo]) } + before do + allow(adapter).to receive(:ldap_search).and_return([:foo]) + end it { is_expected.to be_truthy } end context "when the search result is empty" do - before { allow(adapter).to receive(:ldap_search).and_return([]) } + before do + allow(adapter).to receive(:ldap_search).and_return([]) + end it { is_expected.to be_falsey } end @@ -91,13 +95,17 @@ describe Gitlab::LDAP::Adapter, lib: true do context "when the search is successful" do context "and the result is non-empty" do - before { allow(ldap).to receive(:search).and_return([:foo]) } + before do + allow(ldap).to receive(:search).and_return([:foo]) + end it { is_expected.to eq [:foo] } end context "and the result is empty" do - before { allow(ldap).to receive(:search).and_return([]) } + before do + allow(ldap).to receive(:search).and_return([]) + end it { is_expected.to eq [] } end diff --git a/spec/lib/gitlab/ldap/user_spec.rb b/spec/lib/gitlab/ldap/user_spec.rb index a0eda685ca3..f0a1dd22fee 100644 --- a/spec/lib/gitlab/ldap/user_spec.rb +++ b/spec/lib/gitlab/ldap/user_spec.rb @@ -173,7 +173,9 @@ describe Gitlab::LDAP::User, lib: true do context 'signup' do context 'dont block on create' do - before { configure_block(false) } + before do + configure_block(false) + end it do ldap_user.save @@ -183,7 +185,9 @@ describe Gitlab::LDAP::User, lib: true do end context 'block on create' do - before { configure_block(true) } + before do + configure_block(true) + end it do ldap_user.save @@ -200,7 +204,9 @@ describe Gitlab::LDAP::User, lib: true do end context 'dont block on create' do - before { configure_block(false) } + before do + configure_block(false) + end it do ldap_user.save @@ -210,7 +216,9 @@ describe Gitlab::LDAP::User, lib: true do end context 'block on create' do - before { configure_block(true) } + before do + configure_block(true) + end it do ldap_user.save diff --git a/spec/lib/gitlab/middleware/rails_queue_duration_spec.rb b/spec/lib/gitlab/middleware/rails_queue_duration_spec.rb index 168090d5b5c..88107536c9e 100644 --- a/spec/lib/gitlab/middleware/rails_queue_duration_spec.rb +++ b/spec/lib/gitlab/middleware/rails_queue_duration_spec.rb @@ -6,7 +6,9 @@ describe Gitlab::Middleware::RailsQueueDuration do let(:env) { {} } let(:transaction) { double(:transaction) } - before { expect(app).to receive(:call).with(env).and_return('yay') } + before do + expect(app).to receive(:call).with(env).and_return('yay') + end describe '#call' do it 'calls the app when metrics are disabled' do @@ -15,7 +17,9 @@ describe Gitlab::Middleware::RailsQueueDuration do end context 'when metrics are enabled' do - before { allow(Gitlab::Metrics).to receive(:current_transaction).and_return(transaction) } + before do + allow(Gitlab::Metrics).to receive(:current_transaction).and_return(transaction) + end it 'calls the app when metrics are enabled but no timing header is found' do expect(middleware.call(env)).to eq('yay') diff --git a/spec/lib/gitlab/o_auth/auth_hash_spec.rb b/spec/lib/gitlab/o_auth/auth_hash_spec.rb index 8aaeb5779d3..19ab17419fc 100644 --- a/spec/lib/gitlab/o_auth/auth_hash_spec.rb +++ b/spec/lib/gitlab/o_auth/auth_hash_spec.rb @@ -55,7 +55,9 @@ describe Gitlab::OAuth::AuthHash, lib: true do end context 'email not provided' do - before { info_hash.delete(:email) } + before do + info_hash.delete(:email) + end it 'generates a temp email' do expect( auth_hash.email).to start_with('temp-email-for-oauth') @@ -63,7 +65,9 @@ describe Gitlab::OAuth::AuthHash, lib: true do end context 'username not provided' do - before { info_hash.delete(:nickname) } + before do + info_hash.delete(:nickname) + end it 'takes the first part of the email as username' do expect(auth_hash.username).to eql 'onur.kucuk_ABC-123' @@ -71,7 +75,9 @@ describe Gitlab::OAuth::AuthHash, lib: true do end context 'name not provided' do - before { info_hash.delete(:name) } + before do + info_hash.delete(:name) + end it 'concats first and lastname as the name' do expect(auth_hash.name).to eql name_utf8 diff --git a/spec/lib/gitlab/o_auth/user_spec.rb b/spec/lib/gitlab/o_auth/user_spec.rb index 8943d1aa488..ea29cb9caf1 100644 --- a/spec/lib/gitlab/o_auth/user_spec.rb +++ b/spec/lib/gitlab/o_auth/user_spec.rb @@ -112,7 +112,9 @@ describe Gitlab::OAuth::User, lib: true do end context 'with new allow_single_sign_on enabled syntax' do - before { stub_omniauth_config(allow_single_sign_on: ['twitter']) } + before do + stub_omniauth_config(allow_single_sign_on: ['twitter']) + end it "creates a user from Omniauth" do oauth_user.save @@ -125,7 +127,9 @@ describe Gitlab::OAuth::User, lib: true do end context "with old allow_single_sign_on enabled syntax" do - before { stub_omniauth_config(allow_single_sign_on: true) } + before do + stub_omniauth_config(allow_single_sign_on: true) + end it "creates a user from Omniauth" do oauth_user.save @@ -138,14 +142,20 @@ describe Gitlab::OAuth::User, lib: true do end context 'with new allow_single_sign_on disabled syntax' do - before { stub_omniauth_config(allow_single_sign_on: []) } + before do + stub_omniauth_config(allow_single_sign_on: []) + end + it 'throws an error' do expect{ oauth_user.save }.to raise_error StandardError end end context 'with old allow_single_sign_on disabled (Default)' do - before { stub_omniauth_config(allow_single_sign_on: false) } + before do + stub_omniauth_config(allow_single_sign_on: false) + end + it 'throws an error' do expect{ oauth_user.save }.to raise_error StandardError end @@ -153,21 +163,30 @@ describe Gitlab::OAuth::User, lib: true do end context "with auto_link_ldap_user disabled (default)" do - before { stub_omniauth_config(auto_link_ldap_user: false) } + before do + stub_omniauth_config(auto_link_ldap_user: false) + end + include_examples "to verify compliance with allow_single_sign_on" end context "with auto_link_ldap_user enabled" do - before { stub_omniauth_config(auto_link_ldap_user: true) } + before do + stub_omniauth_config(auto_link_ldap_user: true) + end context "and no LDAP provider defined" do - before { stub_ldap_config(providers: []) } + before do + stub_ldap_config(providers: []) + end include_examples "to verify compliance with allow_single_sign_on" end context "and at least one LDAP provider is defined" do - before { stub_ldap_config(providers: %w(ldapmain)) } + before do + stub_ldap_config(providers: %w(ldapmain)) + end context "and a corresponding LDAP person" do before do @@ -238,7 +257,9 @@ describe Gitlab::OAuth::User, lib: true do end context "and no corresponding LDAP person" do - before { allow(Gitlab::LDAP::Person).to receive(:find_by_uid).and_return(nil) } + before do + allow(Gitlab::LDAP::Person).to receive(:find_by_uid).and_return(nil) + end include_examples "to verify compliance with allow_single_sign_on" end @@ -248,11 +269,16 @@ describe Gitlab::OAuth::User, lib: true do describe 'blocking' do let(:provider) { 'twitter' } - before { stub_omniauth_config(allow_single_sign_on: ['twitter']) } + + before do + stub_omniauth_config(allow_single_sign_on: ['twitter']) + end context 'signup with omniauth only' do context 'dont block on create' do - before { stub_omniauth_config(block_auto_created_users: false) } + before do + stub_omniauth_config(block_auto_created_users: false) + end it do oauth_user.save @@ -262,7 +288,9 @@ describe Gitlab::OAuth::User, lib: true do end context 'block on create' do - before { stub_omniauth_config(block_auto_created_users: true) } + before do + stub_omniauth_config(block_auto_created_users: true) + end it do oauth_user.save @@ -284,7 +312,9 @@ describe Gitlab::OAuth::User, lib: true do context "and no account for the LDAP user" do context 'dont block on create (LDAP)' do - before { allow_any_instance_of(Gitlab::LDAP::Config).to receive_messages(block_auto_created_users: false) } + before do + allow_any_instance_of(Gitlab::LDAP::Config).to receive_messages(block_auto_created_users: false) + end it do oauth_user.save @@ -294,7 +324,9 @@ describe Gitlab::OAuth::User, lib: true do end context 'block on create (LDAP)' do - before { allow_any_instance_of(Gitlab::LDAP::Config).to receive_messages(block_auto_created_users: true) } + before do + allow_any_instance_of(Gitlab::LDAP::Config).to receive_messages(block_auto_created_users: true) + end it do oauth_user.save @@ -308,7 +340,9 @@ describe Gitlab::OAuth::User, lib: true do let!(:existing_user) { create(:omniauth_user, email: 'john@example.com', extern_uid: 'uid=user1,ou=People,dc=example', provider: 'ldapmain', username: 'john') } context 'dont block on create (LDAP)' do - before { allow_any_instance_of(Gitlab::LDAP::Config).to receive_messages(block_auto_created_users: false) } + before do + allow_any_instance_of(Gitlab::LDAP::Config).to receive_messages(block_auto_created_users: false) + end it do oauth_user.save @@ -318,7 +352,9 @@ describe Gitlab::OAuth::User, lib: true do end context 'block on create (LDAP)' do - before { allow_any_instance_of(Gitlab::LDAP::Config).to receive_messages(block_auto_created_users: true) } + before do + allow_any_instance_of(Gitlab::LDAP::Config).to receive_messages(block_auto_created_users: true) + end it do oauth_user.save @@ -336,7 +372,9 @@ describe Gitlab::OAuth::User, lib: true do end context 'dont block on create' do - before { stub_omniauth_config(block_auto_created_users: false) } + before do + stub_omniauth_config(block_auto_created_users: false) + end it do oauth_user.save @@ -346,7 +384,9 @@ describe Gitlab::OAuth::User, lib: true do end context 'block on create' do - before { stub_omniauth_config(block_auto_created_users: true) } + before do + stub_omniauth_config(block_auto_created_users: true) + end it do oauth_user.save @@ -356,7 +396,9 @@ describe Gitlab::OAuth::User, lib: true do end context 'dont block on create (LDAP)' do - before { allow_any_instance_of(Gitlab::LDAP::Config).to receive_messages(block_auto_created_users: false) } + before do + allow_any_instance_of(Gitlab::LDAP::Config).to receive_messages(block_auto_created_users: false) + end it do oauth_user.save @@ -366,7 +408,9 @@ describe Gitlab::OAuth::User, lib: true do end context 'block on create (LDAP)' do - before { allow_any_instance_of(Gitlab::LDAP::Config).to receive_messages(block_auto_created_users: true) } + before do + allow_any_instance_of(Gitlab::LDAP::Config).to receive_messages(block_auto_created_users: true) + end it do oauth_user.save diff --git a/spec/lib/gitlab/redis_spec.rb b/spec/lib/gitlab/redis_spec.rb index 8b77c925705..593aa5038ad 100644 --- a/spec/lib/gitlab/redis_spec.rb +++ b/spec/lib/gitlab/redis_spec.rb @@ -108,11 +108,18 @@ describe Gitlab::Redis do end describe '.with' do - before { clear_pool } - after { clear_pool } + before do + clear_pool + end + + after do + clear_pool + end context 'when running not on sidekiq workers' do - before { allow(Sidekiq).to receive(:server?).and_return(false) } + before do + allow(Sidekiq).to receive(:server?).and_return(false) + end it 'instantiates a connection pool with size 5' do expect(ConnectionPool).to receive(:new).with(size: 5).and_call_original diff --git a/spec/lib/gitlab/saml/user_spec.rb b/spec/lib/gitlab/saml/user_spec.rb index b106d156b75..a4d2367b72a 100644 --- a/spec/lib/gitlab/saml/user_spec.rb +++ b/spec/lib/gitlab/saml/user_spec.rb @@ -31,11 +31,17 @@ describe Gitlab::Saml::User, lib: true do allow(Gitlab::Saml::Config).to receive_messages({ options: { name: 'saml', groups_attribute: 'groups', external_groups: groups, args: {} } }) end - before { stub_basic_saml_config } + before do + stub_basic_saml_config + end describe 'account exists on server' do - before { stub_omniauth_config({ allow_single_sign_on: ['saml'], auto_link_saml_user: true }) } + before do + stub_omniauth_config({ allow_single_sign_on: ['saml'], auto_link_saml_user: true }) + end + let!(:existing_user) { create(:user, email: 'john@mail.com', username: 'john') } + context 'and should bind with SAML' do it 'adds the SAML identity to the existing user' do saml_user.save @@ -57,7 +63,10 @@ describe Gitlab::Saml::User, lib: true do end end - before { stub_saml_group_config(%w(Interns)) } + before do + stub_saml_group_config(%w(Interns)) + end + context 'are defined but the user does not belong there' do it 'does not mark the user as external' do saml_user.save @@ -80,7 +89,9 @@ describe Gitlab::Saml::User, lib: true do describe 'no account exists on server' do shared_examples 'to verify compliance with allow_single_sign_on' do context 'with allow_single_sign_on enabled' do - before { stub_omniauth_config(allow_single_sign_on: ['saml']) } + before do + stub_omniauth_config(allow_single_sign_on: ['saml']) + end it 'creates a user from SAML' do saml_user.save @@ -93,14 +104,20 @@ describe Gitlab::Saml::User, lib: true do end context 'with allow_single_sign_on default (["saml"])' do - before { stub_omniauth_config(allow_single_sign_on: ['saml']) } + before do + stub_omniauth_config(allow_single_sign_on: ['saml']) + end + it 'does not throw an error' do expect{ saml_user.save }.not_to raise_error end end context 'with allow_single_sign_on disabled' do - before { stub_omniauth_config(allow_single_sign_on: false) } + before do + stub_omniauth_config(allow_single_sign_on: false) + end + it 'throws an error' do expect{ saml_user.save }.to raise_error StandardError end @@ -128,15 +145,22 @@ describe Gitlab::Saml::User, lib: true do end context 'with auto_link_ldap_user disabled (default)' do - before { stub_omniauth_config({ auto_link_ldap_user: false, auto_link_saml_user: false, allow_single_sign_on: ['saml'] }) } + before do + stub_omniauth_config({ auto_link_ldap_user: false, auto_link_saml_user: false, allow_single_sign_on: ['saml'] }) + end + include_examples 'to verify compliance with allow_single_sign_on' end context 'with auto_link_ldap_user enabled' do - before { stub_omniauth_config({ auto_link_ldap_user: true, auto_link_saml_user: false }) } + before do + stub_omniauth_config({ auto_link_ldap_user: true, auto_link_saml_user: false }) + end context 'and at least one LDAP provider is defined' do - before { stub_ldap_config(providers: %w(ldapmain)) } + before do + stub_ldap_config(providers: %w(ldapmain)) + end context 'and a corresponding LDAP person' do before do @@ -239,11 +263,15 @@ describe Gitlab::Saml::User, lib: true do end describe 'blocking' do - before { stub_omniauth_config({ allow_single_sign_on: ['saml'], auto_link_saml_user: true }) } + before do + stub_omniauth_config({ allow_single_sign_on: ['saml'], auto_link_saml_user: true }) + end context 'signup with SAML only' do context 'dont block on create' do - before { stub_omniauth_config(block_auto_created_users: false) } + before do + stub_omniauth_config(block_auto_created_users: false) + end it 'does not block the user' do saml_user.save @@ -253,7 +281,9 @@ describe Gitlab::Saml::User, lib: true do end context 'block on create' do - before { stub_omniauth_config(block_auto_created_users: true) } + before do + stub_omniauth_config(block_auto_created_users: true) + end it 'blocks user' do saml_user.save @@ -270,7 +300,9 @@ describe Gitlab::Saml::User, lib: true do end context 'dont block on create' do - before { stub_omniauth_config(block_auto_created_users: false) } + before do + stub_omniauth_config(block_auto_created_users: false) + end it do saml_user.save @@ -280,7 +312,9 @@ describe Gitlab::Saml::User, lib: true do end context 'block on create' do - before { stub_omniauth_config(block_auto_created_users: true) } + before do + stub_omniauth_config(block_auto_created_users: true) + end it do saml_user.save diff --git a/spec/lib/gitlab/serializer/pagination_spec.rb b/spec/lib/gitlab/serializer/pagination_spec.rb index 519eb1b274f..1bc6536439e 100644 --- a/spec/lib/gitlab/serializer/pagination_spec.rb +++ b/spec/lib/gitlab/serializer/pagination_spec.rb @@ -22,7 +22,9 @@ describe Gitlab::Serializer::Pagination do let(:params) { { page: 1, per_page: 2 } } context 'when a multiple resources are present in relation' do - before { create_list(:user, 3) } + before do + create_list(:user, 3) + end it 'correctly paginates the resource' do expect(subject.count).to be 2 diff --git a/spec/lib/gitlab/template/issue_template_spec.rb b/spec/lib/gitlab/template/issue_template_spec.rb index 329d1d74970..bf45c8d16d6 100644 --- a/spec/lib/gitlab/template/issue_template_spec.rb +++ b/spec/lib/gitlab/template/issue_template_spec.rb @@ -52,7 +52,10 @@ describe Gitlab::Template::IssueTemplate do context 'when repo is bare or empty' do let(:empty_project) { create(:empty_project) } - before { empty_project.add_user(user, Gitlab::Access::MASTER) } + + before do + empty_project.add_user(user, Gitlab::Access::MASTER) + end it "returns empty array" do templates = subject.by_category('', empty_project) @@ -77,7 +80,9 @@ describe Gitlab::Template::IssueTemplate do context "when repo is empty" do let(:empty_project) { create(:empty_project) } - before { empty_project.add_user(user, Gitlab::Access::MASTER) } + before do + empty_project.add_user(user, Gitlab::Access::MASTER) + end it "raises file not found" do issue_template = subject.new('.gitlab/issue_templates/not_existent.md', empty_project) diff --git a/spec/lib/gitlab/template/merge_request_template_spec.rb b/spec/lib/gitlab/template/merge_request_template_spec.rb index 2b0056d9bab..8479f92c8df 100644 --- a/spec/lib/gitlab/template/merge_request_template_spec.rb +++ b/spec/lib/gitlab/template/merge_request_template_spec.rb @@ -52,7 +52,10 @@ describe Gitlab::Template::MergeRequestTemplate do context 'when repo is bare or empty' do let(:empty_project) { create(:empty_project) } - before { empty_project.add_user(user, Gitlab::Access::MASTER) } + + before do + empty_project.add_user(user, Gitlab::Access::MASTER) + end it "returns empty array" do templates = subject.by_category('', empty_project) @@ -77,7 +80,9 @@ describe Gitlab::Template::MergeRequestTemplate do context "when repo is empty" do let(:empty_project) { create(:empty_project) } - before { empty_project.add_user(user, Gitlab::Access::MASTER) } + before do + empty_project.add_user(user, Gitlab::Access::MASTER) + end it "raises file not found" do issue_template = subject.new('.gitlab/merge_request_templates/not_existent.md', empty_project) diff --git a/spec/lib/json_web_token/rsa_token_spec.rb b/spec/lib/json_web_token/rsa_token_spec.rb index 18726754517..e7022bd06f8 100644 --- a/spec/lib/json_web_token/rsa_token_spec.rb +++ b/spec/lib/json_web_token/rsa_token_spec.rb @@ -15,11 +15,15 @@ describe JSONWebToken::RSAToken do let(:rsa_token) { described_class.new(nil) } let(:rsa_encoded) { rsa_token.encoded } - before { allow_any_instance_of(described_class).to receive(:key).and_return(rsa_key) } + before do + allow_any_instance_of(described_class).to receive(:key).and_return(rsa_key) + end context 'token' do context 'for valid key to be validated' do - before { rsa_token['key'] = 'value' } + before do + rsa_token['key'] = 'value' + end subject { JWT.decode(rsa_encoded, rsa_key) } diff --git a/spec/lib/json_web_token/token_spec.rb b/spec/lib/json_web_token/token_spec.rb index 3d955e4d774..d7e7560d962 100644 --- a/spec/lib/json_web_token/token_spec.rb +++ b/spec/lib/json_web_token/token_spec.rb @@ -3,7 +3,10 @@ describe JSONWebToken::Token do context 'custom parameters' do let(:value) { 'value' } - before { token[:key] = value } + + before do + token[:key] = value + end it { expect(token[:key]).to eq(value) } it { expect(token.payload).to include(key: value) } diff --git a/spec/mailers/notify_spec.rb b/spec/mailers/notify_spec.rb index ec6f6c42eac..980b24370d0 100644 --- a/spec/mailers/notify_spec.rb +++ b/spec/mailers/notify_spec.rb @@ -130,8 +130,13 @@ describe Notify do end context 'with a preferred language' do - before { Gitlab::I18n.locale = :es } - after { Gitlab::I18n.use_default_locale } + before do + Gitlab::I18n.locale = :es + end + + after do + Gitlab::I18n.use_default_locale + end it 'always generates the email using the default language' do is_expected.to have_body_text('foo, bar, and baz') @@ -581,7 +586,9 @@ describe Notify do let(:project) { create(:project, :repository) } let(:commit) { project.commit } - before(:each) { allow(note).to receive(:noteable).and_return(commit) } + before do + allow(note).to receive(:noteable).and_return(commit) + end subject { described_class.note_commit_email(recipient.id, note.id) } @@ -603,7 +610,10 @@ describe Notify do describe 'on a merge request' do let(:merge_request) { create(:merge_request, source_project: project, target_project: project) } let(:note_on_merge_request_path) { namespace_project_merge_request_path(project.namespace, project, merge_request, anchor: "note_#{note.id}") } - before(:each) { allow(note).to receive(:noteable).and_return(merge_request) } + + before do + allow(note).to receive(:noteable).and_return(merge_request) + end subject { described_class.note_merge_request_email(recipient.id, note.id) } @@ -625,7 +635,10 @@ describe Notify do describe 'on an issue' do let(:issue) { create(:issue, project: project) } let(:note_on_issue_path) { namespace_project_issue_path(project.namespace, project, issue, anchor: "note_#{note.id}") } - before(:each) { allow(note).to receive(:noteable).and_return(issue) } + + before do + allow(note).to receive(:noteable).and_return(issue) + end subject { described_class.note_issue_email(recipient.id, note.id) } @@ -687,7 +700,9 @@ describe Notify do let(:commit) { project.commit } let(:note) { create(:discussion_note_on_commit, commit_id: commit.id, project: project, author: note_author) } - before(:each) { allow(note).to receive(:noteable).and_return(commit) } + before do + allow(note).to receive(:noteable).and_return(commit) + end subject { described_class.note_commit_email(recipient.id, note.id) } @@ -711,7 +726,10 @@ describe Notify do let(:merge_request) { create(:merge_request, source_project: project, target_project: project) } let(:note) { create(:discussion_note_on_merge_request, noteable: merge_request, project: project, author: note_author) } let(:note_on_merge_request_path) { namespace_project_merge_request_path(project.namespace, project, merge_request, anchor: "note_#{note.id}") } - before(:each) { allow(note).to receive(:noteable).and_return(merge_request) } + + before do + allow(note).to receive(:noteable).and_return(merge_request) + end subject { described_class.note_merge_request_email(recipient.id, note.id) } @@ -735,7 +753,10 @@ describe Notify do let(:issue) { create(:issue, project: project) } let(:note) { create(:discussion_note_on_issue, noteable: issue, project: project, author: note_author) } let(:note_on_issue_path) { namespace_project_issue_path(project.namespace, project, issue, anchor: "note_#{note.id}") } - before(:each) { allow(note).to receive(:noteable).and_return(issue) } + + before do + allow(note).to receive(:noteable).and_return(issue) + end subject { described_class.note_issue_email(recipient.id, note.id) } diff --git a/spec/migrations/rename_more_reserved_project_names_spec.rb b/spec/migrations/rename_more_reserved_project_names_spec.rb index 36e82729c23..4bd8d4ac0d1 100644 --- a/spec/migrations/rename_more_reserved_project_names_spec.rb +++ b/spec/migrations/rename_more_reserved_project_names_spec.rb @@ -17,7 +17,9 @@ describe RenameMoreReservedProjectNames, truncate: true do describe '#up' do context 'when project repository exists' do - before { project.create_repository } + before do + project.create_repository + end context 'when no exception is raised' do it 'renames project with reserved names' do diff --git a/spec/migrations/rename_reserved_project_names_spec.rb b/spec/migrations/rename_reserved_project_names_spec.rb index 4fb7ed36884..05e021c2e32 100644 --- a/spec/migrations/rename_reserved_project_names_spec.rb +++ b/spec/migrations/rename_reserved_project_names_spec.rb @@ -17,7 +17,9 @@ describe RenameReservedProjectNames, truncate: true do describe '#up' do context 'when project repository exists' do - before { project.create_repository } + before do + project.create_repository + end context 'when no exception is raised' do it 'renames project with reserved names' do diff --git a/spec/models/application_setting_spec.rb b/spec/models/application_setting_spec.rb index fa229542f70..166a4474abf 100644 --- a/spec/models/application_setting_spec.rb +++ b/spec/models/application_setting_spec.rb @@ -78,7 +78,9 @@ describe ApplicationSetting, models: true do # Upgraded databases will have this sort of content context 'repository_storages is a String, not an Array' do - before { setting.__send__(:raw_write_attribute, :repository_storages, 'default') } + before do + setting.__send__(:raw_write_attribute, :repository_storages, 'default') + end it { expect(setting.repository_storages_before_type_cast).to eq('default') } it { expect(setting.repository_storages).to eq(['default']) } diff --git a/spec/models/ci/build_spec.rb b/spec/models/ci/build_spec.rb index b0716e04d3d..975a8b01e9e 100644 --- a/spec/models/ci/build_spec.rb +++ b/spec/models/ci/build_spec.rb @@ -95,12 +95,18 @@ describe Ci::Build, :models do it { is_expected.to be_truthy } context 'is expired' do - before { build.update(artifacts_expire_at: Time.now - 7.days) } + before do + build.update(artifacts_expire_at: Time.now - 7.days) + end + it { is_expected.to be_falsy } end context 'is not expired' do - before { build.update(artifacts_expire_at: Time.now + 7.days) } + before do + build.update(artifacts_expire_at: Time.now + 7.days) + end + it { is_expected.to be_truthy } end end @@ -110,13 +116,17 @@ describe Ci::Build, :models do subject { build.artifacts_expired? } context 'is expired' do - before { build.update(artifacts_expire_at: Time.now - 7.days) } + before do + build.update(artifacts_expire_at: Time.now - 7.days) + end it { is_expected.to be_truthy } end context 'is not expired' do - before { build.update(artifacts_expire_at: Time.now + 7.days) } + before do + build.update(artifacts_expire_at: Time.now + 7.days) + end it { is_expected.to be_falsey } end @@ -141,7 +151,9 @@ describe Ci::Build, :models do context 'when artifacts_expire_at is specified' do let(:expire_at) { Time.now + 7.days } - before { build.artifacts_expire_at = expire_at } + before do + build.artifacts_expire_at = expire_at + end it { is_expected.to be_within(5).of(expire_at - Time.now) } end @@ -1071,7 +1083,9 @@ describe Ci::Build, :models do describe '#has_expiring_artifacts?' do context 'when artifacts have expiration date set' do - before { build.update(artifacts_expire_at: 1.day.from_now) } + before do + build.update(artifacts_expire_at: 1.day.from_now) + end it 'has expiring artifacts' do expect(build).to have_expiring_artifacts @@ -1079,7 +1093,9 @@ describe Ci::Build, :models do end context 'when artifacts do not have expiration date set' do - before { build.update(artifacts_expire_at: nil) } + before do + build.update(artifacts_expire_at: nil) + end it 'does not have expiring artifacts' do expect(build).not_to have_expiring_artifacts diff --git a/spec/models/ci/pipeline_spec.rb b/spec/models/ci/pipeline_spec.rb index b50c7700bd3..e86cbe8498a 100644 --- a/spec/models/ci/pipeline_spec.rb +++ b/spec/models/ci/pipeline_spec.rb @@ -1156,7 +1156,9 @@ describe Ci::Pipeline, models: true do end context 'when pipeline is not stuck' do - before { create(:ci_runner, :shared, :online) } + before do + create(:ci_runner, :shared, :online) + end it 'is not stuck' do expect(pipeline).not_to be_stuck diff --git a/spec/models/commit_spec.rb b/spec/models/commit_spec.rb index ba247dcc5cf..6056d78da4e 100644 --- a/spec/models/commit_spec.rb +++ b/spec/models/commit_spec.rb @@ -206,19 +206,25 @@ eos it { expect(commit.reverts_commit?(another_commit, user)).to be_falsy } context 'commit has no description' do - before { allow(commit).to receive(:description?).and_return(false) } + before do + allow(commit).to receive(:description?).and_return(false) + end it { expect(commit.reverts_commit?(another_commit, user)).to be_falsy } end context "another_commit's description does not revert commit" do - before { allow(commit).to receive(:description).and_return("Foo Bar") } + before do + allow(commit).to receive(:description).and_return("Foo Bar") + end it { expect(commit.reverts_commit?(another_commit, user)).to be_falsy } end context "another_commit's description reverts commit" do - before { allow(commit).to receive(:description).and_return("Foo #{another_commit.revert_description} Bar") } + before do + allow(commit).to receive(:description).and_return("Foo #{another_commit.revert_description} Bar") + end it { expect(commit.reverts_commit?(another_commit, user)).to be_truthy } end diff --git a/spec/models/commit_status_spec.rb b/spec/models/commit_status_spec.rb index c50b8bf7b13..9262ce08987 100644 --- a/spec/models/commit_status_spec.rb +++ b/spec/models/commit_status_spec.rb @@ -31,7 +31,10 @@ describe CommitStatus, :models do describe '#author' do subject { commit_status.author } - before { commit_status.author = User.new } + + before do + commit_status.author = User.new + end it { is_expected.to eq(commit_status.user) } end @@ -50,14 +53,18 @@ describe CommitStatus, :models do subject { commit_status.started? } context 'without started_at' do - before { commit_status.started_at = nil } + before do + commit_status.started_at = nil + end it { is_expected.to be_falsey } end %w[running success failed].each do |status| context "if commit status is #{status}" do - before { commit_status.status = status } + before do + commit_status.status = status + end it { is_expected.to be_truthy } end @@ -65,7 +72,9 @@ describe CommitStatus, :models do %w[pending canceled].each do |status| context "if commit status is #{status}" do - before { commit_status.status = status } + before do + commit_status.status = status + end it { is_expected.to be_falsey } end @@ -77,7 +86,9 @@ describe CommitStatus, :models do %w[pending running].each do |state| context "if commit_status.status is #{state}" do - before { commit_status.status = state } + before do + commit_status.status = state + end it { is_expected.to be_truthy } end @@ -85,7 +96,9 @@ describe CommitStatus, :models do %w[success failed canceled].each do |state| context "if commit_status.status is #{state}" do - before { commit_status.status = state } + before do + commit_status.status = state + end it { is_expected.to be_falsey } end @@ -97,7 +110,9 @@ describe CommitStatus, :models do %w[success failed canceled].each do |state| context "if commit_status.status is #{state}" do - before { commit_status.status = state } + before do + commit_status.status = state + end it { is_expected.to be_truthy } end @@ -105,7 +120,9 @@ describe CommitStatus, :models do %w[pending running].each do |state| context "if commit_status.status is #{state}" do - before { commit_status.status = state } + before do + commit_status.status = state + end it { is_expected.to be_falsey } end @@ -271,7 +288,9 @@ describe CommitStatus, :models do subject { commit_status.before_sha } context 'when no before_sha is set for pipeline' do - before { pipeline.before_sha = nil } + before do + pipeline.before_sha = nil + end it 'returns blank sha' do is_expected.to eq(Gitlab::Git::BLANK_SHA) @@ -280,7 +299,10 @@ describe CommitStatus, :models do context 'for before_sha set for pipeline' do let(:value) { '1234' } - before { pipeline.before_sha = value } + + before do + pipeline.before_sha = value + end it 'returns the set value' do is_expected.to eq(value) diff --git a/spec/models/concerns/access_requestable_spec.rb b/spec/models/concerns/access_requestable_spec.rb index 4829ef17a20..97b7e48bb3c 100644 --- a/spec/models/concerns/access_requestable_spec.rb +++ b/spec/models/concerns/access_requestable_spec.rb @@ -14,7 +14,9 @@ describe AccessRequestable do let(:group) { create(:group, :public, :access_requestable) } let(:user) { create(:user) } - before { group.request_access(user) } + before do + group.request_access(user) + end it { expect(group.requesters.exists?(user_id: user)).to be_truthy } end @@ -32,7 +34,9 @@ describe AccessRequestable do let(:project) { create(:empty_project, :public, :access_requestable) } let(:user) { create(:user) } - before { project.request_access(user) } + before do + project.request_access(user) + end it { expect(project.requesters.exists?(user_id: user)).to be_truthy } end diff --git a/spec/models/concerns/issuable_spec.rb b/spec/models/concerns/issuable_spec.rb index 27890e33b49..1a9bda64191 100644 --- a/spec/models/concerns/issuable_spec.rb +++ b/spec/models/concerns/issuable_spec.rb @@ -200,7 +200,9 @@ describe Issuable do let(:project) { issue.project } context 'user is not a participant in the issue' do - before { allow(issue).to receive(:participants).with(user).and_return([]) } + before do + allow(issue).to receive(:participants).with(user).and_return([]) + end it 'returns false when no subcription exists' do expect(issue.subscribed?(user, project)).to be_falsey @@ -220,7 +222,9 @@ describe Issuable do end context 'user is a participant in the issue' do - before { allow(issue).to receive(:participants).with(user).and_return([user]) } + before do + allow(issue).to receive(:participants).with(user).and_return([user]) + end it 'returns false when no subcription exists' do expect(issue.subscribed?(user, project)).to be_truthy @@ -252,7 +256,9 @@ describe Issuable do end context "issue is assigned" do - before { issue.assignees << user } + before do + issue.assignees << user + end it "returns correct hook data" do expect(data[:assignees].first).to eq(user.hook_attrs) @@ -276,7 +282,9 @@ describe Issuable do context 'issue has labels' do let(:labels) { [create(:label), create(:label)] } - before { issue.update_attribute(:labels, labels)} + before do + issue.update_attribute(:labels, labels) + end it 'includes labels in the hook data' do expect(data[:labels]).to eq(labels.map(&:hook_attrs)) diff --git a/spec/models/concerns/mentionable_spec.rb b/spec/models/concerns/mentionable_spec.rb index e382c7120de..e2a29e0ae70 100644 --- a/spec/models/concerns/mentionable_spec.rb +++ b/spec/models/concerns/mentionable_spec.rb @@ -61,7 +61,9 @@ describe Issue, "Mentionable" do end context 'when the current user can see the issue' do - before { private_project.team << [user, Gitlab::Access::DEVELOPER] } + before do + private_project.team << [user, Gitlab::Access::DEVELOPER] + end it 'includes the reference' do expect(referenced_issues(user)).to contain_exactly(private_issue, public_issue) diff --git a/spec/models/concerns/reactive_caching_spec.rb b/spec/models/concerns/reactive_caching_spec.rb index a0765a264cf..808247ebfd5 100644 --- a/spec/models/concerns/reactive_caching_spec.rb +++ b/spec/models/concerns/reactive_caching_spec.rb @@ -40,7 +40,10 @@ describe ReactiveCaching, caching: true do let(:instance) { CacheTest.new(666, &calculation) } describe '#with_reactive_cache' do - before { stub_reactive_cache } + before do + stub_reactive_cache + end + subject(:go!) { instance.result } context 'when cache is empty' do @@ -60,12 +63,17 @@ describe ReactiveCaching, caching: true do end context 'when the cache is full' do - before { stub_reactive_cache(instance, 4) } + before do + stub_reactive_cache(instance, 4) + end it { is_expected.to eq(2) } context 'and expired' do - before { invalidate_reactive_cache(instance) } + before do + invalidate_reactive_cache(instance) + end + it { is_expected.to be_nil } end end @@ -84,7 +92,9 @@ describe ReactiveCaching, caching: true do subject(:go!) { instance.exclusively_update_reactive_cache! } context 'when the lease is free and lifetime is not exceeded' do - before { stub_reactive_cache(instance, "preexisting") } + before do + stub_reactive_cache(instance, "preexisting") + end it 'takes and releases the lease' do expect_any_instance_of(Gitlab::ExclusiveLease).to receive(:try_obtain).and_return("000000") @@ -106,7 +116,10 @@ describe ReactiveCaching, caching: true do end context 'and #calculate_reactive_cache raises an exception' do - before { stub_reactive_cache(instance, "preexisting") } + before do + stub_reactive_cache(instance, "preexisting") + end + let(:calculation) { -> { raise "foo"} } it 'leaves the cache untouched' do diff --git a/spec/models/concerns/token_authenticatable_spec.rb b/spec/models/concerns/token_authenticatable_spec.rb index 4b0bfa43abf..882afeccfc6 100644 --- a/spec/models/concerns/token_authenticatable_spec.rb +++ b/spec/models/concerns/token_authenticatable_spec.rb @@ -49,7 +49,10 @@ describe ApplicationSetting, 'TokenAuthenticatable' do end context 'token is generated' do - before { subject.send("reset_#{token_field}!") } + before do + subject.send("reset_#{token_field}!") + end + it 'persists a new token' do expect(subject.send(:read_attribute, token_field)).to be_a String end diff --git a/spec/models/diff_viewer/base_spec.rb b/spec/models/diff_viewer/base_spec.rb new file mode 100644 index 00000000000..3755f4a56f3 --- /dev/null +++ b/spec/models/diff_viewer/base_spec.rb @@ -0,0 +1,150 @@ +require 'spec_helper' + +describe DiffViewer::Base, model: true do + include FakeBlobHelpers + + let(:project) { create(:project, :repository) } + let(:commit) { project.commit('570e7b2abdd848b95f2f578043fc23bd6f6fd24d') } + let(:diff_file) { commit.diffs.diff_file_with_new_path('files/ruby/popen.rb') } + + let(:viewer_class) do + Class.new(described_class) do + include DiffViewer::ServerSide + + self.extensions = %w(jpg) + self.binary = true + self.collapse_limit = 1.megabyte + self.size_limit = 5.megabytes + end + end + + let(:viewer) { viewer_class.new(diff_file) } + + describe '.can_render?' do + context 'when the extension is supported' do + let(:commit) { project.commit('2f63565e7aac07bcdadb654e253078b727143ec4') } + let(:diff_file) { commit.diffs.diff_file_with_new_path('files/images/6049019_460s.jpg') } + + context 'when the binaryness matches' do + it 'returns true' do + expect(viewer_class.can_render?(diff_file)).to be_truthy + end + end + + context 'when the binaryness does not match' do + before do + allow(diff_file.old_blob).to receive(:binary?).and_return(false) + allow(diff_file.new_blob).to receive(:binary?).and_return(false) + end + + it 'returns false' do + expect(viewer_class.can_render?(diff_file)).to be_falsey + end + end + end + + context 'when the file type is supported' do + let(:commit) { project.commit('1a0b36b3cdad1d2ee32457c102a8c0b7056fa863') } + let(:diff_file) { commit.diffs.diff_file_with_new_path('LICENSE') } + + before do + viewer_class.file_types = %i(license) + viewer_class.binary = false + end + + context 'when the binaryness matches' do + it 'returns true' do + expect(viewer_class.can_render?(diff_file)).to be_truthy + end + end + + context 'when the binaryness does not match' do + before do + allow(diff_file.old_blob).to receive(:binary?).and_return(true) + allow(diff_file.new_blob).to receive(:binary?).and_return(true) + end + + it 'returns false' do + expect(viewer_class.can_render?(diff_file)).to be_falsey + end + end + end + + context 'when the extension and file type are not supported' do + it 'returns false' do + expect(viewer_class.can_render?(diff_file)).to be_falsey + end + end + + context 'when the file was renamed and only the old blob is supported' do + let(:commit) { project.commit('2f63565e7aac07bcdadb654e253078b727143ec4') } + let(:diff_file) { commit.diffs.diff_file_with_new_path('files/images/6049019_460s.jpg') } + + before do + allow(diff_file).to receive(:renamed_file?).and_return(true) + allow(diff_file.new_blob).to receive(:extension).and_return('jpeg') + end + + it 'returns false' do + expect(viewer_class.can_render?(diff_file)).to be_falsey + end + end + end + + describe '#collapsed?' do + context 'when the combined blob size is larger than the collapse limit' do + before do + allow(diff_file.old_blob).to receive(:raw_size).and_return(512.kilobytes) + allow(diff_file.new_blob).to receive(:raw_size).and_return(513.kilobytes) + end + + it 'returns true' do + expect(viewer.collapsed?).to be_truthy + end + end + + context 'when the combined blob size is smaller than the collapse limit' do + it 'returns false' do + expect(viewer.collapsed?).to be_falsey + end + end + end + + describe '#too_large?' do + context 'when the combined blob size is larger than the size limit' do + before do + allow(diff_file.old_blob).to receive(:raw_size).and_return(2.megabytes) + allow(diff_file.new_blob).to receive(:raw_size).and_return(4.megabytes) + end + + it 'returns true' do + expect(viewer.too_large?).to be_truthy + end + end + + context 'when the blob size is smaller than the size limit' do + it 'returns false' do + expect(viewer.too_large?).to be_falsey + end + end + end + + describe '#render_error' do + context 'when the combined blob size is larger than the size limit' do + before do + allow(diff_file.old_blob).to receive(:raw_size).and_return(2.megabytes) + allow(diff_file.new_blob).to receive(:raw_size).and_return(4.megabytes) + end + + it 'returns :too_large' do + expect(viewer.render_error).to eq(:too_large) + end + end + + context 'when the combined blob size is smaller than the size limit' do + it 'returns nil' do + expect(viewer.render_error).to be_nil + end + end + end +end diff --git a/spec/models/diff_viewer/server_side_spec.rb b/spec/models/diff_viewer/server_side_spec.rb new file mode 100644 index 00000000000..2d926e06936 --- /dev/null +++ b/spec/models/diff_viewer/server_side_spec.rb @@ -0,0 +1,36 @@ +require 'spec_helper' + +describe DiffViewer::ServerSide, model: true do + let(:project) { create(:project, :repository) } + let(:commit) { project.commit('570e7b2abdd848b95f2f578043fc23bd6f6fd24d') } + let(:diff_file) { commit.diffs.diff_file_with_new_path('files/ruby/popen.rb') } + + let(:viewer_class) do + Class.new(DiffViewer::Base) do + include DiffViewer::ServerSide + end + end + + subject { viewer_class.new(diff_file) } + + describe '#prepare!' do + it 'loads all diff file data' do + expect(diff_file.old_blob).to receive(:load_all_data!) + expect(diff_file.new_blob).to receive(:load_all_data!) + + subject.prepare! + end + end + + describe '#render_error' do + context 'when the diff file is stored externally' do + before do + allow(diff_file).to receive(:stored_externally?).and_return(true) + end + + it 'return :server_side_but_stored_externally' do + expect(subject.render_error).to eq(:server_side_but_stored_externally) + end + end + end +end diff --git a/spec/models/generic_commit_status_spec.rb b/spec/models/generic_commit_status_spec.rb index f4c3e6d503f..152e97e09bf 100644 --- a/spec/models/generic_commit_status_spec.rb +++ b/spec/models/generic_commit_status_spec.rb @@ -19,7 +19,10 @@ describe GenericCommitStatus, models: true do describe '#context' do subject { generic_commit_status.context } - before { generic_commit_status.context = 'my_context' } + + before do + generic_commit_status.context = 'my_context' + end it { is_expected.to eq(generic_commit_status.name) } end @@ -39,7 +42,9 @@ describe GenericCommitStatus, models: true do end context 'when user has ability to see datails' do - before { project.team << [user, :developer] } + before do + project.team << [user, :developer] + end it 'details path points to an external URL' do expect(status).to have_details diff --git a/spec/models/group_spec.rb b/spec/models/group_spec.rb index 3d437ca0fcc..449b7c2f7d7 100644 --- a/spec/models/group_spec.rb +++ b/spec/models/group_spec.rb @@ -143,14 +143,20 @@ describe Group, models: true do describe '#add_user' do let(:user) { create(:user) } - before { group.add_user(user, GroupMember::MASTER) } + + before do + group.add_user(user, GroupMember::MASTER) + end it { expect(group.group_members.masters.map(&:user)).to include(user) } end describe '#add_users' do let(:user) { create(:user) } - before { group.add_users([user.id], GroupMember::GUEST) } + + before do + group.add_users([user.id], GroupMember::GUEST) + end it "updates the group permission" do expect(group.group_members.guests.map(&:user)).to include(user) @@ -162,7 +168,10 @@ describe Group, models: true do describe '#avatar_type' do let(:user) { create(:user) } - before { group.add_user(user, GroupMember::MASTER) } + + before do + group.add_user(user, GroupMember::MASTER) + end it "is true if avatar is image" do group.update_attribute(:avatar, 'uploads/avatar.png') @@ -182,7 +191,9 @@ describe Group, models: true do let(:avatar_path) { "/uploads/system/group/avatar/#{group.id}/dk.png" } context 'when avatar file is uploaded' do - before { group.add_master(user) } + before do + group.add_master(user) + end it 'shows correct avatar url' do expect(group.avatar_url).to eq(avatar_path) @@ -222,7 +233,9 @@ describe Group, models: true do end describe '#has_owner?' do - before { @members = setup_group_members(group) } + before do + @members = setup_group_members(group) + end it { expect(group.has_owner?(@members[:owner])).to be_truthy } it { expect(group.has_owner?(@members[:master])).to be_falsey } @@ -233,7 +246,9 @@ describe Group, models: true do end describe '#has_master?' do - before { @members = setup_group_members(group) } + before do + @members = setup_group_members(group) + end it { expect(group.has_master?(@members[:owner])).to be_falsey } it { expect(group.has_master?(@members[:master])).to be_truthy } diff --git a/spec/models/issue_spec.rb b/spec/models/issue_spec.rb index bb4e70db2e9..12e7d646382 100644 --- a/spec/models/issue_spec.rb +++ b/spec/models/issue_spec.rb @@ -245,7 +245,9 @@ describe Issue, models: true do let(:project) { create(:empty_project) } let(:issue) { create(:issue, project: project) } - before { project.team << [user, :reporter] } + before do + project.team << [user, :reporter] + end it { is_expected.to eq true } @@ -259,12 +261,18 @@ describe Issue, models: true do let(:to_project) { create(:empty_project) } context 'destination project allowed' do - before { to_project.team << [user, :reporter] } + before do + to_project.team << [user, :reporter] + end + it { is_expected.to eq true } end context 'destination project not allowed' do - before { to_project.team << [user, :guest] } + before do + to_project.team << [user, :guest] + end + it { is_expected.to eq false } end end @@ -549,7 +557,9 @@ describe Issue, models: true do end context 'when the user is the project owner' do - before { project.team << [user, :master] } + before do + project.team << [user, :master] + end it 'returns true for a regular issue' do issue = build(:issue, project: project) diff --git a/spec/models/merge_request_diff_spec.rb b/spec/models/merge_request_diff_spec.rb index ed9fde57bf7..25f7062860b 100644 --- a/spec/models/merge_request_diff_spec.rb +++ b/spec/models/merge_request_diff_spec.rb @@ -36,7 +36,9 @@ describe MergeRequestDiff, models: true do end context 'when the raw diffs are empty' do - before { mr_diff.update_attributes(st_diffs: '') } + before do + mr_diff.update_attributes(st_diffs: '') + end it 'returns an empty DiffCollection' do expect(mr_diff.raw_diffs).to be_a(Gitlab::Git::DiffCollection) @@ -45,7 +47,9 @@ describe MergeRequestDiff, models: true do end context 'when the raw diffs have invalid content' do - before { mr_diff.update_attributes(st_diffs: ["--broken-diff"]) } + before do + mr_diff.update_attributes(st_diffs: ["--broken-diff"]) + end it 'returns an empty DiffCollection' do expect(mr_diff.raw_diffs.to_a).to be_empty diff --git a/spec/models/merge_request_spec.rb b/spec/models/merge_request_spec.rb index 060754fab63..cd2f11dec96 100644 --- a/spec/models/merge_request_spec.rb +++ b/spec/models/merge_request_spec.rb @@ -892,7 +892,9 @@ describe MergeRequest, models: true do end context 'when broken' do - before { allow(subject).to receive(:broken?) { true } } + before do + allow(subject).to receive(:broken?) { true } + end it 'becomes unmergeable' do expect { subject.check_if_can_be_merged }.to change { subject.merge_status }.to('cannot_be_merged') @@ -944,7 +946,9 @@ describe MergeRequest, models: true do end context 'when not open' do - before { subject.close } + before do + subject.close + end it 'returns false' do expect(subject.mergeable_state?).to be_falsey @@ -952,7 +956,9 @@ describe MergeRequest, models: true do end context 'when working in progress' do - before { subject.title = 'WIP MR' } + before do + subject.title = 'WIP MR' + end it 'returns false' do expect(subject.mergeable_state?).to be_falsey @@ -960,7 +966,9 @@ describe MergeRequest, models: true do end context 'when broken' do - before { allow(subject).to receive(:broken?) { true } } + before do + allow(subject).to receive(:broken?) { true } + end it 'returns false' do expect(subject.mergeable_state?).to be_falsey diff --git a/spec/models/note_spec.rb b/spec/models/note_spec.rb index 7a01cef9b4b..d4d4fc86343 100644 --- a/spec/models/note_spec.rb +++ b/spec/models/note_spec.rb @@ -26,14 +26,18 @@ describe Note, models: true do it { is_expected.to validate_presence_of(:project) } context 'when note is on commit' do - before { allow(subject).to receive(:for_commit?).and_return(true) } + before do + allow(subject).to receive(:for_commit?).and_return(true) + end it { is_expected.to validate_presence_of(:commit_id) } it { is_expected.not_to validate_presence_of(:noteable_id) } end context 'when note is not on commit' do - before { allow(subject).to receive(:for_commit?).and_return(false) } + before do + allow(subject).to receive(:for_commit?).and_return(false) + end it { is_expected.not_to validate_presence_of(:commit_id) } it { is_expected.to validate_presence_of(:noteable_id) } diff --git a/spec/models/project_services/bamboo_service_spec.rb b/spec/models/project_services/bamboo_service_spec.rb index 4014d6129ee..e62fd69e567 100644 --- a/spec/models/project_services/bamboo_service_spec.rb +++ b/spec/models/project_services/bamboo_service_spec.rb @@ -24,7 +24,9 @@ describe BambooService, models: true, caching: true do describe 'Validations' do context 'when service is active' do - before { subject.active = true } + before do + subject.active = true + end it { is_expected.to validate_presence_of(:build_key) } it { is_expected.to validate_presence_of(:bamboo_url) } @@ -60,7 +62,9 @@ describe BambooService, models: true, caching: true do end context 'when service is inactive' do - before { subject.active = false } + before do + subject.active = false + end it { is_expected.not_to validate_presence_of(:build_key) } it { is_expected.not_to validate_presence_of(:bamboo_url) } diff --git a/spec/models/project_services/bugzilla_service_spec.rb b/spec/models/project_services/bugzilla_service_spec.rb index 739cc72b2ff..5f17bbde390 100644 --- a/spec/models/project_services/bugzilla_service_spec.rb +++ b/spec/models/project_services/bugzilla_service_spec.rb @@ -8,7 +8,9 @@ describe BugzillaService, models: true do describe 'Validations' do context 'when service is active' do - before { subject.active = true } + before do + subject.active = true + end it { is_expected.to validate_presence_of(:project_url) } it { is_expected.to validate_presence_of(:issues_url) } @@ -19,7 +21,9 @@ describe BugzillaService, models: true do end context 'when service is inactive' do - before { subject.active = false } + before do + subject.active = false + end it { is_expected.not_to validate_presence_of(:project_url) } it { is_expected.not_to validate_presence_of(:issues_url) } diff --git a/spec/models/project_services/buildkite_service_spec.rb b/spec/models/project_services/buildkite_service_spec.rb index 05b602d8106..dd529597067 100644 --- a/spec/models/project_services/buildkite_service_spec.rb +++ b/spec/models/project_services/buildkite_service_spec.rb @@ -23,7 +23,9 @@ describe BuildkiteService, models: true, caching: true do describe 'Validations' do context 'when service is active' do - before { subject.active = true } + before do + subject.active = true + end it { is_expected.to validate_presence_of(:project_url) } it { is_expected.to validate_presence_of(:token) } @@ -31,7 +33,9 @@ describe BuildkiteService, models: true, caching: true do end context 'when service is inactive' do - before { subject.active = false } + before do + subject.active = false + end it { is_expected.not_to validate_presence_of(:project_url) } it { is_expected.not_to validate_presence_of(:token) } diff --git a/spec/models/project_services/campfire_service_spec.rb b/spec/models/project_services/campfire_service_spec.rb index 953e664fb66..de55627dd27 100644 --- a/spec/models/project_services/campfire_service_spec.rb +++ b/spec/models/project_services/campfire_service_spec.rb @@ -8,13 +8,17 @@ describe CampfireService, models: true do describe 'Validations' do context 'when service is active' do - before { subject.active = true } + before do + subject.active = true + end it { is_expected.to validate_presence_of(:token) } end context 'when service is inactive' do - before { subject.active = false } + before do + subject.active = false + end it { is_expected.not_to validate_presence_of(:token) } end diff --git a/spec/models/project_services/chat_message/wiki_page_message_spec.rb b/spec/models/project_services/chat_message/wiki_page_message_spec.rb index 4ca1b8aa7b7..17355c1e6f1 100644 --- a/spec/models/project_services/chat_message/wiki_page_message_spec.rb +++ b/spec/models/project_services/chat_message/wiki_page_message_spec.rb @@ -23,7 +23,9 @@ describe ChatMessage::WikiPageMessage, models: true do context 'without markdown' do describe '#pretext' do context 'when :action == "create"' do - before { args[:object_attributes][:action] = 'create' } + before do + args[:object_attributes][:action] = 'create' + end it 'returns a message that a new wiki page was created' do expect(subject.pretext).to eq( @@ -33,7 +35,9 @@ describe ChatMessage::WikiPageMessage, models: true do end context 'when :action == "update"' do - before { args[:object_attributes][:action] = 'update' } + before do + args[:object_attributes][:action] = 'update' + end it 'returns a message that a wiki page was updated' do expect(subject.pretext).to eq( @@ -47,7 +51,9 @@ describe ChatMessage::WikiPageMessage, models: true do let(:color) { '#345' } context 'when :action == "create"' do - before { args[:object_attributes][:action] = 'create' } + before do + args[:object_attributes][:action] = 'create' + end it 'returns the attachment for a new wiki page' do expect(subject.attachments).to eq([ @@ -60,7 +66,9 @@ describe ChatMessage::WikiPageMessage, models: true do end context 'when :action == "update"' do - before { args[:object_attributes][:action] = 'update' } + before do + args[:object_attributes][:action] = 'update' + end it 'returns the attachment for an updated wiki page' do expect(subject.attachments).to eq([ @@ -81,7 +89,9 @@ describe ChatMessage::WikiPageMessage, models: true do describe '#pretext' do context 'when :action == "create"' do - before { args[:object_attributes][:action] = 'create' } + before do + args[:object_attributes][:action] = 'create' + end it 'returns a message that a new wiki page was created' do expect(subject.pretext).to eq( @@ -90,7 +100,9 @@ describe ChatMessage::WikiPageMessage, models: true do end context 'when :action == "update"' do - before { args[:object_attributes][:action] = 'update' } + before do + args[:object_attributes][:action] = 'update' + end it 'returns a message that a wiki page was updated' do expect(subject.pretext).to eq( @@ -101,7 +113,9 @@ describe ChatMessage::WikiPageMessage, models: true do describe '#attachments' do context 'when :action == "create"' do - before { args[:object_attributes][:action] = 'create' } + before do + args[:object_attributes][:action] = 'create' + end it 'returns the attachment for a new wiki page' do expect(subject.attachments).to eq('Wiki page description') @@ -109,7 +123,9 @@ describe ChatMessage::WikiPageMessage, models: true do end context 'when :action == "update"' do - before { args[:object_attributes][:action] = 'update' } + before do + args[:object_attributes][:action] = 'update' + end it 'returns the attachment for an updated wiki page' do expect(subject.attachments).to eq('Wiki page description') @@ -119,7 +135,9 @@ describe ChatMessage::WikiPageMessage, models: true do describe '#activity' do context 'when :action == "create"' do - before { args[:object_attributes][:action] = 'create' } + before do + args[:object_attributes][:action] = 'create' + end it 'returns the attachment for a new wiki page' do expect(subject.activity).to eq({ @@ -132,7 +150,9 @@ describe ChatMessage::WikiPageMessage, models: true do end context 'when :action == "update"' do - before { args[:object_attributes][:action] = 'update' } + before do + args[:object_attributes][:action] = 'update' + end it 'returns the attachment for an updated wiki page' do expect(subject.activity).to eq({ diff --git a/spec/models/project_services/custom_issue_tracker_service_spec.rb b/spec/models/project_services/custom_issue_tracker_service_spec.rb index 63320931e76..9e574762232 100644 --- a/spec/models/project_services/custom_issue_tracker_service_spec.rb +++ b/spec/models/project_services/custom_issue_tracker_service_spec.rb @@ -8,7 +8,9 @@ describe CustomIssueTrackerService, models: true do describe 'Validations' do context 'when service is active' do - before { subject.active = true } + before do + subject.active = true + end it { is_expected.to validate_presence_of(:project_url) } it { is_expected.to validate_presence_of(:issues_url) } @@ -19,7 +21,9 @@ describe CustomIssueTrackerService, models: true do end context 'when service is inactive' do - before { subject.active = false } + before do + subject.active = false + end it { is_expected.not_to validate_presence_of(:project_url) } it { is_expected.not_to validate_presence_of(:issues_url) } diff --git a/spec/models/project_services/drone_ci_service_spec.rb b/spec/models/project_services/drone_ci_service_spec.rb index 044737c6026..1400175427f 100644 --- a/spec/models/project_services/drone_ci_service_spec.rb +++ b/spec/models/project_services/drone_ci_service_spec.rb @@ -10,7 +10,9 @@ describe DroneCiService, models: true, caching: true do describe 'validations' do context 'active' do - before { subject.active = true } + before do + subject.active = true + end it { is_expected.to validate_presence_of(:token) } it { is_expected.to validate_presence_of(:drone_url) } @@ -18,7 +20,9 @@ describe DroneCiService, models: true, caching: true do end context 'inactive' do - before { subject.active = false } + before do + subject.active = false + end it { is_expected.not_to validate_presence_of(:token) } it { is_expected.not_to validate_presence_of(:drone_url) } diff --git a/spec/models/project_services/emails_on_push_service_spec.rb b/spec/models/project_services/emails_on_push_service_spec.rb index e6f78898c82..d9b7010e5e5 100644 --- a/spec/models/project_services/emails_on_push_service_spec.rb +++ b/spec/models/project_services/emails_on_push_service_spec.rb @@ -3,13 +3,17 @@ require 'spec_helper' describe EmailsOnPushService do describe 'Validations' do context 'when service is active' do - before { subject.active = true } + before do + subject.active = true + end it { is_expected.to validate_presence_of(:recipients) } end context 'when service is inactive' do - before { subject.active = false } + before do + subject.active = false + end it { is_expected.not_to validate_presence_of(:recipients) } end diff --git a/spec/models/project_services/external_wiki_service_spec.rb b/spec/models/project_services/external_wiki_service_spec.rb index bdeea1db1e3..291fc645a1c 100644 --- a/spec/models/project_services/external_wiki_service_spec.rb +++ b/spec/models/project_services/external_wiki_service_spec.rb @@ -9,14 +9,18 @@ describe ExternalWikiService, models: true do describe 'Validations' do context 'when service is active' do - before { subject.active = true } + before do + subject.active = true + end it { is_expected.to validate_presence_of(:external_wiki_url) } it_behaves_like 'issue tracker service URL attribute', :external_wiki_url end context 'when service is inactive' do - before { subject.active = false } + before do + subject.active = false + end it { is_expected.not_to validate_presence_of(:external_wiki_url) } end diff --git a/spec/models/project_services/flowdock_service_spec.rb b/spec/models/project_services/flowdock_service_spec.rb index a97e8c6e4ce..56ace04dd58 100644 --- a/spec/models/project_services/flowdock_service_spec.rb +++ b/spec/models/project_services/flowdock_service_spec.rb @@ -8,13 +8,17 @@ describe FlowdockService, models: true do describe 'Validations' do context 'when service is active' do - before { subject.active = true } + before do + subject.active = true + end it { is_expected.to validate_presence_of(:token) } end context 'when service is inactive' do - before { subject.active = false } + before do + subject.active = false + end it { is_expected.not_to validate_presence_of(:token) } end diff --git a/spec/models/project_services/gemnasium_service_spec.rb b/spec/models/project_services/gemnasium_service_spec.rb index a13fbae03eb..65c9e714bd1 100644 --- a/spec/models/project_services/gemnasium_service_spec.rb +++ b/spec/models/project_services/gemnasium_service_spec.rb @@ -8,14 +8,18 @@ describe GemnasiumService, models: true do describe 'Validations' do context 'when service is active' do - before { subject.active = true } + before do + subject.active = true + end it { is_expected.to validate_presence_of(:token) } it { is_expected.to validate_presence_of(:api_key) } end context 'when service is inactive' do - before { subject.active = false } + before do + subject.active = false + end it { is_expected.not_to validate_presence_of(:token) } it { is_expected.not_to validate_presence_of(:api_key) } diff --git a/spec/models/project_services/hipchat_service_spec.rb b/spec/models/project_services/hipchat_service_spec.rb index 1200ae7eb22..c7c8e9651ab 100644 --- a/spec/models/project_services/hipchat_service_spec.rb +++ b/spec/models/project_services/hipchat_service_spec.rb @@ -8,13 +8,17 @@ describe HipchatService, models: true do describe 'Validations' do context 'when service is active' do - before { subject.active = true } + before do + subject.active = true + end it { is_expected.to validate_presence_of(:token) } end context 'when service is inactive' do - before { subject.active = false } + before do + subject.active = false + end it { is_expected.not_to validate_presence_of(:token) } end diff --git a/spec/models/project_services/irker_service_spec.rb b/spec/models/project_services/irker_service_spec.rb index d5a16226d9d..a5c4938b54e 100644 --- a/spec/models/project_services/irker_service_spec.rb +++ b/spec/models/project_services/irker_service_spec.rb @@ -10,13 +10,17 @@ describe IrkerService, models: true do describe 'Validations' do context 'when service is active' do - before { subject.active = true } + before do + subject.active = true + end it { is_expected.to validate_presence_of(:recipients) } end context 'when service is inactive' do - before { subject.active = false } + before do + subject.active = false + end it { is_expected.not_to validate_presence_of(:recipients) } end diff --git a/spec/models/project_services/jira_service_spec.rb b/spec/models/project_services/jira_service_spec.rb index 0ee050196e4..e2b8226124f 100644 --- a/spec/models/project_services/jira_service_spec.rb +++ b/spec/models/project_services/jira_service_spec.rb @@ -10,7 +10,9 @@ describe JiraService, models: true do describe 'Validations' do context 'when service is active' do - before { subject.active = true } + before do + subject.active = true + end it { is_expected.to validate_presence_of(:url) } it { is_expected.to validate_presence_of(:project_key) } @@ -18,7 +20,9 @@ describe JiraService, models: true do end context 'when service is inactive' do - before { subject.active = false } + before do + subject.active = false + end it { is_expected.not_to validate_presence_of(:url) } end diff --git a/spec/models/project_services/kubernetes_service_spec.rb b/spec/models/project_services/kubernetes_service_spec.rb index 0dcf4a4b5d6..858ad595dbf 100644 --- a/spec/models/project_services/kubernetes_service_spec.rb +++ b/spec/models/project_services/kubernetes_service_spec.rb @@ -7,31 +7,15 @@ describe KubernetesService, models: true, caching: true do let(:project) { build_stubbed(:kubernetes_project) } let(:service) { project.kubernetes_service } - # We use Kubeclient to interactive with the Kubernetes API. It will - # GET /api/v1 for a list of resources the API supports. This must be stubbed - # in addition to any other HTTP requests we expect it to perform. - let(:discovery_url) { service.api_url + '/api/v1' } - let(:discovery_response) { { body: kube_discovery_body.to_json } } - - let(:pods_url) { service.api_url + "/api/v1/namespaces/#{service.actual_namespace}/pods" } - let(:pods_response) { { body: kube_pods_body(kube_pod).to_json } } - - def stub_kubeclient_discover - WebMock.stub_request(:get, discovery_url).to_return(discovery_response) - end - - def stub_kubeclient_pods - stub_kubeclient_discover - WebMock.stub_request(:get, pods_url).to_return(pods_response) - end - describe "Associations" do it { is_expected.to belong_to :project } end describe 'Validations' do context 'when service is active' do - before { subject.active = true } + before do + subject.active = true + end it { is_expected.not_to validate_presence_of(:namespace) } it { is_expected.to validate_presence_of(:api_url) } @@ -66,7 +50,9 @@ describe KubernetesService, models: true, caching: true do end context 'when service is inactive' do - before { subject.active = false } + before do + subject.active = false + end it { is_expected.not_to validate_presence_of(:api_url) } it { is_expected.not_to validate_presence_of(:token) } @@ -87,7 +73,9 @@ describe KubernetesService, models: true, caching: true do end context 'as template' do - before { subject.template = true } + before do + subject.template = true + end it 'sets the namespace to the default' do expect(kube_namespace).not_to be_nil @@ -96,7 +84,9 @@ describe KubernetesService, models: true, caching: true do end context 'with associated project' do - before { subject.project = project } + before do + subject.project = project + end it 'sets the namespace to the default' do expect(kube_namespace).not_to be_nil @@ -111,6 +101,34 @@ describe KubernetesService, models: true, caching: true do it "returns the default namespace" do is_expected.to eq(service.send(:default_namespace)) end + + context 'when namespace is specified' do + before do + service.namespace = 'my-namespace' + end + + it "returns the user-namespace" do + is_expected.to eq('my-namespace') + end + end + + context 'when service is not assigned to project' do + before do + service.project = nil + end + + it "does not return namespace" do + is_expected.to be_nil + end + end + end + + describe '#actual_namespace' do + subject { service.actual_namespace } + + it "returns the default namespace" do + is_expected.to eq(service.send(:default_namespace)) + end context 'when namespace is specified' do before do @@ -134,6 +152,8 @@ describe KubernetesService, models: true, caching: true do end describe '#test' do + let(:discovery_url) { 'https://kubernetes.example.com/api/v1' } + before do stub_kubeclient_discover end @@ -142,7 +162,8 @@ describe KubernetesService, models: true, caching: true do let(:discovery_url) { 'https://kubernetes.example.com/prefix/api/v1' } it 'tests with the prefix' do - service.api_url = 'https://kubernetes.example.com/prefix/' + service.api_url = 'https://kubernetes.example.com/prefix' + stub_kubeclient_discover expect(service.test[:success]).to be_truthy expect(WebMock).to have_requested(:get, discovery_url).once @@ -170,9 +191,9 @@ describe KubernetesService, models: true, caching: true do end context 'failure' do - let(:discovery_response) { { status: 404 } } - it 'fails to read the discovery endpoint' do + WebMock.stub_request(:get, service.api_url + '/api/v1').to_return(status: 404) + expect(service.test[:success]).to be_falsy expect(WebMock).to have_requested(:get, discovery_url).once end @@ -188,7 +209,9 @@ describe KubernetesService, models: true, caching: true do end context 'namespace is provided' do - before { subject.namespace = 'my-project' } + before do + subject.namespace = 'my-project' + end it 'sets the variables' do expect(subject.predefined_variables).to include( @@ -258,27 +281,36 @@ describe KubernetesService, models: true, caching: true do end describe '#calculate_reactive_cache' do - before { stub_kubeclient_pods } subject { service.calculate_reactive_cache } context 'when service is inactive' do - before { service.active = false } + before do + service.active = false + end it { is_expected.to be_nil } end context 'when kubernetes responds with valid pods' do + before do + stub_kubeclient_pods + end + it { is_expected.to eq(pods: [kube_pod]) } end - context 'when kubernetes responds with 500' do - let(:pods_response) { { status: 500 } } + context 'when kubernetes responds with 500s' do + before do + stub_kubeclient_pods(status: 500) + end it { expect { subject }.to raise_error(KubeException) } end - context 'when kubernetes responds with 404' do - let(:pods_response) { { status: 404 } } + context 'when kubernetes responds with 404s' do + before do + stub_kubeclient_pods(status: 404) + end it { is_expected.to eq(pods: []) } end diff --git a/spec/models/project_services/microsoft_teams_service_spec.rb b/spec/models/project_services/microsoft_teams_service_spec.rb index facc034f69c..bd50a2d1470 100644 --- a/spec/models/project_services/microsoft_teams_service_spec.rb +++ b/spec/models/project_services/microsoft_teams_service_spec.rb @@ -11,14 +11,18 @@ describe MicrosoftTeamsService, models: true do describe 'Validations' do context 'when service is active' do - before { subject.active = true } + before do + subject.active = true + end it { is_expected.to validate_presence_of(:webhook) } it_behaves_like 'issue tracker service URL attribute', :webhook end context 'when service is inactive' do - before { subject.active = false } + before do + subject.active = false + end it { is_expected.not_to validate_presence_of(:webhook) } end diff --git a/spec/models/project_services/pivotaltracker_service_spec.rb b/spec/models/project_services/pivotaltracker_service_spec.rb index a76e909d04d..f4c1a9c94b6 100644 --- a/spec/models/project_services/pivotaltracker_service_spec.rb +++ b/spec/models/project_services/pivotaltracker_service_spec.rb @@ -8,13 +8,17 @@ describe PivotaltrackerService, models: true do describe 'Validations' do context 'when service is active' do - before { subject.active = true } + before do + subject.active = true + end it { is_expected.to validate_presence_of(:token) } end context 'when service is inactive' do - before { subject.active = false } + before do + subject.active = false + end it { is_expected.not_to validate_presence_of(:token) } end diff --git a/spec/models/project_services/prometheus_service_spec.rb b/spec/models/project_services/prometheus_service_spec.rb index 1f9d3c07b51..71b53732164 100644 --- a/spec/models/project_services/prometheus_service_spec.rb +++ b/spec/models/project_services/prometheus_service_spec.rb @@ -14,13 +14,17 @@ describe PrometheusService, models: true, caching: true do describe 'Validations' do context 'when service is active' do - before { subject.active = true } + before do + subject.active = true + end it { is_expected.to validate_presence_of(:api_url) } end context 'when service is inactive' do - before { subject.active = false } + before do + subject.active = false + end it { is_expected.not_to validate_presence_of(:api_url) } end diff --git a/spec/models/project_services/pushover_service_spec.rb b/spec/models/project_services/pushover_service_spec.rb index a7e7594a7d5..9171d9604ee 100644 --- a/spec/models/project_services/pushover_service_spec.rb +++ b/spec/models/project_services/pushover_service_spec.rb @@ -8,7 +8,9 @@ describe PushoverService, models: true do describe 'Validations' do context 'when service is active' do - before { subject.active = true } + before do + subject.active = true + end it { is_expected.to validate_presence_of(:api_key) } it { is_expected.to validate_presence_of(:user_key) } @@ -16,7 +18,9 @@ describe PushoverService, models: true do end context 'when service is inactive' do - before { subject.active = false } + before do + subject.active = false + end it { is_expected.not_to validate_presence_of(:api_key) } it { is_expected.not_to validate_presence_of(:user_key) } diff --git a/spec/models/project_services/redmine_service_spec.rb b/spec/models/project_services/redmine_service_spec.rb index 0a7b237a051..6631d9040b1 100644 --- a/spec/models/project_services/redmine_service_spec.rb +++ b/spec/models/project_services/redmine_service_spec.rb @@ -8,7 +8,9 @@ describe RedmineService, models: true do describe 'Validations' do context 'when service is active' do - before { subject.active = true } + before do + subject.active = true + end it { is_expected.to validate_presence_of(:project_url) } it { is_expected.to validate_presence_of(:issues_url) } @@ -19,7 +21,9 @@ describe RedmineService, models: true do end context 'when service is inactive' do - before { subject.active = false } + before do + subject.active = false + end it { is_expected.not_to validate_presence_of(:project_url) } it { is_expected.not_to validate_presence_of(:issues_url) } diff --git a/spec/models/project_services/teamcity_service_spec.rb b/spec/models/project_services/teamcity_service_spec.rb index 77b18e1c7d0..7349eb4149a 100644 --- a/spec/models/project_services/teamcity_service_spec.rb +++ b/spec/models/project_services/teamcity_service_spec.rb @@ -24,7 +24,9 @@ describe TeamcityService, models: true, caching: true do describe 'Validations' do context 'when service is active' do - before { subject.active = true } + before do + subject.active = true + end it { is_expected.to validate_presence_of(:build_type) } it { is_expected.to validate_presence_of(:teamcity_url) } @@ -60,7 +62,9 @@ describe TeamcityService, models: true, caching: true do end context 'when service is inactive' do - before { subject.active = false } + before do + subject.active = false + end it { is_expected.not_to validate_presence_of(:build_type) } it { is_expected.not_to validate_presence_of(:teamcity_url) } diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb index 454eeb58ecd..63333b7af1f 100644 --- a/spec/models/project_spec.rb +++ b/spec/models/project_spec.rb @@ -1005,13 +1005,17 @@ describe Project, models: true do subject { project.shared_runners_enabled } context 'are enabled' do - before { stub_application_setting(shared_runners_enabled: true) } + before do + stub_application_setting(shared_runners_enabled: true) + end it { is_expected.to be_truthy } end context 'are disabled' do - before { stub_application_setting(shared_runners_enabled: false) } + before do + stub_application_setting(shared_runners_enabled: false) + end it { is_expected.to be_falsey } end @@ -1107,7 +1111,9 @@ describe Project, models: true do subject { project.pages_deployed? } context 'if public folder does exist' do - before { allow(Dir).to receive(:exist?).with(project.public_pages_path).and_return(true) } + before do + allow(Dir).to receive(:exist?).with(project.public_pages_path).and_return(true) + end it { is_expected.to be_truthy } end @@ -1365,7 +1371,9 @@ describe Project, models: true do subject { project.container_registry_url } - before { stub_container_registry_config(**registry_settings) } + before do + stub_container_registry_config(**registry_settings) + end context 'for enabled registry' do let(:registry_settings) do @@ -1389,7 +1397,9 @@ describe Project, models: true do let(:project) { create(:empty_project) } context 'when container registry is enabled' do - before { stub_container_registry_config(enabled: true) } + before do + stub_container_registry_config(enabled: true) + end context 'when tags are present for multi-level registries' do before do @@ -1427,7 +1437,9 @@ describe Project, models: true do end context 'when container registry is disabled' do - before { stub_container_registry_config(enabled: false) } + before do + stub_container_registry_config(enabled: false) + end it 'should not have image tags' do expect(project).not_to have_container_registry_tags @@ -1945,7 +1957,9 @@ describe Project, models: true do describe '#parent_changed?' do let(:project) { create(:empty_project) } - before { project.namespace_id = 7 } + before do + project.namespace_id = 7 + end it { expect(project.parent_changed?).to be_truthy } end diff --git a/spec/models/project_team_spec.rb b/spec/models/project_team_spec.rb index 497e3cdf415..ea3cd5fe10a 100644 --- a/spec/models/project_team_spec.rb +++ b/spec/models/project_team_spec.rb @@ -240,7 +240,9 @@ describe ProjectTeam, models: true do it { expect(project.team.max_member_access(requester.id)).to eq(Gitlab::Access::NO_ACCESS) } context 'but share_with_group_lock is true' do - before { project.namespace.update(share_with_group_lock: true) } + before do + project.namespace.update(share_with_group_lock: true) + end it { expect(project.team.max_member_access(master.id)).to eq(Gitlab::Access::NO_ACCESS) } it { expect(project.team.max_member_access(reporter.id)).to eq(Gitlab::Access::NO_ACCESS) } diff --git a/spec/models/project_wiki_spec.rb b/spec/models/project_wiki_spec.rb index 224067f58dd..3f5f4eea4a1 100644 --- a/spec/models/project_wiki_spec.rb +++ b/spec/models/project_wiki_spec.rb @@ -8,7 +8,10 @@ describe ProjectWiki, models: true do let(:project_wiki) { ProjectWiki.new(project, user) } subject { project_wiki } - before { project_wiki.wiki } + + before do + project_wiki.wiki + end describe "#path_with_namespace" do it "returns the project path with namespace with the .wiki extension" do diff --git a/spec/models/route_spec.rb b/spec/models/route_spec.rb index c1fe1b06c52..1754253e0f2 100644 --- a/spec/models/route_spec.rb +++ b/spec/models/route_spec.rb @@ -9,7 +9,10 @@ describe Route, models: true do end describe 'validations' do - before { route } + before do + expect(route).to be_persisted + end + it { is_expected.to validate_presence_of(:source) } it { is_expected.to validate_presence_of(:path) } it { is_expected.to validate_uniqueness_of(:path) } @@ -59,7 +62,9 @@ describe Route, models: true do context 'path update' do context 'when route name is set' do - before { route.update_attributes(path: 'bar') } + before do + route.update_attributes(path: 'bar') + end it 'updates children routes with new path' do expect(described_class.exists?(path: 'bar')).to be_truthy diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb index d5bd9946ab6..1a1bbd60504 100644 --- a/spec/models/user_spec.rb +++ b/spec/models/user_spec.rb @@ -1584,7 +1584,9 @@ describe User, models: true do end context 'user is member of the top group' do - before { group.add_owner(user) } + before do + group.add_owner(user) + end if Group.supports_nested_groups? it 'returns all groups' do @@ -1602,7 +1604,9 @@ describe User, models: true do end context 'user is member of the first child (internal node), branch 1', :nested_groups do - before { nested_group_1.add_owner(user) } + before do + nested_group_1.add_owner(user) + end it 'returns the groups in the hierarchy' do is_expected.to match_array [ @@ -1613,7 +1617,9 @@ describe User, models: true do end context 'user is member of the first child (internal node), branch 2', :nested_groups do - before { nested_group_2.add_owner(user) } + before do + nested_group_2.add_owner(user) + end it 'returns the groups in the hierarchy' do is_expected.to match_array [ @@ -1624,7 +1630,9 @@ describe User, models: true do end context 'user is member of the last child (leaf node)', :nested_groups do - before { nested_group_1_1.add_owner(user) } + before do + nested_group_1_1.add_owner(user) + end it 'returns the groups in the hierarchy' do is_expected.to match_array [ diff --git a/spec/policies/ci/build_policy_spec.rb b/spec/policies/ci/build_policy_spec.rb index 3f4ce222b60..48a139d4b83 100644 --- a/spec/policies/ci/build_policy_spec.rb +++ b/spec/policies/ci/build_policy_spec.rb @@ -10,7 +10,9 @@ describe Ci::BuildPolicy, :models do end shared_context 'public pipelines disabled' do - before { project.update_attribute(:public_builds, false) } + before do + project.update_attribute(:public_builds, false) + end end describe '#rules' do @@ -54,7 +56,9 @@ describe Ci::BuildPolicy, :models do let(:project) { create(:empty_project, :public) } context 'team member is a guest' do - before { project.team << [user, :guest] } + before do + project.team << [user, :guest] + end context 'when public builds are enabled' do it 'includes ability to read build' do @@ -72,7 +76,9 @@ describe Ci::BuildPolicy, :models do end context 'team member is a reporter' do - before { project.team << [user, :reporter] } + before do + project.team << [user, :reporter] + end context 'when public builds are enabled' do it 'includes ability to read build' do diff --git a/spec/policies/project_snippet_policy_spec.rb b/spec/policies/project_snippet_policy_spec.rb index ddbed5f781e..d2b2528c57a 100644 --- a/spec/policies/project_snippet_policy_spec.rb +++ b/spec/policies/project_snippet_policy_spec.rb @@ -78,7 +78,9 @@ describe ProjectSnippetPolicy, models: true do context 'project team member external user' do subject { abilities(external_user, :internal) } - before { project.team << [external_user, :developer] } + before do + project.team << [external_user, :developer] + end it do is_expected.to include(:read_project_snippet) @@ -120,7 +122,9 @@ describe ProjectSnippetPolicy, models: true do context 'project team member normal user' do subject { abilities(regular_user, :private) } - before { project.team << [regular_user, :developer] } + before do + project.team << [regular_user, :developer] + end it do is_expected.to include(:read_project_snippet) @@ -131,7 +135,9 @@ describe ProjectSnippetPolicy, models: true do context 'project team member external user' do subject { abilities(external_user, :private) } - before { project.team << [external_user, :developer] } + before do + project.team << [external_user, :developer] + end it do is_expected.to include(:read_project_snippet) diff --git a/spec/requests/api/award_emoji_spec.rb b/spec/requests/api/award_emoji_spec.rb index bbdef0aeb1b..6d822b5cb4f 100644 --- a/spec/requests/api/award_emoji_spec.rb +++ b/spec/requests/api/award_emoji_spec.rb @@ -9,7 +9,9 @@ describe API::AwardEmoji do let!(:downvote) { create(:award_emoji, :downvote, awardable: merge_request, user: user) } let!(:note) { create(:note, project: project, noteable: issue) } - before { project.team << [user, :master] } + before do + project.team << [user, :master] + end describe "GET /projects/:id/awardable/:awardable_id/award_emoji" do context 'on an issue' do diff --git a/spec/requests/api/commit_statuses_spec.rb b/spec/requests/api/commit_statuses_spec.rb index 6b637a03b6f..b8ca73c321c 100644 --- a/spec/requests/api/commit_statuses_spec.rb +++ b/spec/requests/api/commit_statuses_spec.rb @@ -34,7 +34,9 @@ describe API::CommitStatuses do let!(:status6) { create_status(master, status: 'success') } context 'latest commit statuses' do - before { get api(get_url, reporter) } + before do + get api(get_url, reporter) + end it 'returns latest commit statuses' do expect(response).to have_http_status(200) @@ -48,7 +50,9 @@ describe API::CommitStatuses do end context 'all commit statuses' do - before { get api(get_url, reporter), all: 1 } + before do + get api(get_url, reporter), all: 1 + end it 'returns all commit statuses' do expect(response).to have_http_status(200) @@ -61,7 +65,9 @@ describe API::CommitStatuses do end context 'latest commit statuses for specific ref' do - before { get api(get_url, reporter), ref: 'develop' } + before do + get api(get_url, reporter), ref: 'develop' + end it 'returns latest commit statuses for specific ref' do expect(response).to have_http_status(200) @@ -72,7 +78,9 @@ describe API::CommitStatuses do end context 'latest commit statues for specific name' do - before { get api(get_url, reporter), name: 'coverage' } + before do + get api(get_url, reporter), name: 'coverage' + end it 'return latest commit statuses for specific name' do expect(response).to have_http_status(200) @@ -85,7 +93,9 @@ describe API::CommitStatuses do end context 'ci commit does not exist' do - before { get api(get_url, reporter) } + before do + get api(get_url, reporter) + end it 'returns empty array' do expect(response.status).to eq 200 @@ -95,7 +105,9 @@ describe API::CommitStatuses do end context "guest user" do - before { get api(get_url, guest) } + before do + get api(get_url, guest) + end it "does not return project commits" do expect(response).to have_http_status(403) @@ -103,7 +115,9 @@ describe API::CommitStatuses do end context "unauthorized user" do - before { get api(get_url) } + before do + get api(get_url) + end it "does not return project commits" do expect(response).to have_http_status(401) @@ -209,7 +223,9 @@ describe API::CommitStatuses do end context 'when status is invalid' do - before { post api(post_url, developer), state: 'invalid' } + before do + post api(post_url, developer), state: 'invalid' + end it 'does not create commit status' do expect(response).to have_http_status(400) @@ -217,7 +233,9 @@ describe API::CommitStatuses do end context 'when request without a state made' do - before { post api(post_url, developer) } + before do + post api(post_url, developer) + end it 'does not create commit status' do expect(response).to have_http_status(400) @@ -226,7 +244,10 @@ describe API::CommitStatuses do context 'when commit SHA is invalid' do let(:sha) { 'invalid_sha' } - before { post api(post_url, developer), state: 'running' } + + before do + post api(post_url, developer), state: 'running' + end it 'returns not found error' do expect(response).to have_http_status(404) @@ -248,7 +269,9 @@ describe API::CommitStatuses do end context 'reporter user' do - before { post api(post_url, reporter), state: 'running' } + before do + post api(post_url, reporter), state: 'running' + end it 'does not create commit status' do expect(response).to have_http_status(403) @@ -256,7 +279,9 @@ describe API::CommitStatuses do end context 'guest user' do - before { post api(post_url, guest), state: 'running' } + before do + post api(post_url, guest), state: 'running' + end it 'does not create commit status' do expect(response).to have_http_status(403) @@ -264,7 +289,9 @@ describe API::CommitStatuses do end context 'unauthorized user' do - before { post api(post_url) } + before do + post api(post_url) + end it 'does not create commit status' do expect(response).to have_http_status(401) diff --git a/spec/requests/api/commits_spec.rb b/spec/requests/api/commits_spec.rb index b0c265b6453..0dad547735d 100644 --- a/spec/requests/api/commits_spec.rb +++ b/spec/requests/api/commits_spec.rb @@ -9,11 +9,15 @@ describe API::Commits do let!(:note) { create(:note_on_commit, author: user, project: project, commit_id: project.repository.commit.id, note: 'a comment on a commit') } let!(:another_note) { create(:note_on_commit, author: user, project: project, commit_id: project.repository.commit.id, note: 'another comment on a commit') } - before { project.team << [user, :reporter] } + before do + project.team << [user, :reporter] + end describe "List repository commits" do context "authorized user" do - before { project.team << [user2, :reporter] } + before do + project.team << [user2, :reporter] + end it "returns project commits" do commit = project.repository.commit @@ -514,7 +518,9 @@ describe API::Commits do describe "Get the diff of a commit" do context "authorized user" do - before { project.team << [user2, :reporter] } + before do + project.team << [user2, :reporter] + end it "returns the diff of the selected commit" do get api("/projects/#{project.id}/repository/commits/#{project.repository.commit.id}/diff", user) diff --git a/spec/requests/api/deploy_keys_spec.rb b/spec/requests/api/deploy_keys_spec.rb index 4d9cd5f3a27..9c260f88f56 100644 --- a/spec/requests/api/deploy_keys_spec.rb +++ b/spec/requests/api/deploy_keys_spec.rb @@ -41,7 +41,9 @@ describe API::DeployKeys do end describe 'GET /projects/:id/deploy_keys' do - before { deploy_key } + before do + deploy_key + end it 'returns array of ssh keys' do get api("/projects/#{project.id}/deploy_keys", admin) @@ -161,7 +163,9 @@ describe API::DeployKeys do end describe 'DELETE /projects/:id/deploy_keys/:key_id' do - before { deploy_key } + before do + deploy_key + end it 'deletes existing key' do expect do diff --git a/spec/requests/api/files_spec.rb b/spec/requests/api/files_spec.rb index d325c6eff9d..c5ec8be4f21 100644 --- a/spec/requests/api/files_spec.rb +++ b/spec/requests/api/files_spec.rb @@ -13,7 +13,9 @@ describe API::Files do let(:author_email) { 'user@example.org' } let(:author_name) { 'John Doe' } - before { project.team << [user, :developer] } + before do + project.team << [user, :developer] + end def route(file_path = nil) "/projects/#{project.id}/repository/files/#{file_path}" diff --git a/spec/requests/api/helpers_spec.rb b/spec/requests/api/helpers_spec.rb index ed392acc607..191c60aba31 100644 --- a/spec/requests/api/helpers_spec.rb +++ b/spec/requests/api/helpers_spec.rb @@ -55,40 +55,62 @@ describe API::Helpers do subject { current_user } describe "Warden authentication" do - before { doorkeeper_guard_returns false } + before do + doorkeeper_guard_returns false + end context "with invalid credentials" do context "GET request" do - before { env['REQUEST_METHOD'] = 'GET' } + before do + env['REQUEST_METHOD'] = 'GET' + end + it { is_expected.to be_nil } end end context "with valid credentials" do - before { warden_authenticate_returns user } + before do + warden_authenticate_returns user + end context "GET request" do - before { env['REQUEST_METHOD'] = 'GET' } + before do + env['REQUEST_METHOD'] = 'GET' + end + it { is_expected.to eq(user) } end context "HEAD request" do - before { env['REQUEST_METHOD'] = 'HEAD' } + before do + env['REQUEST_METHOD'] = 'HEAD' + end + it { is_expected.to eq(user) } end context "PUT request" do - before { env['REQUEST_METHOD'] = 'PUT' } + before do + env['REQUEST_METHOD'] = 'PUT' + end + it { is_expected.to be_nil } end context "POST request" do - before { env['REQUEST_METHOD'] = 'POST' } + before do + env['REQUEST_METHOD'] = 'POST' + end + it { is_expected.to be_nil } end context "DELETE request" do - before { env['REQUEST_METHOD'] = 'DELETE' } + before do + env['REQUEST_METHOD'] = 'DELETE' + end + it { is_expected.to be_nil } end end diff --git a/spec/requests/api/jobs_spec.rb b/spec/requests/api/jobs_spec.rb index e5e5872dc1f..8d647eb1c7e 100644 --- a/spec/requests/api/jobs_spec.rb +++ b/spec/requests/api/jobs_spec.rb @@ -11,7 +11,7 @@ describe API::Jobs, :api do ref: project.default_branch) end - let!(:build) { create(:ci_build, pipeline: pipeline) } + let!(:job) { create(:ci_build, pipeline: pipeline) } let(:user) { create(:user) } let(:api_user) { user } @@ -42,13 +42,13 @@ describe API::Jobs, :api do end it 'returns pipeline data' do - json_build = json_response.first + json_job = json_response.first - expect(json_build['pipeline']).not_to be_empty - expect(json_build['pipeline']['id']).to eq build.pipeline.id - expect(json_build['pipeline']['ref']).to eq build.pipeline.ref - expect(json_build['pipeline']['sha']).to eq build.pipeline.sha - expect(json_build['pipeline']['status']).to eq build.pipeline.status + expect(json_job['pipeline']).not_to be_empty + expect(json_job['pipeline']['id']).to eq job.pipeline.id + expect(json_job['pipeline']['ref']).to eq job.pipeline.ref + expect(json_job['pipeline']['sha']).to eq job.pipeline.sha + expect(json_job['pipeline']['status']).to eq job.pipeline.status end context 'filter project with one scope element' do @@ -79,7 +79,7 @@ describe API::Jobs, :api do context 'unauthorized user' do let(:api_user) { nil } - it 'does not return project builds' do + it 'does not return project jobs' do expect(response).to have_http_status(401) end end @@ -105,13 +105,13 @@ describe API::Jobs, :api do end it 'returns pipeline data' do - json_build = json_response.first + json_job = json_response.first - expect(json_build['pipeline']).not_to be_empty - expect(json_build['pipeline']['id']).to eq build.pipeline.id - expect(json_build['pipeline']['ref']).to eq build.pipeline.ref - expect(json_build['pipeline']['sha']).to eq build.pipeline.sha - expect(json_build['pipeline']['status']).to eq build.pipeline.status + expect(json_job['pipeline']).not_to be_empty + expect(json_job['pipeline']['id']).to eq job.pipeline.id + expect(json_job['pipeline']['ref']).to eq job.pipeline.ref + expect(json_job['pipeline']['sha']).to eq job.pipeline.sha + expect(json_job['pipeline']['status']).to eq job.pipeline.status end context 'filter jobs with one scope element' do @@ -140,7 +140,7 @@ describe API::Jobs, :api do context 'jobs in different pipelines' do let!(:pipeline2) { create(:ci_empty_pipeline, project: project) } - let!(:build2) { create(:ci_build, pipeline: pipeline2) } + let!(:job2) { create(:ci_build, pipeline: pipeline2) } it 'excludes jobs from other pipelines' do json_response.each { |job| expect(job['pipeline']['id']).to eq(pipeline.id) } @@ -159,7 +159,7 @@ describe API::Jobs, :api do describe 'GET /projects/:id/jobs/:job_id' do before do - get api("/projects/#{project.id}/jobs/#{build.id}", api_user) + get api("/projects/#{project.id}/jobs/#{job.id}", api_user) end context 'authorized user' do @@ -169,12 +169,13 @@ describe API::Jobs, :api do end it 'returns pipeline data' do - json_build = json_response - expect(json_build['pipeline']).not_to be_empty - expect(json_build['pipeline']['id']).to eq build.pipeline.id - expect(json_build['pipeline']['ref']).to eq build.pipeline.ref - expect(json_build['pipeline']['sha']).to eq build.pipeline.sha - expect(json_build['pipeline']['status']).to eq build.pipeline.status + json_job = json_response + + expect(json_job['pipeline']).not_to be_empty + expect(json_job['pipeline']['id']).to eq job.pipeline.id + expect(json_job['pipeline']['ref']).to eq job.pipeline.ref + expect(json_job['pipeline']['sha']).to eq job.pipeline.sha + expect(json_job['pipeline']['status']).to eq job.pipeline.status end end @@ -189,11 +190,11 @@ describe API::Jobs, :api do describe 'GET /projects/:id/jobs/:job_id/artifacts' do before do - get api("/projects/#{project.id}/jobs/#{build.id}/artifacts", api_user) + get api("/projects/#{project.id}/jobs/#{job.id}/artifacts", api_user) end context 'job with artifacts' do - let(:build) { create(:ci_build, :artifacts, pipeline: pipeline) } + let(:job) { create(:ci_build, :artifacts, pipeline: pipeline) } context 'authorized user' do let(:download_headers) do @@ -204,7 +205,7 @@ describe API::Jobs, :api do it 'returns specific job artifacts' do expect(response).to have_http_status(200) expect(response.headers).to include(download_headers) - expect(response.body).to match_file(build.artifacts_file.file.file) + expect(response.body).to match_file(job.artifacts_file.file.file) end end @@ -224,14 +225,14 @@ describe API::Jobs, :api do describe 'GET /projects/:id/artifacts/:ref_name/download?job=name' do let(:api_user) { reporter } - let(:build) { create(:ci_build, :artifacts, pipeline: pipeline) } + let(:job) { create(:ci_build, :artifacts, pipeline: pipeline) } before do - build.success + job.success end - def get_for_ref(ref = pipeline.ref, job = build.name) - get api("/projects/#{project.id}/jobs/artifacts/#{ref}/download", api_user), job: job + def get_for_ref(ref = pipeline.ref, job_name = job.name) + get api("/projects/#{project.id}/jobs/artifacts/#{ref}/download", api_user), job: job_name end context 'when not logged in' do @@ -285,7 +286,7 @@ describe API::Jobs, :api do let(:download_headers) do { 'Content-Transfer-Encoding' => 'binary', 'Content-Disposition' => - "attachment; filename=#{build.artifacts_file.filename}" } + "attachment; filename=#{job.artifacts_file.filename}" } end it { expect(response).to have_http_status(200) } @@ -321,16 +322,16 @@ describe API::Jobs, :api do end describe 'GET /projects/:id/jobs/:job_id/trace' do - let(:build) { create(:ci_build, :trace, pipeline: pipeline) } + let(:job) { create(:ci_build, :trace, pipeline: pipeline) } before do - get api("/projects/#{project.id}/jobs/#{build.id}/trace", api_user) + get api("/projects/#{project.id}/jobs/#{job.id}/trace", api_user) end context 'authorized user' do it 'returns specific job trace' do expect(response).to have_http_status(200) - expect(response.body).to eq(build.trace.raw) + expect(response.body).to eq(job.trace.raw) end end @@ -345,7 +346,7 @@ describe API::Jobs, :api do describe 'POST /projects/:id/jobs/:job_id/cancel' do before do - post api("/projects/#{project.id}/jobs/#{build.id}/cancel", api_user) + post api("/projects/#{project.id}/jobs/#{job.id}/cancel", api_user) end context 'authorized user' do @@ -375,10 +376,10 @@ describe API::Jobs, :api do end describe 'POST /projects/:id/jobs/:job_id/retry' do - let(:build) { create(:ci_build, :canceled, pipeline: pipeline) } + let(:job) { create(:ci_build, :canceled, pipeline: pipeline) } before do - post api("/projects/#{project.id}/jobs/#{build.id}/retry", api_user) + post api("/projects/#{project.id}/jobs/#{job.id}/retry", api_user) end context 'authorized user' do @@ -410,28 +411,29 @@ describe API::Jobs, :api do describe 'POST /projects/:id/jobs/:job_id/erase' do before do - post api("/projects/#{project.id}/jobs/#{build.id}/erase", user) + post api("/projects/#{project.id}/jobs/#{job.id}/erase", user) end context 'job is erasable' do - let(:build) { create(:ci_build, :trace, :artifacts, :success, project: project, pipeline: pipeline) } + let(:job) { create(:ci_build, :trace, :artifacts, :success, project: project, pipeline: pipeline) } it 'erases job content' do expect(response).to have_http_status(201) - expect(build).not_to have_trace - expect(build.artifacts_file.exists?).to be_falsy - expect(build.artifacts_metadata.exists?).to be_falsy + expect(job).not_to have_trace + expect(job.artifacts_file.exists?).to be_falsy + expect(job.artifacts_metadata.exists?).to be_falsy end it 'updates job' do - build.reload - expect(build.erased_at).to be_truthy - expect(build.erased_by).to eq(user) + job.reload + + expect(job.erased_at).to be_truthy + expect(job.erased_by).to eq(user) end end context 'job is not erasable' do - let(:build) { create(:ci_build, :trace, project: project, pipeline: pipeline) } + let(:job) { create(:ci_build, :trace, project: project, pipeline: pipeline) } it 'responds with forbidden' do expect(response).to have_http_status(403) @@ -439,25 +441,25 @@ describe API::Jobs, :api do end end - describe 'POST /projects/:id/jobs/:build_id/artifacts/keep' do + describe 'POST /projects/:id/jobs/:job_id/artifacts/keep' do before do - post api("/projects/#{project.id}/jobs/#{build.id}/artifacts/keep", user) + post api("/projects/#{project.id}/jobs/#{job.id}/artifacts/keep", user) end context 'artifacts did not expire' do - let(:build) do + let(:job) do create(:ci_build, :trace, :artifacts, :success, project: project, pipeline: pipeline, artifacts_expire_at: Time.now + 7.days) end it 'keeps artifacts' do expect(response).to have_http_status(200) - expect(build.reload.artifacts_expire_at).to be_nil + expect(job.reload.artifacts_expire_at).to be_nil end end context 'no artifacts' do - let(:build) { create(:ci_build, project: project, pipeline: pipeline) } + let(:job) { create(:ci_build, project: project, pipeline: pipeline) } it 'responds with not found' do expect(response).to have_http_status(404) @@ -467,18 +469,18 @@ describe API::Jobs, :api do describe 'POST /projects/:id/jobs/:job_id/play' do before do - post api("/projects/#{project.id}/jobs/#{build.id}/play", api_user) + post api("/projects/#{project.id}/jobs/#{job.id}/play", api_user) end context 'on an playable job' do - let(:build) { create(:ci_build, :manual, project: project, pipeline: pipeline) } + let(:job) { create(:ci_build, :manual, project: project, pipeline: pipeline) } context 'when user is authorized to trigger a manual action' do it 'plays the job' do expect(response).to have_http_status(200) expect(json_response['user']['id']).to eq(user.id) - expect(json_response['id']).to eq(build.id) - expect(build.reload).to be_pending + expect(json_response['id']).to eq(job.id) + expect(job.reload).to be_pending end end @@ -487,7 +489,7 @@ describe API::Jobs, :api do let(:api_user) { create(:user) } it 'does not trigger a manual action' do - expect(build.reload).to be_manual + expect(job.reload).to be_manual expect(response).to have_http_status(404) end end @@ -496,7 +498,7 @@ describe API::Jobs, :api do let(:api_user) { reporter } it 'does not trigger a manual action' do - expect(build.reload).to be_manual + expect(job.reload).to be_manual expect(response).to have_http_status(403) end end diff --git a/spec/requests/api/keys_spec.rb b/spec/requests/api/keys_spec.rb index ab957c72984..f534332ca6c 100644 --- a/spec/requests/api/keys_spec.rb +++ b/spec/requests/api/keys_spec.rb @@ -4,11 +4,9 @@ describe API::Keys do let(:user) { create(:user) } let(:admin) { create(:admin) } let(:key) { create(:key, user: user) } - let(:email) { create(:email, user: user) } + let(:email) { create(:email, user: user) } describe 'GET /keys/:uid' do - before { admin } - context 'when unauthenticated' do it 'returns authentication error' do get api("/keys/#{key.id}") diff --git a/spec/requests/api/labels_spec.rb b/spec/requests/api/labels_spec.rb index 0c6b55c1630..f7e2f1908bb 100644 --- a/spec/requests/api/labels_spec.rb +++ b/spec/requests/api/labels_spec.rb @@ -339,7 +339,9 @@ describe API::Labels do end context "when user is already subscribed to label" do - before { label1.subscribe(user, project) } + before do + label1.subscribe(user, project) + end it "returns 304" do post api("/projects/#{project.id}/labels/#{label1.id}/subscribe", user) @@ -358,7 +360,9 @@ describe API::Labels do end describe "POST /projects/:id/labels/:label_id/unsubscribe" do - before { label1.subscribe(user, project) } + before do + label1.subscribe(user, project) + end context "when label_id is a label title" do it "unsubscribes from the label" do @@ -381,7 +385,9 @@ describe API::Labels do end context "when user is already unsubscribed from label" do - before { label1.unsubscribe(user, project) } + before do + label1.unsubscribe(user, project) + end it "returns 304" do post api("/projects/#{project.id}/labels/#{label1.id}/unsubscribe", user) diff --git a/spec/requests/api/milestones_spec.rb b/spec/requests/api/milestones_spec.rb index dd74351a2b1..40934c25afc 100644 --- a/spec/requests/api/milestones_spec.rb +++ b/spec/requests/api/milestones_spec.rb @@ -6,7 +6,9 @@ describe API::Milestones do let!(:closed_milestone) { create(:closed_milestone, project: project, title: 'version1', description: 'closed milestone') } let!(:milestone) { create(:milestone, project: project, title: 'version2', description: 'open milestone') } - before { project.team << [user, :developer] } + before do + project.team << [user, :developer] + end describe 'GET /projects/:id/milestones' do it 'returns project milestones' do diff --git a/spec/requests/api/notes_spec.rb b/spec/requests/api/notes_spec.rb index 6afcd237c3c..03f2b5950ee 100644 --- a/spec/requests/api/notes_spec.rb +++ b/spec/requests/api/notes_spec.rb @@ -28,7 +28,9 @@ describe API::Notes do system: true end - before { project.team << [user, :reporter] } + before do + project.team << [user, :reporter] + end describe "GET /projects/:id/noteable/:noteable_id/notes" do context "when noteable is an Issue" do @@ -58,7 +60,9 @@ describe API::Notes do end context "and issue is confidential" do - before { ext_issue.update_attributes(confidential: true) } + before do + ext_issue.update_attributes(confidential: true) + end it "returns 404" do get api("/projects/#{ext_proj.id}/issues/#{ext_issue.iid}/notes", user) @@ -150,7 +154,9 @@ describe API::Notes do end context "when issue is confidential" do - before { issue.update_attributes(confidential: true) } + before do + issue.update_attributes(confidential: true) + end it "returns 404" do get api("/projects/#{project.id}/issues/#{issue.iid}/notes/#{issue_note.id}", private_user) diff --git a/spec/requests/api/pipelines_spec.rb b/spec/requests/api/pipelines_spec.rb index 9e6957e9922..258085e503f 100644 --- a/spec/requests/api/pipelines_spec.rb +++ b/spec/requests/api/pipelines_spec.rb @@ -10,7 +10,9 @@ describe API::Pipelines do ref: project.default_branch, user: user) end - before { project.team << [user, :master] } + before do + project.team << [user, :master] + end describe 'GET /projects/:id/pipelines ' do context 'authorized user' do @@ -285,7 +287,9 @@ describe API::Pipelines do describe 'POST /projects/:id/pipeline ' do context 'authorized user' do context 'with gitlab-ci.yml' do - before { stub_ci_pipeline_to_return_yaml_file } + before do + stub_ci_pipeline_to_return_yaml_file + end it 'creates and returns a new pipeline' do expect do @@ -419,7 +423,9 @@ describe API::Pipelines do context 'user without proper access rights' do let!(:reporter) { create(:user) } - before { project.team << [reporter, :reporter] } + before do + project.team << [reporter, :reporter] + end it 'rejects the action' do post api("/projects/#{project.id}/pipelines/#{pipeline.id}/cancel", reporter) diff --git a/spec/requests/api/projects_spec.rb b/spec/requests/api/projects_spec.rb index 3e831373514..d92262a4c99 100644 --- a/spec/requests/api/projects_spec.rb +++ b/spec/requests/api/projects_spec.rb @@ -476,8 +476,9 @@ describe API::Projects do end describe 'POST /projects/user/:id' do - before { project } - before { admin } + before do + expect(project).to be_persisted + end it 'creates new project without path but with name and return 201' do expect { post api("/projects/user/#{user.id}", admin), name: 'Foo Project' }.to change {Project.count}.by(1) @@ -581,7 +582,9 @@ describe API::Projects do end describe "POST /projects/:id/uploads" do - before { project } + before do + project + end it "uploads the file and returns its info" do post api("/projects/#{project.id}/uploads", user), file: fixture_file_upload(Rails.root + "spec/fixtures/dk.png", "image/png") @@ -729,7 +732,9 @@ describe API::Projects do describe 'permissions' do context 'all projects' do - before { project.team << [user, :master] } + before do + project.team << [user, :master] + end it 'contains permission information' do get api("/projects", user) @@ -756,7 +761,9 @@ describe API::Projects do context 'group project' do let(:project2) { create(:empty_project, group: create(:group)) } - before { project2.group.add_owner(user) } + before do + project2.group.add_owner(user) + end it 'sets the owner and return 200' do get api("/projects/#{project2.id}", user) @@ -822,7 +829,9 @@ describe API::Projects do end describe 'GET /projects/:id/snippets' do - before { snippet } + before do + snippet + end it 'returns an array of project snippets' do get api("/projects/#{project.id}/snippets", user) @@ -879,7 +888,9 @@ describe API::Projects do end describe 'DELETE /projects/:id/snippets/:snippet_id' do - before { snippet } + before do + snippet + end it 'deletes existing project snippet' do expect do @@ -1074,14 +1085,16 @@ describe API::Projects do end describe 'PUT /projects/:id' do - before { project } - before { user } - before { user3 } - before { user4 } - before { project3 } - before { project4 } - before { project_member2 } - before { project_member } + before do + expect(project).to be_persisted + expect(user).to be_persisted + expect(user3).to be_persisted + expect(user4).to be_persisted + expect(project3).to be_persisted + expect(project4).to be_persisted + expect(project_member2).to be_persisted + expect(project_member).to be_persisted + end it 'returns 400 when nothing sent' do project_param = {} diff --git a/spec/requests/api/runner_spec.rb b/spec/requests/api/runner_spec.rb index 5a4f0513248..d554c242916 100644 --- a/spec/requests/api/runner_spec.rb +++ b/spec/requests/api/runner_spec.rb @@ -190,17 +190,23 @@ describe API::Runner do pipeline: pipeline, name: 'spinach', stage: 'test', stage_idx: 0, commands: "ls\ndate") end - before { project.runners << runner } + before do + project.runners << runner + end describe 'POST /api/v4/jobs/request' do let!(:last_update) {} let!(:new_update) { } let(:user_agent) { 'gitlab-runner 9.0.0 (9-0-stable; go1.7.4; linux/amd64)' } - before { stub_container_registry_config(enabled: false) } + before do + stub_container_registry_config(enabled: false) + end shared_examples 'no jobs available' do - before { request_job } + before do + request_job + end context 'when runner sends version in User-Agent' do context 'for stable version' do @@ -277,7 +283,9 @@ describe API::Runner do end context 'when jobs are finished' do - before { job.success } + before do + job.success + end it_behaves_like 'no jobs available' end @@ -508,10 +516,14 @@ describe API::Runner do end context 'when job has no tags' do - before { job.update(tags: []) } + before do + job.update(tags: []) + end context 'when runner is allowed to pick untagged jobs' do - before { runner.update_column(:run_untagged, true) } + before do + runner.update_column(:run_untagged, true) + end it 'picks job' do request_job @@ -521,7 +533,9 @@ describe API::Runner do end context 'when runner is not allowed to pick untagged jobs' do - before { runner.update_column(:run_untagged, false) } + before do + runner.update_column(:run_untagged, false) + end it_behaves_like 'no jobs available' end @@ -561,7 +575,9 @@ describe API::Runner do end context 'when registry is enabled' do - before { stub_container_registry_config(enabled: true, host_port: registry_url) } + before do + stub_container_registry_config(enabled: true, host_port: registry_url) + end it 'sends registry credentials key' do request_job @@ -572,7 +588,9 @@ describe API::Runner do end context 'when registry is disabled' do - before { stub_container_registry_config(enabled: false, host_port: registry_url) } + before do + stub_container_registry_config(enabled: false, host_port: registry_url) + end it 'does not send registry credentials' do request_job @@ -594,7 +612,9 @@ describe API::Runner do describe 'PUT /api/v4/jobs/:id' do let(:job) { create(:ci_build, :pending, :trace, pipeline: pipeline, runner_id: runner.id) } - before { job.run! } + before do + job.run! + end context 'when status is given' do it 'mark job as succeeded' do @@ -649,7 +669,9 @@ describe API::Runner do let(:headers_with_range) { headers.merge({ 'Content-Range' => '11-20' }) } let(:update_interval) { 10.seconds.to_i } - before { initial_patch_the_trace } + before do + initial_patch_the_trace + end context 'when request is valid' do it 'gets correct response' do @@ -791,7 +813,9 @@ describe API::Runner do let(:file_upload) { fixture_file_upload(Rails.root + 'spec/fixtures/banana_sample.gif', 'image/gif') } let(:file_upload2) { fixture_file_upload(Rails.root + 'spec/fixtures/dk.png', 'image/gif') } - before { job.run! } + before do + job.run! + end describe 'POST /api/v4/jobs/:id/artifacts/authorize' do context 'when using token as parameter' do @@ -897,13 +921,17 @@ describe API::Runner do end context 'when uses regular file post' do - before { upload_artifacts(file_upload, headers_with_token, false) } + before do + upload_artifacts(file_upload, headers_with_token, false) + end it_behaves_like 'successful artifacts upload' end context 'when uses accelerated file post' do - before { upload_artifacts(file_upload, headers_with_token, true) } + before do + upload_artifacts(file_upload, headers_with_token, true) + end it_behaves_like 'successful artifacts upload' end @@ -1057,7 +1085,9 @@ describe API::Runner do allow(ArtifactUploader).to receive(:artifacts_upload_path).and_return(@tmpdir) end - after { FileUtils.remove_entry @tmpdir } + after do + FileUtils.remove_entry @tmpdir + end it' "fails to post artifacts for outside of tmp path"' do upload_artifacts(file_upload, headers_with_token) @@ -1079,7 +1109,9 @@ describe API::Runner do describe 'GET /api/v4/jobs/:id/artifacts' do let(:token) { job.token } - before { download_artifact } + before do + download_artifact + end context 'when job has artifacts' do let(:job) { create(:ci_build, :artifacts) } diff --git a/spec/requests/api/settings_spec.rb b/spec/requests/api/settings_spec.rb index 2398ae6219c..ede48b1c888 100644 --- a/spec/requests/api/settings_spec.rb +++ b/spec/requests/api/settings_spec.rb @@ -40,7 +40,10 @@ describe API::Settings, 'Settings' do plantuml_url: 'http://plantuml.example.com', default_snippet_visibility: 'internal', restricted_visibility_levels: ['public'], - default_artifacts_expire_in: '2 days' + default_artifacts_expire_in: '2 days', + help_page_text: 'custom help text', + help_page_hide_commercial_content: true, + help_page_support_url: 'http://example.com/help' expect(response).to have_http_status(200) expect(json_response['default_projects_limit']).to eq(3) expect(json_response['signin_enabled']).to be_falsey @@ -53,6 +56,9 @@ describe API::Settings, 'Settings' do expect(json_response['default_snippet_visibility']).to eq('internal') expect(json_response['restricted_visibility_levels']).to eq(['public']) expect(json_response['default_artifacts_expire_in']).to eq('2 days') + expect(json_response['help_page_text']).to eq('custom help text') + expect(json_response['help_page_hide_commercial_content']).to be_truthy + expect(json_response['help_page_support_url']).to eq('http://example.com/help') end end diff --git a/spec/requests/api/system_hooks_spec.rb b/spec/requests/api/system_hooks_spec.rb index 2eb191d6049..f65b475fe44 100644 --- a/spec/requests/api/system_hooks_spec.rb +++ b/spec/requests/api/system_hooks_spec.rb @@ -5,7 +5,9 @@ describe API::SystemHooks do let(:admin) { create(:admin) } let!(:hook) { create(:system_hook, url: "http://example.com") } - before { stub_request(:post, hook.url) } + before do + stub_request(:post, hook.url) + end describe "GET /hooks" do context "when no user" do diff --git a/spec/requests/api/templates_spec.rb b/spec/requests/api/templates_spec.rb index cb55985e3f5..f8af9295842 100644 --- a/spec/requests/api/templates_spec.rb +++ b/spec/requests/api/templates_spec.rb @@ -2,14 +2,18 @@ require 'spec_helper' describe API::Templates do context 'the Template Entity' do - before { get api('/templates/gitignores/Ruby') } + before do + get api('/templates/gitignores/Ruby') + end it { expect(json_response['name']).to eq('Ruby') } it { expect(json_response['content']).to include('*.gem') } end context 'the TemplateList Entity' do - before { get api('/templates/gitignores') } + before do + get api('/templates/gitignores') + end it { expect(json_response.first['name']).not_to be_nil } it { expect(json_response.first['content']).to be_nil } @@ -47,7 +51,9 @@ describe API::Templates do end context 'the License Template Entity' do - before { get api('/templates/licenses/mit') } + before do + get api('/templates/licenses/mit') + end it 'returns a license template' do expect(json_response['key']).to eq('mit') diff --git a/spec/requests/api/users_spec.rb b/spec/requests/api/users_spec.rb index ec51b96c86b..9dc4b6972a6 100644 --- a/spec/requests/api/users_spec.rb +++ b/spec/requests/api/users_spec.rb @@ -160,7 +160,9 @@ describe API::Users do end describe "POST /users" do - before { admin } + before do + admin + end it "creates user" do expect do @@ -349,7 +351,9 @@ describe API::Users do describe "PUT /users/:id" do let!(:admin_user) { create(:admin) } - before { admin } + before do + admin + end it "updates user with new bio" do put api("/users/#{user.id}", admin), { bio: 'new test bio' } @@ -502,7 +506,9 @@ describe API::Users do end describe "POST /users/:id/keys" do - before { admin } + before do + admin + end it "does not create invalid ssh key" do post api("/users/#{user.id}/keys", admin), { title: "invalid key" } @@ -532,7 +538,9 @@ describe API::Users do end describe 'GET /user/:id/keys' do - before { admin } + before do + admin + end context 'when unauthenticated' do it 'returns authentication error' do @@ -563,7 +571,9 @@ describe API::Users do end describe 'DELETE /user/:id/keys/:key_id' do - before { admin } + before do + admin + end context 'when unauthenticated' do it 'returns authentication error' do @@ -601,7 +611,9 @@ describe API::Users do end describe "POST /users/:id/emails" do - before { admin } + before do + admin + end it "does not create invalid email" do post api("/users/#{user.id}/emails", admin), {} @@ -625,7 +637,9 @@ describe API::Users do end describe 'GET /user/:id/emails' do - before { admin } + before do + admin + end context 'when unauthenticated' do it 'returns authentication error' do @@ -662,7 +676,9 @@ describe API::Users do end describe 'DELETE /user/:id/emails/:email_id' do - before { admin } + before do + admin + end context 'when unauthenticated' do it 'returns authentication error' do @@ -708,7 +724,10 @@ describe API::Users do describe "DELETE /users/:id" do let!(:namespace) { user.namespace } let!(:issue) { create(:issue, author: user) } - before { admin } + + before do + admin + end it "deletes user" do Sidekiq::Testing.inline! { delete api("/users/#{user.id}", admin) } @@ -1068,7 +1087,10 @@ describe API::Users do end describe 'POST /users/:id/block' do - before { admin } + before do + admin + end + it 'blocks existing user' do post api("/users/#{user.id}/block", admin) expect(response).to have_http_status(201) @@ -1096,7 +1118,10 @@ describe API::Users do describe 'POST /users/:id/unblock' do let(:blocked_user) { create(:user, state: 'blocked') } - before { admin } + + before do + admin + end it 'unblocks existing user' do post api("/users/#{user.id}/unblock", admin) diff --git a/spec/requests/ci/api/builds_spec.rb b/spec/requests/ci/api/builds_spec.rb index 04cc7708858..83c675792f4 100644 --- a/spec/requests/ci/api/builds_spec.rb +++ b/spec/requests/ci/api/builds_spec.rb @@ -241,7 +241,9 @@ describe Ci::API::Builds do end context 'when runner is allowed to pick untagged builds' do - before { runner.update_column(:run_untagged, true) } + before do + runner.update_column(:run_untagged, true) + end it 'picks build' do register_builds @@ -467,7 +469,9 @@ describe Ci::API::Builds do let(:token) { build.token } let(:headers_with_token) { headers.merge(Ci::API::Helpers::BUILD_TOKEN_HEADER => token) } - before { build.run! } + before do + build.run! + end describe "POST /builds/:id/artifacts/authorize" do context "authorizes posting artifact to running build" do @@ -523,7 +527,9 @@ describe Ci::API::Builds do end context 'authorization token is invalid' do - before { post authorize_url, { token: 'invalid', filesize: 100 } } + before do + post authorize_url, { token: 'invalid', filesize: 100 } + end it 'responds with forbidden' do expect(response).to have_http_status(403) diff --git a/spec/requests/ci/api/runners_spec.rb b/spec/requests/ci/api/runners_spec.rb index 0b9733221d8..78b2be350cd 100644 --- a/spec/requests/ci/api/runners_spec.rb +++ b/spec/requests/ci/api/runners_spec.rb @@ -12,7 +12,9 @@ describe Ci::API::Runners do describe "POST /runners/register" do context 'when runner token is provided' do - before { post ci_api("/runners/register"), token: registration_token } + before do + post ci_api("/runners/register"), token: registration_token + end it 'creates runner with default values' do expect(response).to have_http_status 201 @@ -69,7 +71,10 @@ describe Ci::API::Runners do context 'when project token is provided' do let(:project) { FactoryGirl.create(:empty_project) } - before { post ci_api("/runners/register"), token: project.runners_token } + + before do + post ci_api("/runners/register"), token: project.runners_token + end it 'creates runner' do expect(response).to have_http_status 201 diff --git a/spec/requests/git_http_spec.rb b/spec/requests/git_http_spec.rb index 6a83024d0d5..dce78faefc9 100644 --- a/spec/requests/git_http_spec.rb +++ b/spec/requests/git_http_spec.rb @@ -627,7 +627,9 @@ describe 'Git HTTP requests', lib: true do let(:path) { "/#{project.path_with_namespace}/info/refs" } context "when no params are added" do - before { get path } + before do + get path + end it "redirects to the .git suffix version" do expect(response).to redirect_to("/#{project.path_with_namespace}.git/info/refs") @@ -636,7 +638,10 @@ describe 'Git HTTP requests', lib: true do context "when the upload-pack service is requested" do let(:params) { { service: 'git-upload-pack' } } - before { get path, params } + + before do + get path, params + end it "redirects to the .git suffix version" do expect(response).to redirect_to("/#{project.path_with_namespace}.git/info/refs?service=#{params[:service]}") @@ -645,7 +650,10 @@ describe 'Git HTTP requests', lib: true do context "when the receive-pack service is requested" do let(:params) { { service: 'git-receive-pack' } } - before { get path, params } + + before do + get path, params + end it "redirects to the .git suffix version" do expect(response).to redirect_to("/#{project.path_with_namespace}.git/info/refs?service=#{params[:service]}") @@ -654,7 +662,10 @@ describe 'Git HTTP requests', lib: true do context "when the params are anything else" do let(:params) { { service: 'git-implode-pack' } } - before { get path, params } + + before do + get path, params + end it "redirects to the sign-in page" do expect(response).to redirect_to(new_user_session_path) @@ -695,7 +706,9 @@ describe 'Git HTTP requests', lib: true do end context "when the file does not exist" do - before { get "/#{project.path_with_namespace}/blob/master/info/refs" } + before do + get "/#{project.path_with_namespace}/blob/master/info/refs" + end it "returns not found" do expect(response).to have_http_status(:not_found) diff --git a/spec/requests/jwt_controller_spec.rb b/spec/requests/jwt_controller_spec.rb index 54d7cf5f10d..5e4cf05748e 100644 --- a/spec/requests/jwt_controller_spec.rb +++ b/spec/requests/jwt_controller_spec.rb @@ -6,7 +6,9 @@ describe JwtController do let(:service_name) { 'test' } let(:parameters) { { service: service_name } } - before { stub_const('JwtController::SERVICES', service_name => service_class) } + before do + stub_const('JwtController::SERVICES', service_name => service_class) + end context 'existing service' do subject! { get '/jwt/auth', parameters } diff --git a/spec/routing/project_routing_spec.rb b/spec/routing/project_routing_spec.rb index 0a6778ae2ef..95d40138fea 100644 --- a/spec/routing/project_routing_spec.rb +++ b/spec/routing/project_routing_spec.rb @@ -93,13 +93,17 @@ describe 'project routing' do end context 'name with dot' do - before { allow(Project).to receive(:find_by_full_path).with('gitlab/gitlabhq.keys', any_args).and_return(true) } + before do + allow(Project).to receive(:find_by_full_path).with('gitlab/gitlabhq.keys', any_args).and_return(true) + end it { expect(get('/gitlab/gitlabhq.keys')).to route_to('projects#show', namespace_id: 'gitlab', id: 'gitlabhq.keys') } end context 'with nested group' do - before { allow(Project).to receive(:find_by_full_path).with('gitlab/subgroup/gitlabhq', any_args).and_return(true) } + before do + allow(Project).to receive(:find_by_full_path).with('gitlab/subgroup/gitlabhq', any_args).and_return(true) + end it { expect(get('/gitlab/subgroup/gitlabhq')).to route_to('projects#show', namespace_id: 'gitlab/subgroup', id: 'gitlabhq') } end diff --git a/spec/routing/routing_spec.rb b/spec/routing/routing_spec.rb index a62af13cf0c..a45839b16f5 100644 --- a/spec/routing/routing_spec.rb +++ b/spec/routing/routing_spec.rb @@ -286,7 +286,9 @@ end describe "Groups", "routing" do let(:name) { 'complex.group-namegit' } - before { allow_any_instance_of(GroupUrlConstrainer).to receive(:matches?).and_return(true) } + before do + allow_any_instance_of(GroupUrlConstrainer).to receive(:matches?).and_return(true) + end it "to #show" do expect(get("/groups/#{name}")).to route_to('groups#show', id: name) diff --git a/spec/rubocop/cop/rspec/single_line_hook_spec.rb b/spec/rubocop/cop/rspec/single_line_hook_spec.rb new file mode 100644 index 00000000000..6cf0831d3ad --- /dev/null +++ b/spec/rubocop/cop/rspec/single_line_hook_spec.rb @@ -0,0 +1,66 @@ +require 'spec_helper' + +require 'rubocop' +require 'rubocop/rspec/support' + +require_relative '../../../../rubocop/cop/rspec/single_line_hook' + +describe RuboCop::Cop::RSpec::SingleLineHook do + include CopHelper + + subject(:cop) { described_class.new } + + # Override `CopHelper#inspect_source` to always appear to be in a spec file, + # so that our RSpec-only cop actually runs + def inspect_source(*args) + super(*args, 'foo_spec.rb') + end + + it 'registers an offense for a single-line `before` block' do + inspect_source(cop, 'before { do_something }') + + expect(cop.offenses.size).to eq(1) + expect(cop.offenses.map(&:line)).to eq([1]) + expect(cop.highlights).to eq(['before { do_something }']) + end + + it 'registers an offense for a single-line `after` block' do + inspect_source(cop, 'after(:each) { undo_something }') + + expect(cop.offenses.size).to eq(1) + expect(cop.offenses.map(&:line)).to eq([1]) + expect(cop.highlights).to eq(['after(:each) { undo_something }']) + end + + it 'registers an offense for a single-line `around` block' do + inspect_source(cop, 'around { |ex| do_something_else }') + + expect(cop.offenses.size).to eq(1) + expect(cop.offenses.map(&:line)).to eq([1]) + expect(cop.highlights).to eq(['around { |ex| do_something_else }']) + end + + it 'ignores a multi-line `before` block' do + inspect_source(cop, ['before do', + ' do_something', + 'end']) + + expect(cop.offenses.size).to eq(0) + end + + it 'ignores a multi-line `after` block' do + inspect_source(cop, ['after(:each) do', + ' undo_something', + 'end']) + + expect(cop.offenses.size).to eq(0) + end + + it 'ignores a multi-line `around` block' do + inspect_source(cop, ['around do |ex|', + ' do_something_else', + 'end']) + + expect(cop.offenses.size).to eq(0) + end +end diff --git a/spec/serializers/environment_serializer_spec.rb b/spec/serializers/environment_serializer_spec.rb index d2ad6c44702..4c52a00b442 100644 --- a/spec/serializers/environment_serializer_spec.rb +++ b/spec/serializers/environment_serializer_spec.rb @@ -62,7 +62,9 @@ describe EnvironmentSerializer do subject { serializer.represent(resource) } context 'when there is a single environment' do - before { create(:environment, name: 'staging') } + before do + create(:environment, name: 'staging') + end it 'represents one standalone environment' do expect(subject.count).to eq 1 @@ -138,7 +140,9 @@ describe EnvironmentSerializer do context 'when resource is paginatable relation' do context 'when there is a single environment object in relation' do - before { create(:environment) } + before do + create(:environment) + end it 'serializes environments' do expect(subject.first).to have_key :id @@ -146,7 +150,9 @@ describe EnvironmentSerializer do end context 'when multiple environment objects are serialized' do - before { create_list(:environment, 3) } + before do + create_list(:environment, 3) + end it 'serializes appropriate number of objects' do expect(subject.count).to be 2 diff --git a/spec/serializers/pipeline_details_entity_spec.rb b/spec/serializers/pipeline_details_entity_spec.rb index 5cb9b9945b6..d28dec9592a 100644 --- a/spec/serializers/pipeline_details_entity_spec.rb +++ b/spec/serializers/pipeline_details_entity_spec.rb @@ -51,7 +51,9 @@ describe PipelineDetailsEntity do end context 'user has ability to retry pipeline' do - before { project.team << [user, :developer] } + before do + project.team << [user, :developer] + end it 'retryable flag is true' do expect(subject[:flags][:retryable]).to eq true @@ -77,7 +79,9 @@ describe PipelineDetailsEntity do end context 'user has ability to cancel pipeline' do - before { project.add_developer(user) } + before do + project.add_developer(user) + end it 'cancelable flag is true' do expect(subject[:flags][:cancelable]).to eq true diff --git a/spec/serializers/pipeline_entity_spec.rb b/spec/serializers/pipeline_entity_spec.rb index a059c2cc736..46650f3a80d 100644 --- a/spec/serializers/pipeline_entity_spec.rb +++ b/spec/serializers/pipeline_entity_spec.rb @@ -51,7 +51,9 @@ describe PipelineEntity do end context 'user has ability to retry pipeline' do - before { project.team << [user, :developer] } + before do + project.team << [user, :developer] + end it 'contains retry path' do expect(subject[:retry_path]).to be_present @@ -77,7 +79,9 @@ describe PipelineEntity do end context 'user has ability to cancel pipeline' do - before { project.add_developer(user) } + before do + project.add_developer(user) + end it 'contains cancel path' do expect(subject[:cancel_path]).to be_present diff --git a/spec/serializers/pipeline_serializer_spec.rb b/spec/serializers/pipeline_serializer_spec.rb index 34b19fb9fc4..44813656aff 100644 --- a/spec/serializers/pipeline_serializer_spec.rb +++ b/spec/serializers/pipeline_serializer_spec.rb @@ -69,7 +69,9 @@ describe PipelineSerializer do let(:pagination) { { page: 1, per_page: 2 } } context 'when a single pipeline object is present in relation' do - before { create(:ci_empty_pipeline) } + before do + create(:ci_empty_pipeline) + end it 'serializes pipeline relation' do expect(subject.first).to have_key :id @@ -77,7 +79,9 @@ describe PipelineSerializer do end context 'when a multiple pipeline objects are being serialized' do - before { create_list(:ci_empty_pipeline, 3) } + before do + create_list(:ci_empty_pipeline, 3) + end it 'serializes appropriate number of objects' do expect(subject.count).to be 2 diff --git a/spec/services/auth/container_registry_authentication_service_spec.rb b/spec/services/auth/container_registry_authentication_service_spec.rb index e273dfe1552..60cb7a9440f 100644 --- a/spec/services/auth/container_registry_authentication_service_spec.rb +++ b/spec/services/auth/container_registry_authentication_service_spec.rb @@ -34,7 +34,9 @@ describe Auth::ContainerRegistryAuthenticationService, services: true do end context 'for changed configuration' do - before { stub_application_setting(container_registry_token_expire_delay: expire_delay) } + before do + stub_application_setting(container_registry_token_expire_delay: expire_delay) + end it { expect(expires_at).to be_within(2.seconds).of(Time.now + expire_delay.minutes) } end @@ -117,7 +119,9 @@ describe Auth::ContainerRegistryAuthenticationService, services: true do end context 'allow developer to push images' do - before { project.team << [current_user, :developer] } + before do + project.team << [current_user, :developer] + end let(:current_params) do { scope: "repository:#{project.path_with_namespace}:push" } @@ -128,7 +132,9 @@ describe Auth::ContainerRegistryAuthenticationService, services: true do end context 'allow reporter to pull images' do - before { project.team << [current_user, :reporter] } + before do + project.team << [current_user, :reporter] + end context 'when pulling from root level repository' do let(:current_params) do @@ -141,7 +147,9 @@ describe Auth::ContainerRegistryAuthenticationService, services: true do end context 'return a least of privileges' do - before { project.team << [current_user, :reporter] } + before do + project.team << [current_user, :reporter] + end let(:current_params) do { scope: "repository:#{project.path_with_namespace}:push,pull" } @@ -152,7 +160,9 @@ describe Auth::ContainerRegistryAuthenticationService, services: true do end context 'disallow guest to pull or push images' do - before { project.team << [current_user, :guest] } + before do + project.team << [current_user, :guest] + end let(:current_params) do { scope: "repository:#{project.path_with_namespace}:pull,push" } @@ -355,7 +365,9 @@ describe Auth::ContainerRegistryAuthenticationService, services: true do context 'for project without container registry' do let(:project) { create(:empty_project, :public, container_registry_enabled: false) } - before { project.update(container_registry_enabled: false) } + before do + project.update(container_registry_enabled: false) + end context 'disallow when pulling' do let(:current_params) do diff --git a/spec/services/ci/update_build_queue_service_spec.rb b/spec/services/ci/update_build_queue_service_spec.rb index c44e6b2a48b..efefa8e8eca 100644 --- a/spec/services/ci/update_build_queue_service_spec.rb +++ b/spec/services/ci/update_build_queue_service_spec.rb @@ -9,7 +9,9 @@ describe Ci::UpdateBuildQueueService, :services do let(:runner) { create(:ci_runner) } context 'when there are runner that can pick build' do - before { build.project.runners << runner } + before do + build.project.runners << runner + end it 'ticks runner queue value' do expect { subject.execute(build) } @@ -36,7 +38,9 @@ describe Ci::UpdateBuildQueueService, :services do end context 'when there are no runners that can pick build' do - before { build.tag_list = [:docker] } + before do + build.tag_list = [:docker] + end it 'does not tick runner queue value' do expect { subject.execute(build) } diff --git a/spec/services/create_deployment_service_spec.rb b/spec/services/create_deployment_service_spec.rb index 5398b5c3f7e..6cf4342ad4c 100644 --- a/spec/services/create_deployment_service_spec.rb +++ b/spec/services/create_deployment_service_spec.rb @@ -204,7 +204,9 @@ describe CreateDeploymentService, services: true do let(:merge_request) { create(:merge_request, target_branch: 'master', source_branch: 'feature', source_project: project) } context "while updating the 'first_deployed_to_production_at' time" do - before { merge_request.mark_as_merged } + before do + merge_request.mark_as_merged + end context "for merge requests merged before the current deploy" do it "sets the time if the deploy's environment is 'production'" do diff --git a/spec/services/groups/create_service_spec.rb b/spec/services/groups/create_service_spec.rb index bcb62429275..fbd9026640c 100644 --- a/spec/services/groups/create_service_spec.rb +++ b/spec/services/groups/create_service_spec.rb @@ -14,7 +14,9 @@ describe Groups::CreateService, '#execute', services: true do end context "cannot create group with restricted visibility level" do - before { allow_any_instance_of(ApplicationSetting).to receive(:restricted_visibility_levels).and_return([Gitlab::VisibilityLevel::PUBLIC]) } + before do + allow_any_instance_of(ApplicationSetting).to receive(:restricted_visibility_levels).and_return([Gitlab::VisibilityLevel::PUBLIC]) + end it { is_expected.not_to be_persisted } end @@ -25,7 +27,9 @@ describe Groups::CreateService, '#execute', services: true do let!(:service) { described_class.new(user, group_params.merge(parent_id: group.id)) } context 'as group owner' do - before { group.add_owner(user) } + before do + group.add_owner(user) + end it { is_expected.to be_persisted } end diff --git a/spec/services/issues/create_service_spec.rb b/spec/services/issues/create_service_spec.rb index dab1a3469f7..370bd352200 100644 --- a/spec/services/issues/create_service_spec.rb +++ b/spec/services/issues/create_service_spec.rb @@ -155,7 +155,9 @@ describe Issues::CreateService, services: true do context 'issue create service' do context 'assignees' do - before { project.team << [user, :master] } + before do + project.team << [user, :master] + end it 'removes assignee when user id is invalid' do opts = { title: 'Title', description: 'Description', assignee_ids: [-1] } diff --git a/spec/services/issues/move_service_spec.rb b/spec/services/issues/move_service_spec.rb index 9f8346d52bb..d1dd1466d95 100644 --- a/spec/services/issues/move_service_spec.rb +++ b/spec/services/issues/move_service_spec.rb @@ -251,12 +251,18 @@ describe Issues::MoveService, services: true do end context 'user is reporter only in new project' do - before { new_project.team << [user, :reporter] } + before do + new_project.team << [user, :reporter] + end + it { expect { move }.to raise_error(StandardError, /permissions/) } end context 'user is reporter only in old project' do - before { old_project.team << [user, :reporter] } + before do + old_project.team << [user, :reporter] + end + it { expect { move }.to raise_error(StandardError, /permissions/) } end diff --git a/spec/services/issues/update_service_spec.rb b/spec/services/issues/update_service_spec.rb index a78866a2c32..c26642f5015 100644 --- a/spec/services/issues/update_service_spec.rb +++ b/spec/services/issues/update_service_spec.rb @@ -295,7 +295,9 @@ describe Issues::UpdateService, services: true do end context 'when issue has the `label` label' do - before { issue.labels << label } + before do + issue.labels << label + end it 'does not send notifications for existing labels' do opts = { label_ids: [label.id, label2.id] } @@ -329,7 +331,9 @@ describe Issues::UpdateService, services: true do it { expect(issue.tasks?).to eq(true) } context 'when tasks are marked as completed' do - before { update_issue(description: "- [x] Task 1\n- [X] Task 2") } + before do + update_issue(description: "- [x] Task 1\n- [X] Task 2") + end it 'creates system note about task status change' do note1 = find_note('marked the task **Task 1** as completed') @@ -417,7 +421,9 @@ describe Issues::UpdateService, services: true do context 'when remove_label_ids and label_ids are passed' do let(:params) { { label_ids: [], remove_label_ids: [label.id] } } - before { issue.update_attributes(labels: [label, label3]) } + before do + issue.update_attributes(labels: [label, label3]) + end it 'ignores the label_ids parameter' do expect(result.label_ids).not_to be_empty @@ -431,7 +437,9 @@ describe Issues::UpdateService, services: true do context 'when add_label_ids and remove_label_ids are passed' do let(:params) { { add_label_ids: [label3.id], remove_label_ids: [label.id] } } - before { issue.update_attributes(labels: [label]) } + before do + issue.update_attributes(labels: [label]) + end it 'adds the passed labels' do expect(result.label_ids).to include(label3.id) diff --git a/spec/services/members/create_service_spec.rb b/spec/services/members/create_service_spec.rb index 5ce8e17976b..5a05ab3ea50 100644 --- a/spec/services/members/create_service_spec.rb +++ b/spec/services/members/create_service_spec.rb @@ -5,7 +5,9 @@ describe Members::CreateService, services: true do let(:user) { create(:user) } let(:project_user) { create(:user) } - before { project.team << [user, :master] } + before do + project.team << [user, :master] + end it 'adds user to members' do params = { user_ids: project_user.id.to_s, access_level: Gitlab::Access::GUEST } diff --git a/spec/services/merge_requests/build_service_spec.rb b/spec/services/merge_requests/build_service_spec.rb index 6f9d1208b1d..01ef52396d7 100644 --- a/spec/services/merge_requests/build_service_spec.rb +++ b/spec/services/merge_requests/build_service_spec.rb @@ -206,7 +206,9 @@ describe MergeRequests::BuildService, services: true do context 'branch starts with external issue IID followed by a hyphen' do let(:source_branch) { '12345-fix-issue' } - before { allow(project).to receive(:default_issues_tracker?).and_return(false) } + before do + allow(project).to receive(:default_issues_tracker?).and_return(false) + end it 'sets the title to: Resolves External Issue $issue-iid' do expect(merge_request.title).to eq('Resolve External Issue 12345') diff --git a/spec/services/merge_requests/create_service_spec.rb b/spec/services/merge_requests/create_service_spec.rb index 2963f62cc7d..13fee953e41 100644 --- a/spec/services/merge_requests/create_service_spec.rb +++ b/spec/services/merge_requests/create_service_spec.rb @@ -150,7 +150,9 @@ describe MergeRequests::CreateService, services: true do context 'asssignee_id' do let(:assignee) { create(:user) } - before { project.team << [user, :master] } + before do + project.team << [user, :master] + end it 'removes assignee_id when user id is invalid' do opts = { title: 'Title', description: 'Description', assignee_id: -1 } diff --git a/spec/services/merge_requests/merge_service_spec.rb b/spec/services/merge_requests/merge_service_spec.rb index d96f819e66a..b3b188a805f 100644 --- a/spec/services/merge_requests/merge_service_spec.rb +++ b/spec/services/merge_requests/merge_service_spec.rb @@ -81,7 +81,9 @@ describe MergeRequests::MergeService, services: true do end context "when jira_issue_transition_id is not present" do - before { allow_any_instance_of(JIRA::Resource::Issue).to receive(:resolution).and_return(nil) } + before do + allow_any_instance_of(JIRA::Resource::Issue).to receive(:resolution).and_return(nil) + end it "does not close issue" do allow(jira_tracker).to receive_messages(jira_issue_transition_id: nil) diff --git a/spec/services/merge_requests/update_service_spec.rb b/spec/services/merge_requests/update_service_spec.rb index 091c193aaa6..fd46020bbdb 100644 --- a/spec/services/merge_requests/update_service_spec.rb +++ b/spec/services/merge_requests/update_service_spec.rb @@ -356,7 +356,9 @@ describe MergeRequests::UpdateService, services: true do end context 'when issue has the `label` label' do - before { merge_request.labels << label } + before do + merge_request.labels << label + end it 'does not send notifications for existing labels' do opts = { label_ids: [label.id, label2.id] } @@ -388,12 +390,16 @@ describe MergeRequests::UpdateService, services: true do end context 'when MergeRequest has tasks' do - before { update_merge_request({ description: "- [ ] Task 1\n- [ ] Task 2" }) } + before do + update_merge_request({ description: "- [ ] Task 1\n- [ ] Task 2" }) + end it { expect(@merge_request.tasks?).to eq(true) } context 'when tasks are marked as completed' do - before { update_merge_request({ description: "- [x] Task 1\n- [X] Task 2" }) } + before do + update_merge_request({ description: "- [x] Task 1\n- [X] Task 2" }) + end it 'creates system note about task status change' do note1 = find_note('marked the task **Task 1** as completed') diff --git a/spec/services/notes/slash_commands_service_spec.rb b/spec/services/notes/slash_commands_service_spec.rb index c9954dc3603..d5ffc1908a9 100644 --- a/spec/services/notes/slash_commands_service_spec.rb +++ b/spec/services/notes/slash_commands_service_spec.rb @@ -6,7 +6,9 @@ describe Notes::SlashCommandsService, services: true do let(:master) { create(:user).tap { |u| project.team << [u, :master] } } let(:assignee) { create(:user) } - before { project.team << [assignee, :master] } + before do + project.team << [assignee, :master] + end end shared_examples 'note on noteable that does not support slash commands' do diff --git a/spec/services/pages_service_spec.rb b/spec/services/pages_service_spec.rb index aa63fe3a5c1..cf38c7c75e5 100644 --- a/spec/services/pages_service_spec.rb +++ b/spec/services/pages_service_spec.rb @@ -10,10 +10,14 @@ describe PagesService, services: true do end context 'execute asynchronously for pages job' do - before { build.name = 'pages' } + before do + build.name = 'pages' + end context 'on success' do - before { build.success } + before do + build.success + end it 'executes worker' do expect(PagesWorker).to receive(:perform_async) @@ -23,7 +27,9 @@ describe PagesService, services: true do %w(pending running failed canceled).each do |status| context "on #{status}" do - before { build.status = status } + before do + build.status = status + end it 'does not execute worker' do expect(PagesWorker).not_to receive(:perform_async) diff --git a/spec/services/projects/transfer_service_spec.rb b/spec/services/projects/transfer_service_spec.rb index b957517c715..5d2f4cf17fb 100644 --- a/spec/services/projects/transfer_service_spec.rb +++ b/spec/services/projects/transfer_service_spec.rb @@ -59,12 +59,16 @@ describe Projects::TransferService, services: true do context 'visibility level' do let(:internal_group) { create(:group, :internal) } - before { internal_group.add_owner(user) } + before do + internal_group.add_owner(user) + end context 'when namespace visibility level < project visibility level' do let(:public_project) { create(:project, :public, :repository, namespace: user.namespace) } - before { transfer_project(public_project, user, internal_group) } + before do + transfer_project(public_project, user, internal_group) + end it { expect(public_project.visibility_level).to eq(internal_group.visibility_level) } end @@ -72,7 +76,9 @@ describe Projects::TransferService, services: true do context 'when namespace visibility level > project visibility level' do let(:private_project) { create(:project, :private, :repository, namespace: user.namespace) } - before { transfer_project(private_project, user, internal_group) } + before do + transfer_project(private_project, user, internal_group) + end it { expect(private_project.visibility_level).to eq(Gitlab::VisibilityLevel::PRIVATE) } end diff --git a/spec/services/slash_commands/interpret_service_spec.rb b/spec/services/slash_commands/interpret_service_spec.rb index 4db491fd5f3..c12fb1a6e53 100644 --- a/spec/services/slash_commands/interpret_service_spec.rb +++ b/spec/services/slash_commands/interpret_service_spec.rb @@ -378,7 +378,9 @@ describe SlashCommands::InterpretService, services: true do context 'assign command with multiple assignees' do let(:content) { "/assign @#{developer.username} @#{developer2.username}" } - before{ project.team << [developer2, :developer] } + before do + project.team << [developer2, :developer] + end context 'Issue' do it 'fetches assignee and populates assignee_id if content contains /assign' do @@ -798,7 +800,11 @@ describe SlashCommands::InterpretService, services: true do context 'if the project has multiple boards' do let(:issuable) { issue } - before { create(:board, project: project) } + + before do + create(:board, project: project) + end + it_behaves_like 'empty command' end diff --git a/spec/services/spam_service_spec.rb b/spec/services/spam_service_spec.rb index 74cba8c014b..5e6e43b7a90 100644 --- a/spec/services/spam_service_spec.rb +++ b/spec/services/spam_service_spec.rb @@ -70,7 +70,9 @@ describe SpamService, services: true do end context 'when not indicated as spam by akismet' do - before { allow(AkismetService).to receive(:new).and_return(double(is_spam?: false)) } + before do + allow(AkismetService).to receive(:new).and_return(double(is_spam?: false)) + end it 'returns false' do expect(check_spam(issue, request, false)).to be_falsey diff --git a/spec/support/kubernetes_helpers.rb b/spec/support/kubernetes_helpers.rb index 9280fad4ace..c92f78b324c 100644 --- a/spec/support/kubernetes_helpers.rb +++ b/spec/support/kubernetes_helpers.rb @@ -1,7 +1,26 @@ module KubernetesHelpers include Gitlab::Kubernetes - def kube_discovery_body + def kube_response(body) + { body: body.to_json } + end + + def kube_pods_response + kube_response(kube_pods_body) + end + + def stub_kubeclient_discover + WebMock.stub_request(:get, service.api_url + '/api/v1').to_return(kube_response(kube_v1_discovery_body)) + end + + def stub_kubeclient_pods(response = nil) + stub_kubeclient_discover + pods_url = service.api_url + "/api/v1/namespaces/#{service.actual_namespace}/pods" + + WebMock.stub_request(:get, pods_url).to_return(response || kube_pods_response) + end + + def kube_v1_discovery_body { "kind" => "APIResourceList", "resources" => [ @@ -10,17 +29,19 @@ module KubernetesHelpers } end - def kube_pods_body(*pods) - { "kind" => "PodList", - "items" => [kube_pod] } + def kube_pods_body + { + "kind" => "PodList", + "items" => [kube_pod] + } end # This is a partial response, it will have many more elements in reality but # these are the ones we care about at the moment - def kube_pod(app: "valid-pod-label") + def kube_pod(name: "kube-pod", app: "valid-pod-label") { "metadata" => { - "name" => "kube-pod", + "name" => name, "creationTimestamp" => "2016-11-25T19:55:19Z", "labels" => { "app" => app } }, diff --git a/spec/support/milestone_tabs_examples.rb b/spec/support/milestone_tabs_examples.rb index 7cfc1e06975..70b499198bf 100644 --- a/spec/support/milestone_tabs_examples.rb +++ b/spec/support/milestone_tabs_examples.rb @@ -15,7 +15,9 @@ shared_examples 'milestone tabs' do describe '#merge_requests' do context 'as html' do - before { go(:merge_requests, format: 'html') } + before do + go(:merge_requests, format: 'html') + end it 'redirects to milestone#show' do expect(response).to redirect_to(milestone_path) @@ -23,7 +25,9 @@ shared_examples 'milestone tabs' do end context 'as json' do - before { go(:merge_requests, format: 'json') } + before do + go(:merge_requests, format: 'json') + end it 'renders the merge requests tab template to a string' do expect(response).to render_template('shared/milestones/_merge_requests_tab') @@ -34,7 +38,9 @@ shared_examples 'milestone tabs' do describe '#participants' do context 'as html' do - before { go(:participants, format: 'html') } + before do + go(:participants, format: 'html') + end it 'redirects to milestone#show' do expect(response).to redirect_to(milestone_path) @@ -42,7 +48,9 @@ shared_examples 'milestone tabs' do end context 'as json' do - before { go(:participants, format: 'json') } + before do + go(:participants, format: 'json') + end it 'renders the participants tab template to a string' do expect(response).to render_template('shared/milestones/_participants_tab') @@ -53,7 +61,9 @@ shared_examples 'milestone tabs' do describe '#labels' do context 'as html' do - before { go(:labels, format: 'html') } + before do + go(:labels, format: 'html') + end it 'redirects to milestone#show' do expect(response).to redirect_to(milestone_path) @@ -61,7 +71,9 @@ shared_examples 'milestone tabs' do end context 'as json' do - before { go(:labels, format: 'json') } + before do + go(:labels, format: 'json') + end it 'renders the labels tab template to a string' do expect(response).to render_template('shared/milestones/_labels_tab') diff --git a/spec/support/reference_parser_shared_examples.rb b/spec/support/reference_parser_shared_examples.rb index 8eb74635a60..bd83cb88058 100644 --- a/spec/support/reference_parser_shared_examples.rb +++ b/spec/support/reference_parser_shared_examples.rb @@ -3,7 +3,9 @@ RSpec.shared_examples "referenced feature visibility" do |*related_features| related_features.map { |feature| (feature + "_access_level").to_sym } end - before { link['data-project'] = project.id.to_s } + before do + link['data-project'] = project.id.to_s + end context "when feature is disabled" do it "does not create reference" do @@ -13,7 +15,9 @@ RSpec.shared_examples "referenced feature visibility" do |*related_features| end context "when feature is enabled only for team members" do - before { set_features_fields_to(ProjectFeature::PRIVATE) } + before do + set_features_fields_to(ProjectFeature::PRIVATE) + end it "does not create reference for non member" do non_member = create(:user) diff --git a/spec/support/services/issuable_create_service_slash_commands_shared_examples.rb b/spec/support/services/issuable_create_service_slash_commands_shared_examples.rb index 1dd3663b944..5e6f9f323a1 100644 --- a/spec/support/services/issuable_create_service_slash_commands_shared_examples.rb +++ b/spec/support/services/issuable_create_service_slash_commands_shared_examples.rb @@ -11,7 +11,9 @@ shared_examples 'new issuable record that supports slash commands' do let(:params) { base_params.merge(defined?(default_params) ? default_params : {}).merge(example_params) } let(:issuable) { described_class.new(project, user, params).execute } - before { project.team << [assignee, :master] } + before do + project.team << [assignee, :master] + end context 'with labels in command only' do let(:example_params) do diff --git a/spec/support/services/issuable_update_service_shared_examples.rb b/spec/support/services/issuable_update_service_shared_examples.rb index 8947f20562f..ffbce6c42bf 100644 --- a/spec/support/services/issuable_update_service_shared_examples.rb +++ b/spec/support/services/issuable_update_service_shared_examples.rb @@ -4,7 +4,9 @@ shared_examples 'issuable update service' do end context 'changing state' do - before { expect(project).to receive(:execute_hooks).once } + before do + expect(project).to receive(:execute_hooks).once + end context 'to reopened' do it 'executes hooks only once' do diff --git a/spec/support/slack_mattermost_notifications_shared_examples.rb b/spec/support/slack_mattermost_notifications_shared_examples.rb index 7e35ebb6c97..a7deb038703 100644 --- a/spec/support/slack_mattermost_notifications_shared_examples.rb +++ b/spec/support/slack_mattermost_notifications_shared_examples.rb @@ -11,14 +11,18 @@ RSpec.shared_examples 'slack or mattermost notifications' do describe 'Validations' do context 'when service is active' do - before { subject.active = true } + before do + subject.active = true + end it { is_expected.to validate_presence_of(:webhook) } it_behaves_like 'issue tracker service URL attribute', :webhook end context 'when service is inactive' do - before { subject.active = false } + before do + subject.active = false + end it { is_expected.not_to validate_presence_of(:webhook) } end diff --git a/spec/support/unique_ip_check_shared_examples.rb b/spec/support/unique_ip_check_shared_examples.rb index 7cf5a65eeed..1986d202c4a 100644 --- a/spec/support/unique_ip_check_shared_examples.rb +++ b/spec/support/unique_ip_check_shared_examples.rb @@ -31,7 +31,9 @@ end shared_examples 'user login operation with unique ip limit' do include_context 'unique ips sign in limit' do - before { current_application_settings.update!(unique_ips_limit_per_user: 1) } + before do + current_application_settings.update!(unique_ips_limit_per_user: 1) + end it 'allows user authenticating from the same ip' do expect { operation_from_ip('ip') }.not_to raise_error @@ -47,7 +49,9 @@ end shared_examples 'user login request with unique ip limit' do |success_status = 200| include_context 'unique ips sign in limit' do - before { current_application_settings.update!(unique_ips_limit_per_user: 1) } + before do + current_application_settings.update!(unique_ips_limit_per_user: 1) + end it 'allows user authenticating from the same ip' do expect(request_from_ip('ip')).to have_http_status(success_status) diff --git a/spec/support/updating_mentions_shared_examples.rb b/spec/support/updating_mentions_shared_examples.rb index e0c59a5c280..eeec3e1d79b 100644 --- a/spec/support/updating_mentions_shared_examples.rb +++ b/spec/support/updating_mentions_shared_examples.rb @@ -2,7 +2,9 @@ RSpec.shared_examples 'updating mentions' do |service_class| let(:mentioned_user) { create(:user) } let(:service_class) { service_class } - before { project.team << [mentioned_user, :developer] } + before do + project.team << [mentioned_user, :developer] + end def update_mentionable(opts) reset_delivered_emails! @@ -15,7 +17,9 @@ RSpec.shared_examples 'updating mentions' do |service_class| end context 'in title' do - before { update_mentionable(title: mentioned_user.to_reference) } + before do + update_mentionable(title: mentioned_user.to_reference) + end it 'emails only the newly-mentioned user' do should_only_email(mentioned_user) @@ -23,7 +27,9 @@ RSpec.shared_examples 'updating mentions' do |service_class| end context 'in description' do - before { update_mentionable(description: mentioned_user.to_reference) } + before do + update_mentionable(description: mentioned_user.to_reference) + end it 'emails only the newly-mentioned user' do should_only_email(mentioned_user) diff --git a/spec/views/projects/diffs/_viewer.html.haml_spec.rb b/spec/views/projects/diffs/_viewer.html.haml_spec.rb new file mode 100644 index 00000000000..32469202508 --- /dev/null +++ b/spec/views/projects/diffs/_viewer.html.haml_spec.rb @@ -0,0 +1,71 @@ +require 'spec_helper' + +describe 'projects/diffs/_viewer.html.haml', :view do + include FakeBlobHelpers + + let(:project) { create(:project, :repository) } + let(:commit) { project.commit('570e7b2abdd848b95f2f578043fc23bd6f6fd24d') } + let(:diff_file) { commit.diffs.diff_file_with_new_path('files/ruby/popen.rb') } + + let(:viewer_class) do + Class.new(DiffViewer::Base) do + include DiffViewer::Rich + + self.partial_name = 'text' + end + end + + let(:viewer) { viewer_class.new(diff_file) } + + before do + assign(:project, project) + + controller.params[:controller] = 'projects/commit' + controller.params[:action] = 'show' + controller.params[:namespace_id] = project.namespace.to_param + controller.params[:project_id] = project.to_param + controller.params[:id] = commit.id + end + + def render_view + render partial: 'projects/diffs/viewer', locals: { viewer: viewer } + end + + context 'when there is a render error' do + before do + allow(viewer).to receive(:render_error).and_return(:too_large) + end + + it 'renders the error' do + render_view + + expect(view).to render_template('projects/diffs/_render_error') + end + end + + context 'when the viewer is collapsed' do + before do + allow(diff_file).to receive(:collapsed?).and_return(true) + end + + it 'renders the collapsed view' do + render_view + + expect(view).to render_template('projects/diffs/_collapsed') + end + end + + context 'when there is no render error' do + it 'prepares the viewer' do + expect(viewer).to receive(:prepare!) + + render_view + end + + it 'renders the viewer' do + render_view + + expect(view).to render_template('projects/diffs/viewers/_text') + end + end +end diff --git a/spec/workers/emails_on_push_worker_spec.rb b/spec/workers/emails_on_push_worker_spec.rb index a0ed85cc0b3..5b6b38e0f76 100644 --- a/spec/workers/emails_on_push_worker_spec.rb +++ b/spec/workers/emails_on_push_worker_spec.rb @@ -71,7 +71,9 @@ describe EmailsOnPushWorker do end context "when there are no errors in sending" do - before { perform } + before do + perform + end it "sends a mail with the correct subject" do expect(email.subject).to include('adds bar folder and branch-test text file') diff --git a/spec/workers/expire_build_artifacts_worker_spec.rb b/spec/workers/expire_build_artifacts_worker_spec.rb index 73cbadc13d9..b47b4a02a68 100644 --- a/spec/workers/expire_build_artifacts_worker_spec.rb +++ b/spec/workers/expire_build_artifacts_worker_spec.rb @@ -5,10 +5,14 @@ describe ExpireBuildArtifactsWorker do let(:worker) { described_class.new } - before { Sidekiq::Worker.clear_all } + before do + Sidekiq::Worker.clear_all + end describe '#perform' do - before { build } + before do + build + end subject! do Sidekiq::Testing.fake! { worker.perform } diff --git a/spec/workers/git_garbage_collect_worker_spec.rb b/spec/workers/git_garbage_collect_worker_spec.rb index 8c5303b61cc..f443bb2c9b4 100644 --- a/spec/workers/git_garbage_collect_worker_spec.rb +++ b/spec/workers/git_garbage_collect_worker_spec.rb @@ -23,7 +23,9 @@ describe GitGarbageCollectWorker do end shared_examples 'gc tasks' do - before { allow(subject).to receive(:bitmaps_enabled?).and_return(bitmaps_enabled) } + before do + allow(subject).to receive(:bitmaps_enabled?).and_return(bitmaps_enabled) + end it 'incremental repack adds a new packfile' do create_objects(project) diff --git a/spec/workers/post_receive_spec.rb b/spec/workers/post_receive_spec.rb index 44163c735ba..3c93da63f2e 100644 --- a/spec/workers/post_receive_spec.rb +++ b/spec/workers/post_receive_spec.rb @@ -89,7 +89,9 @@ describe PostReceive do end context "does not create a Ci::Pipeline" do - before { stub_ci_pipeline_yaml_file(nil) } + before do + stub_ci_pipeline_yaml_file(nil) + end it { expect{ subject }.not_to change{ Ci::Pipeline.count } } end diff --git a/spec/workers/stuck_ci_jobs_worker_spec.rb b/spec/workers/stuck_ci_jobs_worker_spec.rb index 8434b0c8e5b..549635f7f33 100644 --- a/spec/workers/stuck_ci_jobs_worker_spec.rb +++ b/spec/workers/stuck_ci_jobs_worker_spec.rb @@ -34,7 +34,9 @@ describe StuckCiJobsWorker do let(:status) { 'pending' } context 'when job is not stuck' do - before { allow_any_instance_of(Ci::Build).to receive(:stuck?).and_return(false) } + before do + allow_any_instance_of(Ci::Build).to receive(:stuck?).and_return(false) + end context 'when job was not updated for more than 1 day ago' do let(:updated_at) { 2.days.ago } @@ -53,7 +55,9 @@ describe StuckCiJobsWorker do end context 'when job is stuck' do - before { allow_any_instance_of(Ci::Build).to receive(:stuck?).and_return(true) } + before do + allow_any_instance_of(Ci::Build).to receive(:stuck?).and_return(true) + end context 'when job was not updated for more than 1 hour ago' do let(:updated_at) { 2.hours.ago } @@ -93,7 +97,9 @@ describe StuckCiJobsWorker do let(:status) { 'running' } let(:updated_at) { 2.days.ago } - before { job.project.update(pending_delete: true) } + before do + job.project.update(pending_delete: true) + end it 'does not drop job' do expect_any_instance_of(Ci::Build).not_to receive(:drop) |